mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-30 12:21:05 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
771ed20d97 | ||
|
|
616f1e4336 |
+8
-3
@@ -1913,7 +1913,10 @@ int CLI::run(int argc, char **argv)
|
|||||||
old_printable_width = static_cast<int>(old_printable_bbox.size().x());
|
old_printable_width = static_cast<int>(old_printable_bbox.size().x());
|
||||||
old_printable_depth = static_cast<int>(old_printable_bbox.size().y());
|
old_printable_depth = static_cast<int>(old_printable_bbox.size().y());
|
||||||
}
|
}
|
||||||
old_printable_height = (int)(config.opt_float("printable_height"));
|
// A 3mf can carry an empty project_settings.config - the models in
|
||||||
|
// resources/handy_models do - and opt_float() dereferences without checking.
|
||||||
|
if (config.option<ConfigOptionFloat>("printable_height"))
|
||||||
|
old_printable_height = (int)(config.opt_float("printable_height"));
|
||||||
|
|
||||||
if (config.option<ConfigOptionFloat>("extruder_clearance_height_to_rod"))
|
if (config.option<ConfigOptionFloat>("extruder_clearance_height_to_rod"))
|
||||||
old_height_to_rod = config.opt_float("extruder_clearance_height_to_rod");
|
old_height_to_rod = config.opt_float("extruder_clearance_height_to_rod");
|
||||||
@@ -2589,7 +2592,8 @@ int CLI::run(int argc, char **argv)
|
|||||||
orig_printable_width = static_cast<int>(orig_printable_bbox.size().x());
|
orig_printable_width = static_cast<int>(orig_printable_bbox.size().x());
|
||||||
orig_printable_depth = static_cast<int>(orig_printable_bbox.size().y());
|
orig_printable_depth = static_cast<int>(orig_printable_bbox.size().y());
|
||||||
}
|
}
|
||||||
orig_printable_height = (int)(config.opt_float("printable_height"));
|
if (config.option<ConfigOptionFloat>("printable_height"))
|
||||||
|
orig_printable_height = (int)(config.opt_float("printable_height"));
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, check printable size: old_printable_width=%2%, orig_printable_width=%3%, old_printable_depth=%4%, orig_printable_depth=%5%, old_printable_height=%6%, orig_printable_height=%7%")
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, check printable size: old_printable_width=%2%, orig_printable_width=%3%, old_printable_depth=%4%, orig_printable_depth=%5%, old_printable_height=%6%, orig_printable_height=%7%")
|
||||||
%__LINE__ %old_printable_width %orig_printable_width %old_printable_depth %orig_printable_depth %old_printable_height %orig_printable_height;
|
%__LINE__ %old_printable_width %orig_printable_width %old_printable_depth %orig_printable_depth %old_printable_height %orig_printable_height;
|
||||||
if ((orig_printable_width > 0) && (orig_printable_depth > 0) && (orig_printable_height > 0))
|
if ((orig_printable_width > 0) && (orig_printable_depth > 0) && (orig_printable_height > 0))
|
||||||
@@ -4617,7 +4621,8 @@ int CLI::run(int argc, char **argv)
|
|||||||
BoundingBoxf temp_printable_bbox(temp_printable_area);
|
BoundingBoxf temp_printable_bbox(temp_printable_area);
|
||||||
printer_plate.printable_width = static_cast<int>(temp_printable_bbox.size().x());
|
printer_plate.printable_width = static_cast<int>(temp_printable_bbox.size().x());
|
||||||
printer_plate.printable_depth = static_cast<int>(temp_printable_bbox.size().y());
|
printer_plate.printable_depth = static_cast<int>(temp_printable_bbox.size().y());
|
||||||
printer_plate.printable_height = (int)(config.opt_float("printable_height"));
|
if (config.option<ConfigOptionFloat>("printable_height"))
|
||||||
|
printer_plate.printable_height = (int)(config.opt_float("printable_height"));
|
||||||
}
|
}
|
||||||
if (temp_exclude_area.size() >= 4) {
|
if (temp_exclude_area.size() >= 4) {
|
||||||
printer_plate.exclude_width = (int)(temp_exclude_area[2].x() - temp_exclude_area[0].x());
|
printer_plate.exclude_width = (int)(temp_exclude_area[2].x() - temp_exclude_area[0].x());
|
||||||
|
|||||||
@@ -7297,8 +7297,6 @@ struct Plater::priv
|
|||||||
|
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
// True, and tells the user, while a background job is working on the model - see the definition.
|
|
||||||
bool undo_redo_blocked_by_job();
|
|
||||||
void undo_redo_to(size_t time_to_load);
|
void undo_redo_to(size_t time_to_load);
|
||||||
|
|
||||||
// BBS: backup
|
// BBS: backup
|
||||||
@@ -14935,25 +14933,8 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name, const UndoRed
|
|||||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info();
|
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
// A background job holds the model it is working on: it was queued against the geometry as it stood at
|
|
||||||
// the time and hands its result back when it finishes. Undoing while it runs restores an older state
|
|
||||||
// underneath it, a different transform or a different mesh, and the result then lands on geometry it
|
|
||||||
// was never computed for. Undo and redo therefore wait for the job, and say so rather than doing
|
|
||||||
// nothing.
|
|
||||||
bool Plater::priv::undo_redo_blocked_by_job()
|
|
||||||
{
|
|
||||||
if (m_worker.is_idle())
|
|
||||||
return false;
|
|
||||||
notification_manager->push_notification(NotificationType::CustomNotification,
|
|
||||||
NotificationManager::NotificationLevel::RegularNotificationLevel,
|
|
||||||
_u8L("Cannot undo or redo while an operation is running. Stop it first."));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Plater::priv::undo()
|
void Plater::priv::undo()
|
||||||
{
|
{
|
||||||
if (this->undo_redo_blocked_by_job())
|
|
||||||
return;
|
|
||||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
||||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time()));
|
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time()));
|
||||||
// BBS: undo-redo until modify record
|
// BBS: undo-redo until modify record
|
||||||
@@ -14971,8 +14952,6 @@ void Plater::priv::undo()
|
|||||||
|
|
||||||
void Plater::priv::redo()
|
void Plater::priv::redo()
|
||||||
{
|
{
|
||||||
if (this->undo_redo_blocked_by_job())
|
|
||||||
return;
|
|
||||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
||||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time()));
|
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time()));
|
||||||
// BBS: undo-redo until modify record
|
// BBS: undo-redo until modify record
|
||||||
@@ -22829,9 +22808,8 @@ bool Plater::can_copy_to_clipboard() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The job check keeps the buttons in step with priv::undo()/redo(), which refuse while one runs.
|
bool Plater::can_undo() const { return IsShown() && p->is_view3D_shown() && p->undo_redo_stack().has_undo_snapshot(); }
|
||||||
bool Plater::can_undo() const { return IsShown() && p->is_view3D_shown() && p->m_worker.is_idle() && p->undo_redo_stack().has_undo_snapshot(); }
|
bool Plater::can_redo() const { return IsShown() && p->is_view3D_shown() && p->undo_redo_stack().has_redo_snapshot(); }
|
||||||
bool Plater::can_redo() const { return IsShown() && p->is_view3D_shown() && p->m_worker.is_idle() && p->undo_redo_stack().has_redo_snapshot(); }
|
|
||||||
bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
|
bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
|
||||||
//BBS
|
//BBS
|
||||||
bool Plater::can_fillcolor() const { return p->can_fillcolor(); }
|
bool Plater::can_fillcolor() const { return p->can_fillcolor(); }
|
||||||
|
|||||||
@@ -11,6 +11,13 @@ endif ()
|
|||||||
|
|
||||||
add_test(NAME cli_strict_mode
|
add_test(NAME cli_strict_mode
|
||||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/test_cli_strict.sh $<TARGET_FILE:OrcaSlicer> ${ORCA_CLI_TEST_PYTHON})
|
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/test_cli_strict.sh $<TARGET_FILE:OrcaSlicer> ${ORCA_CLI_TEST_PYTHON})
|
||||||
|
add_test(NAME cli_empty_project_config
|
||||||
|
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/test_cli_empty_project_config.sh $<TARGET_FILE:OrcaSlicer> ${ORCA_CLI_TEST_PYTHON} ${CMAKE_SOURCE_DIR})
|
||||||
|
set_tests_properties(cli_empty_project_config PROPERTIES
|
||||||
|
LABELS "CLI;RequiresApp"
|
||||||
|
SKIP_RETURN_CODE 77
|
||||||
|
TIMEOUT 300)
|
||||||
|
|
||||||
set_tests_properties(cli_strict_mode PROPERTIES
|
set_tests_properties(cli_strict_mode PROPERTIES
|
||||||
LABELS "CLI;RequiresApp"
|
LABELS "CLI;RequiresApp"
|
||||||
SKIP_RETURN_CODE 77
|
SKIP_RETURN_CODE 77
|
||||||
|
|||||||
Executable
+52
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Regression check: a 3mf whose Metadata/project_settings.config carries no settings must load.
|
||||||
|
#
|
||||||
|
# The CLI reads printable_height out of the project config with opt_float(), which dereferences
|
||||||
|
# what option<>() returns. With create = false that is null when the key is absent, so a project
|
||||||
|
# saved without settings used to take the CLI down with a segfault. Both models in
|
||||||
|
# resources/handy_models are such files.
|
||||||
|
#
|
||||||
|
# usage: test_cli_empty_project_config.sh <orca-slicer binary> <python3> <source dir>
|
||||||
|
set -u
|
||||||
|
|
||||||
|
BIN="${1:-}"
|
||||||
|
PY="${2:-python3}"
|
||||||
|
SRC="${3:-}"
|
||||||
|
# 77 is the test's SKIP_RETURN_CODE.
|
||||||
|
[ -x "$BIN" ] || { echo "SKIP: orca-slicer binary not found: $BIN"; exit 77; }
|
||||||
|
[ -f "$SRC/resources/handy_models/OrcaBadge.3mf" ] || { echo "SKIP: handy model not found"; exit 77; }
|
||||||
|
|
||||||
|
WORK="$(mktemp -d "${TMPDIR:-/tmp}/orca-cli-emptycfg.XXXXXX")"
|
||||||
|
trap 'rm -rf "$WORK"' EXIT
|
||||||
|
mkdir -p "$WORK/datadir"
|
||||||
|
|
||||||
|
# Rewrite the project settings to an empty object, so the test holds no matter what the shipped
|
||||||
|
# models carry later on.
|
||||||
|
cp "$SRC/resources/handy_models/OrcaBadge.3mf" "$WORK/empty_config.3mf"
|
||||||
|
"$PY" - "$WORK/empty_config.3mf" <<'PYEOF'
|
||||||
|
import shutil, sys, zipfile
|
||||||
|
|
||||||
|
path = sys.argv[1]
|
||||||
|
entry = "Metadata/project_settings.config"
|
||||||
|
with zipfile.ZipFile(path) as src:
|
||||||
|
items = [(i, src.read(i.filename)) for i in src.infolist()]
|
||||||
|
with zipfile.ZipFile(path + ".new", "w", zipfile.ZIP_DEFLATED) as dst:
|
||||||
|
seen = False
|
||||||
|
for info, data in items:
|
||||||
|
if info.filename == entry:
|
||||||
|
data, seen = b"{\n}\n", True
|
||||||
|
dst.writestr(info, data)
|
||||||
|
if not seen:
|
||||||
|
dst.writestr(entry, b"{\n}\n")
|
||||||
|
shutil.move(path + ".new", path)
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
"$BIN" --datadir "$WORK/datadir" --info "$WORK/empty_config.3mf" > "$WORK/info.txt" 2>&1
|
||||||
|
rc=$?
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
echo "FAIL: --info on a project with empty settings exited $rc"
|
||||||
|
tail -20 "$WORK/info.txt"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -q "size_x" "$WORK/info.txt" || { echo "FAIL: --info printed no geometry"; cat "$WORK/info.txt"; exit 1; }
|
||||||
|
echo "PASS: a project with empty settings loads"
|
||||||
Reference in New Issue
Block a user