mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-19 13:41:03 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86941859fa | ||
|
|
d3699dd9f6 | ||
|
|
a315a96c5c | ||
|
|
24cf1c6bcc |
No files matched your search
@@ -10657,6 +10657,9 @@ msgstr ""
|
|||||||
msgid "Send Failed"
|
msgid "Send Failed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No available printers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "The name length exceeds the limit."
|
msgid "The name length exceeds the limit."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
+37
-13
@@ -841,8 +841,12 @@ public:
|
|||||||
{
|
{
|
||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
iss >> this->value;
|
double value;
|
||||||
return !iss.fail();
|
iss >> value;
|
||||||
|
if (iss.fail())
|
||||||
|
return false;
|
||||||
|
this->value = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ConfigOption &rhs) const override
|
bool operator==(const ConfigOption &rhs) const override
|
||||||
@@ -1033,8 +1037,12 @@ public:
|
|||||||
{
|
{
|
||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
iss >> this->value;
|
int value;
|
||||||
return !iss.fail();
|
iss >> value;
|
||||||
|
if (iss.fail())
|
||||||
|
return false;
|
||||||
|
this->value = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigOptionInt& operator=(const ConfigOption *opt)
|
ConfigOptionInt& operator=(const ConfigOption *opt)
|
||||||
@@ -1252,8 +1260,12 @@ public:
|
|||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
// don't try to parse the trailing % since it's optional
|
// don't try to parse the trailing % since it's optional
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
iss >> this->value;
|
double value;
|
||||||
return !iss.fail();
|
iss >> value;
|
||||||
|
if (iss.fail())
|
||||||
|
return false;
|
||||||
|
this->value = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -1365,10 +1377,14 @@ public:
|
|||||||
bool deserialize(const std::string &str, bool append = false) override
|
bool deserialize(const std::string &str, bool append = false) override
|
||||||
{
|
{
|
||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
this->percent = str.find_first_of("%") != std::string::npos;
|
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
iss >> this->value;
|
double value;
|
||||||
return !iss.fail();
|
iss >> value;
|
||||||
|
if (iss.fail())
|
||||||
|
return false;
|
||||||
|
this->value = value;
|
||||||
|
this->percent = str.find_first_of("%") != std::string::npos;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -1538,8 +1554,12 @@ public:
|
|||||||
{
|
{
|
||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
char dummy;
|
char dummy;
|
||||||
return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 ||
|
Vec2d value;
|
||||||
sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2;
|
if (sscanf(str.data(), " %lf , %lf %c", &value(0), &value(1), &dummy) != 2 &&
|
||||||
|
sscanf(str.data(), " %lf x %lf %c", &value(0), &value(1), &dummy) != 2)
|
||||||
|
return false;
|
||||||
|
this->value = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -1658,8 +1678,12 @@ public:
|
|||||||
{
|
{
|
||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
char dummy;
|
char dummy;
|
||||||
return sscanf(str.data(), " %lf , %lf , %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 3 ||
|
Vec3d value;
|
||||||
sscanf(str.data(), " %lf x %lf x %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 3;
|
if (sscanf(str.data(), " %lf , %lf , %lf %c", &value(0), &value(1), &value(2), &dummy) != 3 &&
|
||||||
|
sscanf(str.data(), " %lf x %lf x %lf %c", &value(0), &value(1), &value(2), &dummy) != 3)
|
||||||
|
return false;
|
||||||
|
this->value = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -756,7 +756,14 @@ public:
|
|||||||
Preset& get_edited_preset() { return m_edited_preset; }
|
Preset& get_edited_preset() { return m_edited_preset; }
|
||||||
const Preset& get_edited_preset() const { return m_edited_preset; }
|
const Preset& get_edited_preset() const { return m_edited_preset; }
|
||||||
|
|
||||||
const Preset& get_selected_preset_base() const { return *get_preset_base(m_presets[m_idx_selected]); }
|
// The root of the selected preset's inherits chain, or the selected preset itself when
|
||||||
|
// the chain names a preset that is not loaded (e.g. a vendor that is not installed).
|
||||||
|
const Preset& get_selected_preset_base() const
|
||||||
|
{
|
||||||
|
const Preset &selected = m_presets[m_idx_selected];
|
||||||
|
const Preset *base = get_preset_base(selected);
|
||||||
|
return base ? *base : selected;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the last saved preset.
|
// Return the last saved preset.
|
||||||
// const Preset& get_saved_preset() const { return m_saved_preset; }
|
// const Preset& get_saved_preset() const { return m_saved_preset; }
|
||||||
|
|||||||
@@ -3151,7 +3151,7 @@ void CreatePrinterPresetDialog::set_current_visible_printer()
|
|||||||
m_printer_name_to_preset.clear();
|
m_printer_name_to_preset.clear();
|
||||||
for (const Preset &printer_preset : printer_presets) {
|
for (const Preset &printer_preset : printer_presets) {
|
||||||
if (!printer_preset.is_visible) continue;
|
if (!printer_preset.is_visible) continue;
|
||||||
if (preset_bundle->printers.get_preset_base(printer_preset)->name != printer_preset.name) continue;
|
if (preset_bundle->printers.get_preset_base(printer_preset) != &printer_preset) continue;
|
||||||
if (auto printer_model = dynamic_cast<ConfigOptionString*>(const_cast<Preset&>(printer_preset).config.option("printer_model", false))) {
|
if (auto printer_model = dynamic_cast<ConfigOptionString*>(const_cast<Preset&>(printer_preset).config.option("printer_model", false))) {
|
||||||
if (m_printer_name_to_preset.find(printer_model->value) == m_printer_name_to_preset.end()) {
|
if (m_printer_name_to_preset.find(printer_model->value) == m_printer_name_to_preset.end()) {
|
||||||
printer_choice.push_back(from_u8(printer_model->value));
|
printer_choice.push_back(from_u8(printer_model->value));
|
||||||
@@ -4962,7 +4962,7 @@ void CreatePresetForPrinterDialog::get_visible_printer_and_compatible_filament_p
|
|||||||
if (filament_preset.is_default || !filament_preset.is_compatible || filament_preset.is_project_embedded) continue;
|
if (filament_preset.is_default || !filament_preset.is_compatible || filament_preset.is_project_embedded) continue;
|
||||||
ConfigOptionStrings *filament_types;
|
ConfigOptionStrings *filament_types;
|
||||||
const Preset * filament_preset_base = m_preset_bundle->filaments.get_preset_base(filament_preset);
|
const Preset * filament_preset_base = m_preset_bundle->filaments.get_preset_base(filament_preset);
|
||||||
if (filament_preset_base == &filament_preset) {
|
if (filament_preset_base == &filament_preset || filament_preset_base == nullptr) {
|
||||||
filament_types = dynamic_cast<ConfigOptionStrings *>(const_cast<Preset *>(&filament_preset)->config.option("filament_type"));
|
filament_types = dynamic_cast<ConfigOptionStrings *>(const_cast<Preset *>(&filament_preset)->config.option("filament_type"));
|
||||||
} else {
|
} else {
|
||||||
filament_types = dynamic_cast<ConfigOptionStrings *>(const_cast<Preset *>(filament_preset_base)->config.option("filament_type"));
|
filament_types = dynamic_cast<ConfigOptionStrings *>(const_cast<Preset *>(filament_preset_base)->config.option("filament_type"));
|
||||||
|
|||||||
@@ -4087,7 +4087,7 @@ void SelectMachineDialog::update_user_printer()
|
|||||||
{
|
{
|
||||||
m_printer_last_select = "";
|
m_printer_last_select = "";
|
||||||
update_select_layout(nullptr);
|
update_select_layout(nullptr);
|
||||||
m_printer_box->GetPrinterComboBox()->SetTextLabel("");
|
m_printer_box->GetPrinterComboBox()->SetValue(_L("No available printers"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl;
|
||||||
|
|||||||
@@ -1229,7 +1229,7 @@ void SendToPrinterDialog::update_user_printer()
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_printer_last_select = "";
|
m_printer_last_select = "";
|
||||||
m_comboBox_printer->SetTextLabel("");
|
m_comboBox_printer->SetValue(_L("No available printers"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl;
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ void ComboBox::DoDeleteOneItem(unsigned int pos)
|
|||||||
|
|
||||||
void ComboBox::ForceDropdownOpen()
|
void ComboBox::ForceDropdownOpen()
|
||||||
{
|
{
|
||||||
if (!IsEnabled())
|
if (!IsEnabled() || items.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!drop_down) {
|
if (!drop_down) {
|
||||||
@@ -398,7 +398,7 @@ void ComboBox::mouseDown(wxMouseEvent &event)
|
|||||||
SetFocus();
|
SetFocus();
|
||||||
if (drop_down) {
|
if (drop_down) {
|
||||||
drop.Hide();
|
drop.Hide();
|
||||||
} else if (drop.HasDismissLongTime()) {
|
} else if (!items.empty() && drop.HasDismissLongTime()) { // DropDown paints nothing for an empty list
|
||||||
drop.autoPosition();
|
drop.autoPosition();
|
||||||
drop_down = true;
|
drop_down = true;
|
||||||
drop.Popup(&drop);
|
drop.Popup(&drop);
|
||||||
@@ -426,7 +426,7 @@ void ComboBox::keyDown(wxKeyEvent& event)
|
|||||||
case WXK_SPACE:
|
case WXK_SPACE:
|
||||||
if (drop_down) {
|
if (drop_down) {
|
||||||
drop.DismissAndNotify();
|
drop.DismissAndNotify();
|
||||||
} else if (drop.HasDismissLongTime()) {
|
} else if (!items.empty() && drop.HasDismissLongTime()) {
|
||||||
drop.autoPosition();
|
drop.autoPosition();
|
||||||
drop_down = true;
|
drop_down = true;
|
||||||
drop.Popup();
|
drop.Popup();
|
||||||
|
|||||||
@@ -584,6 +584,19 @@ bool PythonInterpreter::initialize()
|
|||||||
}
|
}
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Program name set successfully";
|
BOOST_LOG_TRIVIAL(debug) << "Program name set successfully";
|
||||||
|
|
||||||
|
// Keep bytecode out of the Python home. The shipped .pyc files are stale against their
|
||||||
|
// sources, so a writable install would rewrite them inside the app (breaking a signed
|
||||||
|
// macOS bundle's seal) and a read-only one would recompile them on every launch.
|
||||||
|
const std::string pycache_prefix = data_dir() + "/python/pycache";
|
||||||
|
#ifdef _WIN32
|
||||||
|
status = PyConfig_SetString(&config, &config.pycache_prefix, boost::nowide::widen(pycache_prefix).c_str());
|
||||||
|
#else
|
||||||
|
status = PyConfig_SetBytesString(&config, &config.pycache_prefix, pycache_prefix.c_str());
|
||||||
|
#endif
|
||||||
|
if (PyStatus_Exception(status))
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "Failed to set the Python bytecode cache to " << pycache_prefix << ": "
|
||||||
|
<< (status.err_msg ? status.err_msg : "unknown error");
|
||||||
|
|
||||||
// Use pybind11's scoped_interpreter which properly initializes
|
// Use pybind11's scoped_interpreter which properly initializes
|
||||||
// pybind11 internals for multi-threaded use — raw Py_InitializeFromConfig
|
// pybind11 internals for multi-threaded use — raw Py_InitializeFromConfig
|
||||||
// does not set up thread state tracking that pybind11 requires.
|
// does not set up thread state tracking that pybind11 requires.
|
||||||
|
|||||||
@@ -1263,6 +1263,55 @@ TEST_CASE("read_cli rejects an invalid scalar numeric value", "[Config]") {
|
|||||||
REQUIRE_FALSE(config.read_cli(3, argv, &extra, &keys));
|
REQUIRE_FALSE(config.read_cli(3, argv, &extra, &keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("A scalar option keeps its value when deserializing fails", "[Config]") {
|
||||||
|
using Catch::Matchers::WithinAbs;
|
||||||
|
|
||||||
|
SECTION("float") {
|
||||||
|
ConfigOptionFloat opt(7.5);
|
||||||
|
REQUIRE_FALSE(opt.deserialize("abc"));
|
||||||
|
CHECK_THAT(opt.value, WithinAbs(7.5, 1e-9));
|
||||||
|
}
|
||||||
|
SECTION("int") {
|
||||||
|
ConfigOptionInt opt(3);
|
||||||
|
REQUIRE_FALSE(opt.deserialize("abc"));
|
||||||
|
CHECK(opt.value == 3);
|
||||||
|
}
|
||||||
|
SECTION("percent") {
|
||||||
|
ConfigOptionPercent opt(40.);
|
||||||
|
REQUIRE_FALSE(opt.deserialize("abc%"));
|
||||||
|
CHECK_THAT(opt.value, WithinAbs(40., 1e-9));
|
||||||
|
}
|
||||||
|
SECTION("float or percent") {
|
||||||
|
ConfigOptionFloatOrPercent opt(0.4, false);
|
||||||
|
REQUIRE_FALSE(opt.deserialize("abc%"));
|
||||||
|
CHECK_THAT(opt.value, WithinAbs(0.4, 1e-9));
|
||||||
|
CHECK_FALSE(opt.percent);
|
||||||
|
}
|
||||||
|
SECTION("point") {
|
||||||
|
ConfigOptionPoint opt(Vec2d(1., 2.));
|
||||||
|
REQUIRE_FALSE(opt.deserialize("5,abc"));
|
||||||
|
CHECK(opt.value == Vec2d(1., 2.));
|
||||||
|
}
|
||||||
|
SECTION("point3") {
|
||||||
|
ConfigOptionPoint3 opt(Vec3d(1., 2., 3.));
|
||||||
|
REQUIRE_FALSE(opt.deserialize("5,6,abc"));
|
||||||
|
CHECK(opt.value == Vec3d(1., 2., 3.));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("A scalar option still takes a valid value", "[Config]") {
|
||||||
|
using Catch::Matchers::WithinAbs;
|
||||||
|
|
||||||
|
ConfigOptionFloatOrPercent opt(0.4, false);
|
||||||
|
REQUIRE(opt.deserialize("50%"));
|
||||||
|
CHECK_THAT(opt.value, WithinAbs(50., 1e-9));
|
||||||
|
CHECK(opt.percent);
|
||||||
|
|
||||||
|
ConfigOptionPoint point;
|
||||||
|
REQUIRE(point.deserialize("3x4"));
|
||||||
|
CHECK(point.value == Vec2d(3., 4.));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("read_cli appends values when a vector option is repeated", "[Config]") {
|
TEST_CASE("read_cli appends values when a vector option is repeated", "[Config]") {
|
||||||
Slic3r::DynamicPrintConfig config;
|
Slic3r::DynamicPrintConfig config;
|
||||||
t_config_option_keys extra, keys;
|
t_config_option_keys extra, keys;
|
||||||
|
|||||||
@@ -1219,6 +1219,24 @@ TEST_CASE("find_preset2 auto-matches removed Generic vendor profiles to the libr
|
|||||||
CHECK(bundle.filaments.find_preset2("BrandX Generic PETG", /*auto_match=*/true) == nullptr);
|
CHECK(bundle.filaments.find_preset2("BrandX Generic PETG", /*auto_match=*/true) == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("The selected preset is its own base when its parent is not loaded", "[Preset]")
|
||||||
|
{
|
||||||
|
PresetCollection printers(Preset::TYPE_PRINTER, Preset::printer_options(),
|
||||||
|
static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()));
|
||||||
|
add_inmemory_preset(printers, "Printer");
|
||||||
|
add_inmemory_preset(printers, "User Printer", "Printer");
|
||||||
|
add_inmemory_preset(printers, "Orphan Printer", "Uninstalled Vendor Printer");
|
||||||
|
|
||||||
|
printers.select_preset_by_name("User Printer", true);
|
||||||
|
REQUIRE(printers.get_selected_preset_name() == "User Printer");
|
||||||
|
CHECK(printers.get_selected_preset_base().name == "Printer");
|
||||||
|
|
||||||
|
printers.select_preset_by_name("Orphan Printer", true);
|
||||||
|
REQUIRE(printers.get_selected_preset_name() == "Orphan Printer");
|
||||||
|
REQUIRE(printers.get_preset_base(printers.get_selected_preset()) == nullptr);
|
||||||
|
CHECK(printers.get_selected_preset_base().name == "Orphan Printer");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]")
|
TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]")
|
||||||
{
|
{
|
||||||
ScopedTemporaryDir temp_dir;
|
ScopedTemporaryDir temp_dir;
|
||||||
|
|||||||
@@ -615,8 +615,22 @@ TEST_CASE("Python module release removes package submodules and owned sys.path",
|
|||||||
|
|
||||||
// Ensure the next import executes the new submodule rather than reusing a stale package child.
|
// Ensure the next import executes the new submodule rather than reusing a stale package child.
|
||||||
write_package("'new'");
|
write_package("'new'");
|
||||||
boost::system::error_code ec;
|
{
|
||||||
fs::remove_all(package_root / "__pycache__", ec);
|
// The rewrite can keep the old mtime and size, so drop the bytecode wherever the
|
||||||
|
// interpreter caches it.
|
||||||
|
PythonGILState gil;
|
||||||
|
REQUIRE(gil);
|
||||||
|
PyObjectPtr util(PyImport_ImportModule("importlib.util"));
|
||||||
|
REQUIRE(util);
|
||||||
|
for (const char* file : {"__init__.py", "sub.py"}) {
|
||||||
|
PyObjectPtr source(PyUnicode_DecodeFSDefault((package_root / file).string().c_str()));
|
||||||
|
REQUIRE(source);
|
||||||
|
PyObjectPtr cached(PyObject_CallMethod(util.get(), "cache_from_source", "O", source.get()));
|
||||||
|
REQUIRE(cached);
|
||||||
|
boost::system::error_code ec;
|
||||||
|
fs::remove(fs::path(PyUnicode_AsUTF8(cached.get())), ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
paths.clear();
|
paths.clear();
|
||||||
modules.clear();
|
modules.clear();
|
||||||
|
|||||||
Reference in new issue
Block a user