Merge branch 'main' into fix/opc-support-for-ota

This commit is contained in:
Ian Chua
2026-09-10 15:42:14 +08:00
committed by GitHub
4799 changed files with 57153 additions and 19328 deletions
+21 -4
View File
@@ -63,6 +63,8 @@ set(SLIC3R_GUI_SOURCES
GUI/BitmapComboBox.hpp
GUI/BonjourDialog.cpp
GUI/BonjourDialog.hpp
GUI/BuildCommit.cpp
GUI/BuildCommit.hpp
GUI/CrealityDiscoveryDialog.cpp
GUI/CrealityDiscoveryDialog.hpp
GUI/calib_dlg.cpp
@@ -95,6 +97,8 @@ set(SLIC3R_GUI_SOURCES
GUI/CloneDialog.hpp
GUI/ConfigManipulation.cpp
GUI/ConfigManipulation.hpp
GUI/ConfigValueFormatter.cpp
GUI/ConfigValueFormatter.hpp
GUI/ConfigWizard.cpp
GUI/ConfigWizard.hpp
GUI/ConfigWizard_private.hpp
@@ -449,6 +453,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Project.hpp
GUI/PublishDialog.cpp
GUI/PublishDialog.hpp
GUI/PublishSettingsDialog.cpp
GUI/PublishSettingsDialog.hpp
GUI/PurgeModeDialog.cpp
GUI/PurgeModeDialog.hpp
GUI/RammingChart.cpp
@@ -845,6 +851,18 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui)
# Only BuildCommit.cpp includes the generated header, plus BaseException.cpp on
# Windows. Both build into libslic3r_gui, so the header only has to exist before
# that target builds.
set(_git_commit_hash_header "${CMAKE_CURRENT_BINARY_DIR}/git_commit_hash.h")
add_custom_target(git_commit_hash_header
BYPRODUCTS "${_git_commit_hash_header}"
COMMAND ${CMAKE_COMMAND}
"-DSOURCE_DIR=${CMAKE_SOURCE_DIR}"
"-DOUT_FILE=${_git_commit_hash_header}"
-P "${CMAKE_CURRENT_LIST_DIR}/GitCommitHash.cmake"
COMMENT "Resolving the git commit hash")
add_dependencies(libslic3r_gui git_commit_hash_header)
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(_opengl_link_lib "")
@@ -902,6 +920,9 @@ endif ()
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
elseif (MSVC)
# Puts the Windows headers first when the PCH is off.
target_compile_options(libslic3r_gui PRIVATE "/FIslic3r/win_platform.hpp")
endif ()
if (APPLE)
@@ -967,10 +988,6 @@ endif ()
# Add a definition so that we can tell we are compiling slic3r.
target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE)
if(ORCA_BUNDLED_UV_EXECUTABLE_CONFIG)
target_compile_definitions(libslic3r_gui PRIVATE "ORCA_BUNDLED_UV_EXECUTABLE=\"${ORCA_BUNDLED_UV_EXECUTABLE_CONFIG}\"")
endif()
if (ORCA_BUILD_PYTHON_STUBGEN_MODULE)
add_library(orca_stubgen MODULE
plugin/PythonPluginBridge.cpp
+25 -3
View File
@@ -20,6 +20,8 @@
#include "libslic3r/AppConfig.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/GCode/WipeTower.hpp"
#include "libslic3r/GCode/WipeTowerEstimate.hpp"
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/PrintConfig.hpp"
@@ -919,6 +921,21 @@ int GLVolumeCollection::load_wipe_tower_preview(
GUI::PartPlateList& ppl = GUI::wxGetApp().plater()->get_partplate_list();
std::vector<int> plate_extruders = ppl.get_plate(plate_idx)->get_extruders(true);
TriangleMesh wipe_tower_shell = make_cube(width, depth, height);
// The brim is part of the printed footprint: draw it and fold it into the shell so the
// outside-bed shader and the drag clamp react to the true first-layer extent.
const bool show_brim = brim_width > 0.f;
const float brim_height = 0.2f; // one first layer, visual only
TriangleMesh brim_slab;
if (show_brim) {
// The brim follows the real first-layer outline: a Type2 cone-wall tower's base bulges
// past the body box. The wall type and angle are print settings, the planner a printer one.
const DynamicPrintConfig &print_cfg = GUI::wxGetApp().preset_bundle->prints.get_edited_preset().config;
const DynamicPrintConfig &printer_cfg = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().config;
const Polygon outline = estimate_wipe_tower_first_layer_outline(print_cfg, resolve_wipe_tower_type(printer_cfg), width, depth, height);
const Polygons brim_outline = offset(outline, scaled(brim_width));
brim_slab = WipeTower::its_make_rib_brim(brim_outline.empty() ? outline : brim_outline.front(), brim_height);
wipe_tower_shell.merge(brim_slab);
}
for (int extruder_id : plate_extruders) {
if (extruder_id <= extruder_colors.size())
colors.push_back(extruder_colors[extruder_id - 1]);
@@ -929,14 +946,19 @@ int GLVolumeCollection::load_wipe_tower_preview(
// Orca: make it transparent
for(auto& color : colors)
color.a(0.66f);
const size_t slab_count = colors.size(); // per-filament body slabs; the brim part comes after
if (show_brim && !colors.empty())
colors.push_back(colors.front());
volumes.emplace_back(new GLWipeTowerVolume(colors));
GLWipeTowerVolume& v = *dynamic_cast<GLWipeTowerVolume*>(volumes.back());
v.model_per_colors.resize(colors.size());
for (int i = 0; i < colors.size(); i++) {
TriangleMesh color_part = make_cube(width, depth / colors.size(), height);
color_part.translate({ 0.f, depth * i / colors.size(), 0. });
for (size_t i = 0; i < slab_count; i++) {
TriangleMesh color_part = make_cube(width, depth / slab_count, height);
color_part.translate({ 0.f, depth * i / slab_count, 0. });
v.model_per_colors[i].init_from(color_part);
}
if (show_brim && !colors.empty())
v.model_per_colors[slab_count].init_from(brim_slab);
v.model.init_from(wipe_tower_shell);
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(wipe_tower_shell));
v.set_convex_hull(wipe_tower_shell);
+26 -37
View File
@@ -437,7 +437,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent)
m_temperature_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(80), -1));
m_temperature_input->SetMaxLength(3); // Limit to 3 digits
m_temperature_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) {
m_temperature_input->Bind(wxEVT_CHAR, [](wxKeyEvent& event) {
int keycode = event.GetKeyCode();
if (keycode >= '0' && keycode <= '9') {
event.Skip();
@@ -464,7 +464,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent)
m_time_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(100), -1));
m_time_input->SetMaxLength(3); // Limit to 3 digits
m_time_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) {
m_time_input->Bind(wxEVT_CHAR, [](wxKeyEvent& event) {
int keycode = event.GetKeyCode();
if (keycode >= '0' && keycode <= '9') {
event.Skip();
@@ -698,7 +698,7 @@ wxBoxSizer* AMSDryCtrWin::create_guide_info_section(wxPanel* parent)
m_rotate_spool_toggle = new wxCheckBox(parent, wxID_ANY, "");
m_rotate_spool_toggle->SetValue(false);
m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) {
m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& event) {
bool is_checked = event.IsChecked();
// Add toggle behavior logic here
});
@@ -1511,6 +1511,10 @@ void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams)
m_temperature_input->GetValue().ToLong(&input_temp);
bool can_start = true;
// "GFA00" is Bambu's PLA id; GetFilamentDryingPreset is keyed by our OF ids.
auto* agent = wxGetApp().getAgent();
const std::string pla_filament_id = agent ? agent->to_orca_filament_id("GFA00") : std::string("GFA00");
int slot_count = 0, empty_count = 0;
for (auto& tray_pair : dev_ams->GetTrays()) {
if (!tray_pair.second) {
@@ -1526,13 +1530,15 @@ void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams)
wxString filament_type = tray_pair.second->get_display_filament_type();
DevFilamentDryingPreset preset;
if (filament_type.IsEmpty()) {
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(pla_filament_id);
if (!fallback_preset) continue; // no PLA preset (e.g. the id map is missing): skip, don't throw
preset = fallback_preset.value();
filament_type = "?";
} else if (preset_opt.has_value()) {
preset = preset_opt.value();
} else {
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(pla_filament_id);
if (!fallback_preset) continue;
preset = fallback_preset.value();
}
std::string icon_path = "dev_ams_dry_ctr_enable";
@@ -1594,39 +1600,21 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj)
}
stream << std::fixed << std::setprecision(1) << obj->GetExtderSystem()->GetNozzleDiameter(extruder_id);
std::string nozzle_diameter_str = stream.str();
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str);
for (auto filament_it = filaments.begin(); filament_it != filaments.end(); ++filament_it) {
Preset& preset = *filament_it;
// Filter by system preset: root preset and (system preset or user preset is supported)
if (filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
if (!filament_id_set.insert(filament_it->filament_id).second)
continue;
const std::string filament_alias = filaments.get_preset_alias(*filament_it, true);
if (filament_alias.empty())
continue;
auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id);
if (!opt_info.has_value())
continue;
}
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
if (!printer_strs) continue;
for (auto printer_str : printer_strs->values) {
if (printer_names.find(printer_str) != printer_names.end()) {
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
continue;
}
filament_id_set.insert(filament_it->filament_id);
auto filament_alias = filaments.get_preset_alias(*filament_it, true);
if (!filament_alias.empty()) {
auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id);
if (opt_info.has_value()) {
auto real_info = opt_info.value();
real_info.filament_name = filament_alias;
m_tray_ids.push_back(std::move(real_info));
m_trays_combo->Append(wxString::FromUTF8(filament_alias));
}
}
}
}
opt_info->filament_name = filament_alias;
m_tray_ids.push_back(std::move(*opt_info));
m_trays_combo->Append(wxString::FromUTF8(filament_alias));
}
if (m_tray_ids.empty()) {
@@ -1701,9 +1689,10 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj)
// Select recommended drying temperature and default filament
float min_dry_temp = std::numeric_limits<float>::max();
std::string default_filament_id = "GFA00";
auto* agent = wxGetApp().getAgent();
std::string default_filament_id = agent ? agent->to_orca_filament_id("GFA00") : std::string("GFA00"); // compared against m_tray_ids[i].filament_id (our OF ids) below
bool has_ready = false;
const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(default_filament_id);
for (const auto& tray_pair : dev_ams->GetTrays()) {
if (!tray_pair.second || !tray_pair.second->is_tray_info_ready()) continue;
has_ready = true;
-6
View File
@@ -97,12 +97,6 @@ private:
wxSimplebook* m_main_simplebook{nullptr};
wxPanel* m_original_page{nullptr};
wxWindow* m_amswin{nullptr};
wxBoxSizer* m_sizer_ams_items{nullptr};
wxScrolledWindow* m_panel_prv_left {nullptr};
wxScrolledWindow* m_panel_prv_right{nullptr};
wxBoxSizer* m_sizer_prv_left{nullptr};
wxBoxSizer* m_sizer_prv_right{nullptr};
// left panel related members
ScalableBitmap m_humidity_image;
+93 -121
View File
@@ -681,6 +681,19 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
}
// Orca: log the tray payload this dialog hands the printer, so the filament_id resolved from the
// dropdown selection can be checked against the tray_info_idx the AMS actually receives. A
// BBL-tagged (RFID) tray is read-only here, so nothing is published for it.
BOOST_LOG_TRIVIAL(info) << "ams_materials_setting: " << (m_is_third ? "sending" : "NOT sending (BBL RFID tray, read-only)")
<< ", ams_id = " << ams_id << ", slot_id = " << slot_id
<< ", selected = " << m_comboBox_filament->GetValue().ToStdString()
<< ", tray_info_idx (filament_id) = " << ams_filament_id
<< ", setting_id = " << ams_setting_id
<< ", tray_type = " << m_filament_type
<< ", tray_color = " << col_buf
<< ", nozzle_temp_min = " << nozzle_temp_min_int
<< ", nozzle_temp_max = " << nozzle_temp_max_int;
// set filament
if (m_is_third) {
obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int);
@@ -802,7 +815,10 @@ void AMSMaterialsSetting::set_color(wxColour color)
fila_color.m_colors.insert(color);
fila_color.EndSet(m_clr_picker->ctype);
auto clr_query = GUI::wxGetApp().get_filament_color_code_query();
m_clr_name->SetLabelText(clr_query->GetFilaColorName(ams_filament_id, fila_color));
// ams_filament_id is our OF id; GetFilaColorName looks up filaments_color_codes.json,
// downloaded from Bambu and keyed by the printer's own ids, so translate for this lookup only.
auto* agent = GUI::wxGetApp().getAgent();
m_clr_name->SetLabelText(clr_query->GetFilaColorName(agent ? agent->from_orca_filament_id(ams_filament_id) : ams_filament_id, fila_color));
}
void AMSMaterialsSetting::set_empty_color(wxColour color)
@@ -823,7 +839,10 @@ void AMSMaterialsSetting::set_colors(std::vector<wxColour> colors)
for (const auto& clr : colors) { fila_color.m_colors.insert(clr); }
fila_color.EndSet(m_clr_picker->ctype);
auto clr_query = GUI::wxGetApp().get_filament_color_code_query();
m_clr_name->SetLabelText(clr_query->GetFilaColorName(ams_filament_id, fila_color));
// ams_filament_id is our OF id; GetFilaColorName looks up filaments_color_codes.json,
// downloaded from Bambu and keyed by the printer's own ids, so translate for this lookup only.
auto* agent = GUI::wxGetApp().getAgent();
m_clr_name->SetLabelText(clr_query->GetFilaColorName(agent ? agent->from_orca_filament_id(ams_filament_id) : ams_filament_id, fila_color));
}
}
@@ -932,7 +951,6 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
m_input_k_val->GetTextCtrl()->SetValue(k);
m_input_n_val->GetTextCtrl()->SetValue(n);
int idx = 0;
wxArrayString filament_items;
wxString bambu_filament_name;
wxString hint_filament_name; // the hint type to be selected
@@ -940,6 +958,9 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
std::unordered_map<wxString, wxString> query_filament_types; //
std::set<std::string> filament_id_set;
// The alias keyed map has to start empty: it is a member, so a stale alias left by an earlier
// popup (a different printer, a different nozzle) would resolve to that printer's filament_id.
map_filament_items.clear();
PresetBundle * preset_bundle = wxGetApp().preset_bundle;
std::ostringstream stream;
// Defensive: this dialog is opened only from StatusPanel (BBL-only) today, so the fallback fires
@@ -952,83 +973,48 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
}
stream << std::fixed << std::setprecision(1) << machine_diameter;
std::string nozzle_diameter_str = stream.str();
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str);
if (preset_bundle) {
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
//filter by system preset
Preset& preset = *filament_it;
/*The situation where the user preset is not displayed is as follows:
1. Not a root preset
2. Not system preset and the printer firmware does not support user preset */
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
if (!filament_id_set.insert(filament_it->filament_id).second)
continue;
const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true);
if (alias.empty())
continue;
}
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
for (auto printer_str : printer_strs->values) {
if (printer_names.find(printer_str) != printer_names.end()) {
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
continue;
} else {
filament_id_set.insert(filament_it->filament_id);
// name matched
if (filament_it->is_system) {
filament_items.push_back(filament_it->alias);
_collect_filament_info(filament_it->alias, preset, query_filament_vendors, query_filament_types);
filament_items.push_back(alias);
_collect_filament_info(alias, *filament_it, query_filament_vendors, query_filament_types);
FilamentInfos filament_infos;
filament_infos.filament_id = filament_it->filament_id;
filament_infos.setting_id = filament_it->setting_id;
map_filament_items[filament_it->alias] = filament_infos;
} else {
char target = '@';
size_t pos = filament_it->name.find(target);
if (pos != std::string::npos) {
std::string user_preset_alias = filament_it->name.substr(0, pos - 1);
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
user_preset_alias = wx_user_preset_alias.ToStdString();
FilamentInfos filament_infos;
filament_infos.filament_id = filament_it->filament_id;
filament_infos.setting_id = filament_it->setting_id;
map_filament_items[alias] = filament_infos;
filament_items.push_back(user_preset_alias);
_collect_filament_info(user_preset_alias, preset, query_filament_vendors, query_filament_types);
FilamentInfos filament_infos;
filament_infos.filament_id = filament_it->filament_id;
filament_infos.setting_id = filament_it->setting_id;
map_filament_items[user_preset_alias] = filament_infos;
}
}
if (filament_it->filament_id == ams_filament_id) {
hint_filament_name = from_u8(filament_it->alias);
bambu_filament_name = from_u8(filament_it->alias);
if (filament_it->filament_id == ams_filament_id) {
hint_filament_name = from_u8(alias);
bambu_filament_name = from_u8(alias);
// update if nozzle_temperature_range is found
ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low");
if (opt_min) {
ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
if (opt_min_ints) {
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
}
}
ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high");
if (opt_max) {
ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
if (opt_max_ints) {
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
}
}
}
idx++;
// update if nozzle_temperature_range is found
ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low");
if (opt_min) {
ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
if (opt_min_ints) {
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
}
}
ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high");
if (opt_max) {
ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
if (opt_max_ints) {
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
}
}
}
}
}
@@ -1251,56 +1237,47 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
stream << std::fixed << std::setprecision(1) << machine_diameter;
}
std::string nozzle_diameter_str = stream.str();
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type),
nozzle_diameter_str);
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
if (!m_comboBox_filament->GetValue().IsEmpty()) {
auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()];
std::string filament_id = filament_item.filament_id;
if (it->filament_id.compare(filament_id) == 0) {
ConfigOption * printer_opt = it->config.option("compatible_printers");
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
bool has_compatible_printer = false;
for (auto printer_str : printer_strs->values) {
if (printer_names.find(printer_str) != printer_names.end()) {
has_compatible_printer = true;
break;
}
// Resolve the selection against the same list Popup() built the dropdown from, so the two
// halves of the dialog cannot disagree about which filaments this machine can use.
const std::string selected = m_comboBox_filament->GetValue().ToStdString();
if (!selected.empty()) {
const std::string filament_id = map_filament_items[selected].filament_id;
for (Preset *it : preset_bundle->get_filament_presets_for_machine(
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
if (it->filament_id != filament_id)
continue;
// ) if nozzle_temperature_range is found
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
if (opt_min) {
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
if (opt_min_ints) {
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
}
if (!it->is_system && !has_compatible_printer) continue;
// ) if nozzle_temperature_range is found
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
if (opt_min) {
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
if (opt_min_ints) {
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
}
}
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
if (opt_max) {
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
if (opt_max_ints) {
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
}
}
ConfigOption* opt_type = it->config.option("filament_type");
bool found_filament_type = false;
if (opt_type) {
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
if (opt_type_strs) {
found_filament_type = true;
//m_filament_type = opt_type_strs->get_at(0);
std::string display_filament_type;
m_filament_type = it->config.get_filament_type(display_filament_type);
}
}
if (!found_filament_type)
m_filament_type = "";
break;
}
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
if (opt_max) {
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
if (opt_max_ints) {
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
}
}
ConfigOption* opt_type = it->config.option("filament_type");
bool found_filament_type = false;
if (opt_type) {
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
if (opt_type_strs) {
found_filament_type = true;
//m_filament_type = opt_type_strs->get_at(0);
std::string display_filament_type;
m_filament_type = it->config.get_filament_type(display_filament_type);
}
}
if (!found_filament_type)
m_filament_type = "";
break;
}
}
}
@@ -1938,11 +1915,6 @@ void ColorPickerPopup::paintEvent(wxPaintEvent& evt)
void ColorPickerPopup::OnDismiss() {}
void ColorPickerPopup::Popup()
{
PopupWindow::Popup();
}
bool ColorPickerPopup::ProcessLeftDown(wxMouseEvent& event) {
return PopupWindow::ProcessLeftDown(event);
}
-1
View File
@@ -85,7 +85,6 @@ public:
void set_ams_colours(std::vector<wxColour> ams);
void set_def_colour(wxColour col);
void paintEvent(wxPaintEvent& evt);
void Popup();
virtual void OnDismiss() wxOVERRIDE;
virtual bool ProcessLeftDown(wxMouseEvent& event) wxOVERRIDE;
+2 -2
View File
@@ -292,7 +292,7 @@ void AMSSetting::UpdateByObj(MachineObject* obj)
update_ams_img(obj);
m_ams_type->Update(obj);
m_ams_type->UpdateInfo(obj);
//m_ams_arrange_order->Update(obj);
update_insert_material_read_mode(obj);
m_sizer_remain_block->Show(obj->is_support_update_remain);
@@ -624,7 +624,7 @@ void AMSSettingTypePanel::CreateGui()
Fit();
}
void AMSSettingTypePanel::Update(const MachineObject* obj)
void AMSSettingTypePanel::UpdateInfo(const MachineObject* obj)
{
if (!obj) {
Show(false);
+1 -1
View File
@@ -110,7 +110,7 @@ public:
~AMSSettingTypePanel();
public:
void Update(const MachineObject* obj);
void UpdateInfo(const MachineObject* obj);
private:
void CreateGui();
+2 -1
View File
@@ -3,6 +3,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/Color.hpp"
#include "BuildCommit.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
@@ -245,7 +246,7 @@ AboutDialog::AboutDialog()
vesizer->Add(0, 0, 1, wxEXPAND, FromDIP(5));
auto version_string = std::string(SoftFever_VERSION); // _L("Orca Slicer ") + " " + std::string(SoftFever_VERSION);
wxStaticText* version = new wxStaticText(this, wxID_ANY, version_string.c_str(), wxDefaultPosition, wxDefaultSize);
wxStaticText* credits_string = new wxStaticText(this, wxID_ANY, wxString::Format("Build %s", std::string(GIT_COMMIT_HASH)), wxDefaultPosition, wxDefaultSize);
wxStaticText* credits_string = new wxStaticText(this, wxID_ANY, wxString::Format("Build %s", build_commit_label), wxDefaultPosition, wxDefaultSize);
credits_string->SetFont(_build_string_font);
wxFont version_font = GetFont();
version_font = version_font.Scaled(1.85f); // SetPointSize(20) not works on macOS because it uses a 72 PPI reference
-1
View File
@@ -457,7 +457,6 @@ private:
ScalableBitmap close_img;
wxStaticBitmap* curr_humidity_img;
wxStaticBitmap* m_img;
Label* m_staticText;;
Label* m_staticText_note;
+1 -1
View File
@@ -406,7 +406,7 @@ void AmsMapingPopup::update_ams_data_multi_machines()
int ams_type = 1;
int nozzle_id = 0;
if (ams_type >= 1 || ams_type <= 3) { // 1:ams 2:ams-lite 3:n3f
if (ams_type >= 1 && ams_type <= 3) { // 1:ams 2:ams-lite 3:n3f
auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL);
auto ams_mapping_item_container = new MappingContainer(nozzle_id == 0 ? m_right_marea_panel : m_left_marea_panel, "AMS-1", 4);
-1
View File
@@ -93,7 +93,6 @@ private:
CenteredTitle* m_title_ctrl { nullptr };
wxString m_titleText;
wxAuiToolBarItem* m_model_store_item;
//wxAuiToolBarItem *m_publish_item;
wxAuiToolBarItem* m_undo_item;
+3 -1
View File
@@ -848,7 +848,9 @@ void BackgroundSlicingProcess::finalize_gcode()
case CopyFileResult::SUCCESS: break; // no error
case CopyFileResult::FAIL_COPY_FILE:
throw Slic3r::ExportError(GUI::format(
_L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"),
m_export_path_on_removable_media ?
_L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%") :
_L("Copying of the temporary G-code to the output G-code failed.\nError message: %1%"),
error_message));
break;
case CopyFileResult::FAIL_FILES_DIFFERENT:
+3 -3
View File
@@ -468,7 +468,7 @@ PingCodeBindDialog::~PingCodeBindDialog() {
m_link_privacy_title->SetFont(Label::Head_13);
m_link_privacy_title->SetMaxSize(wxSize(FromDIP(450), -1));
m_link_privacy_title->Wrap(FromDIP(450));
m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [](auto& e) {
std::string url;
std::string country_code = Slic3r::GUI::wxGetApp().app_config->get_country_code();
@@ -893,7 +893,7 @@ void BindMachineDialog::on_show(wxShowEvent &event)
}
}
})
.on_error([this](std::string body, std::string error, unsigned status) {
.on_error([](std::string body, std::string error, unsigned status) {
//BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error;
}).perform();
}
@@ -1099,7 +1099,7 @@ void UnBindMachineDialog::on_show(wxShowEvent &event)
}
}
})
.on_error([this](std::string body, std::string error, unsigned status) {
.on_error([](std::string body, std::string error, unsigned status) {
//BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error;
}).perform();
-9
View File
@@ -65,18 +65,10 @@ private:
wxPanel* request_bind_panel;
wxPanel* binding_panel;
wxScrolledWindow* m_sw_bind_failed_info;
Label* m_bind_failed_info;
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
HyperLink* m_link_network_state{ nullptr };
wxString m_result_info;
wxString m_result_extra;
wxString m_ping_code_wiki;
bool m_show_error_info_state = true;
int m_result_code;
std::shared_ptr<BBLStatusBarBind> m_status_bar;
public:
@@ -110,7 +102,6 @@ private:
wxBitmap m_bitmap_show_error_close;
wxBitmap m_bitmap_show_error_open;
wxScrolledWindow* m_sw_bind_failed_info;
Label* m_bind_failed_info;
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
+9
View File
@@ -0,0 +1,9 @@
#include "BuildCommit.hpp"
#include "git_commit_hash.h"
namespace Slic3r { namespace GUI {
const char *const build_commit_hash = GIT_COMMIT_HASH;
const char *const build_commit_label = GIT_COMMIT_HASH GIT_COMMIT_SUFFIX;
}} // namespace Slic3r::GUI
+15
View File
@@ -0,0 +1,15 @@
#pragma once
// Read these rather than including git_commit_hash.h, which changes with every
// commit and rebuilds everything that includes it.
namespace Slic3r { namespace GUI {
// The commit alone, safe to use in a commit URL.
extern const char *const build_commit_hash;
// The same, with "-dirty" when the build had uncommitted changes. Use this
// wherever the build is shown to a person.
extern const char *const build_commit_label;
}} // namespace Slic3r::GUI
+13 -60
View File
@@ -443,7 +443,7 @@ void HistoryWindow::sync_history_data() {
auto edit_button = new Button(m_history_data_panel, _L("Edit"));
edit_button->SetStyle(ButtonStyle::Confirm, ButtonType::Window);
edit_button->Bind(wxEVT_BUTTON, [this, result, k_value, name_value, edit_button](auto& e) {
edit_button->Bind(wxEVT_BUTTON, [this, result, k_value, name_value](auto& e) {
if (m_ui_op_lock) return;
PACalibResult result_buffer = result;
@@ -702,7 +702,6 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
wxArrayString filament_items;
std::set<std::string> filament_id_set;
std::set<std::string> printer_names;
std::ostringstream stream;
// If the machine didn't report a nozzle diameter (0.0 = unknown), fall back to the currently
// selected printer preset so the filament list isn't empty.
@@ -714,67 +713,21 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
stream << std::fixed << std::setprecision(1) << machine_diameter;
std::string nozzle_diameter_str = stream.str();
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
// filter by system preset
if (!printer_it->is_system)
continue;
// get printer_model
ConfigOption * printer_model_opt = printer_it->config.option("printer_model");
ConfigOptionString *printer_model_str = dynamic_cast<ConfigOptionString *>(printer_model_opt);
if (!printer_model_str)
continue;
// use printer_model as printer type
if (printer_model_str->value != DevPrinterConfigUtil::get_printer_display_name(obj->printer_type))
continue;
if (printer_it->name.find(nozzle_diameter_str) != std::string::npos)
printer_names.insert(printer_it->name);
}
if (preset_bundle) {
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
// filter by system preset
Preset &preset = *filament_it;
/*The situation where the user preset is not displayed is as follows:
1. Not a root preset
2. Not system preset and the printer firmware does not support user preset */
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && ! obj->is_support_user_preset)) { continue; }
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
if (!filament_id_set.insert(filament_it->filament_id).second)
continue;
const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true);
if (alias.empty())
continue;
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
for (auto printer_str : printer_strs->values) {
if (printer_names.find(printer_str) != printer_names.end()) {
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
continue;
} else {
filament_id_set.insert(filament_it->filament_id);
// name matched
if (filament_it->is_system) {
filament_items.push_back(filament_it->alias);
FilamentInfos filament_infos;
filament_infos.filament_id = filament_it->filament_id;
filament_infos.setting_id = filament_it->setting_id;
map_filament_items[filament_it->alias] = filament_infos;
} else {
char target = '@';
size_t pos = filament_it->name.find(target);
if (pos != std::string::npos) {
std::string user_preset_alias = filament_it->name.substr(0, pos - 1);
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
user_preset_alias = wx_user_preset_alias.ToStdString();
filament_items.push_back(user_preset_alias);
FilamentInfos filament_infos;
filament_infos.filament_id = filament_it->filament_id;
filament_infos.setting_id = filament_it->setting_id;
map_filament_items[user_preset_alias] = filament_infos;
}
}
}
}
}
filament_items.push_back(alias);
FilamentInfos filament_infos;
filament_infos.filament_id = filament_it->filament_id;
filament_infos.setting_id = filament_it->setting_id;
map_filament_items[alias] = filament_infos;
}
}
return filament_items;
+1 -1
View File
@@ -201,7 +201,7 @@ wxWindow* CalibrationDialog::create_check_option(wxString title, wxWindow* paren
checkbox->SetToolTip(tooltip);
text->SetToolTip(tooltip);
text->Bind(wxEVT_LEFT_DOWN, [this, check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); });
text->Bind(wxEVT_LEFT_DOWN, [check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); });
m_checkbox_list[param] = check;
m_checkbox_list[param]->SetValue(true);
return checkbox;
-4
View File
@@ -70,11 +70,7 @@ public:
private:
int m_my_devices_count{ 0 };
int m_other_devices_count{ 0 };
bool m_dismiss{ false };
wxWindow* m_placeholder_panel { nullptr };
wxWindow* m_panel_body{ nullptr };
wxBoxSizer* m_sizer_body{ nullptr };
wxBoxSizer* m_sizer_my_devices{ nullptr };
wxScrolledWindow* m_scrolledWindow{ nullptr };
wxTimer* m_refresh_timer{ nullptr };
+1 -1
View File
@@ -477,7 +477,7 @@ void CalibrationWizard::on_cali_go_home()
if (go_home_dialog == nullptr)
go_home_dialog = new SecondaryCheckDialog(this, wxID_ANY, _L("Confirm"));
go_home_dialog->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, method](wxCommandEvent &e) {
go_home_dialog->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this](wxCommandEvent &e) {
if (curr_obj) {
curr_obj->command_task_abort();
} else {
+1 -1
View File
@@ -90,7 +90,7 @@ void CalibrationCaliPage::on_subtask_abort(wxCommandEvent& event)
if (abort_dlg == nullptr) {
abort_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Cancel print"));
abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, obj](wxCommandEvent& e) {
abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [obj](wxCommandEvent& e) {
if (obj) obj->command_task_abort();
});
}
+1 -1
View File
@@ -762,7 +762,7 @@ void CaliPageActionPanel::bind_button(CaliPageActionType action_type, bool is_bl
if (is_block) {
m_action_btns[i]->Bind(wxEVT_BUTTON,
[this](wxCommandEvent& evt) {
[](wxCommandEvent& evt) {
MessageDialog msg(nullptr, _L("The current firmware version of the printer does not support calibration.\nPlease upgrade the printer firmware."), _L("Calibration not supported"), wxOK | wxICON_WARNING);
msg.ShowModal();
});
@@ -360,7 +360,7 @@ void CaliPresetCustomRangePanel::create_panel(wxWindow* parent)
int max_decimal_length;
if (i <= 1)
max_decimal_length = 3;
else if (i >= 2)
else
max_decimal_length = 4;
if (decimal_number > max_decimal_length) {
int allowed_length = number.length() - decimal_number + max_decimal_length;
+3 -3
View File
@@ -272,7 +272,7 @@ void CaliPASaveAutoPanel::sync_cali_result(const std::vector<PACalibResult>& cal
preset_names = default_naming(preset_names);
std::vector<PACalibResult> sorted_cali_result = cali_result;
std::sort(sorted_cali_result.begin(), sorted_cali_result.end(), [this](const PACalibResult &left, const PACalibResult& right) {
std::sort(sorted_cali_result.begin(), sorted_cali_result.end(), [](const PACalibResult &left, const PACalibResult& right) {
return left.tray_id < right.tray_id;
});
@@ -366,7 +366,7 @@ void CaliPASaveAutoPanel::sync_cali_result(const std::vector<PACalibResult>& cal
}
}
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto& e) {
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [comboBox_tray_name](auto& e) {
int selection = comboBox_tray_name->GetSelection();
auto history = filtered_results[selection];
});
@@ -744,7 +744,7 @@ void CaliPASaveAutoPanel::sync_cali_result_for_multi_extruder(const std::vector<
}
}
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto &e) {
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [comboBox_tray_name](auto &e) {
int selection = comboBox_tray_name->GetSelection();
auto history = filtered_results[selection];
});
+1 -1
View File
@@ -140,7 +140,7 @@ CameraPopup::CameraPopup(wxWindow *parent)
vcamera_guide_link->Wrap(-1);
vcamera_guide_link->SetForegroundColour(wxColour(0x1F, 0x8E, 0xEA));
auto text_size = vcamera_guide_link->GetTextExtent(text);
vcamera_guide_link->Bind(wxEVT_LEFT_DOWN, [this, url](wxMouseEvent& e) {wxLaunchDefaultBrowser(url); });
vcamera_guide_link->Bind(wxEVT_LEFT_DOWN, [url](wxMouseEvent& e) {wxLaunchDefaultBrowser(url); });
link_underline = new wxPanel(m_panel, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
link_underline->SetBackgroundColour(wxColour(0x1F, 0x8E, 0xEA));
+2
View File
@@ -72,8 +72,10 @@ private:
SwitchButton* m_switch_recording;
wxStaticText* m_text_vcamera;
SwitchButton* m_switch_vcamera;
#if !BBL_RELEASE_TO_PUBLIC
wxStaticText* m_text_liveview_retry;
SwitchButton* m_switch_liveview_retry;
#endif //BBL_RELEASE_TO_PUBLIC
wxStaticText* m_custom_camera_hint;
TextInput* m_custom_camera_input;
Button* m_custom_camera_input_confirm;
+33 -11
View File
@@ -62,10 +62,16 @@ std::string decompose_basic_type_from_source(size_t source_config_idx,
auto& project_config = wxGetApp().preset_bundle->project_config;
if (auto* filament_id_opt = project_config.option<ConfigOptionStrings>("filament_id")) {
if (source_config_idx < filament_id_opt->values.size()) {
const std::string& filament_id = filament_id_opt->values[source_config_idx];
if (filament_id == kDecomposePetgFilamentId)
// Dead in practice: "filament_id" is not in PresetBundle's s_project_options, so this
// option() lookup (create=false) always returns null and the block never runs. Kept as
// found, with the translation the values would need: they would be our OF ids, and the
// two constants are the printer's own ids.
auto* agent = wxGetApp().getAgent();
const std::string& orca_filament_id = filament_id_opt->values[source_config_idx];
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(orca_filament_id) : orca_filament_id;
if (printer_filament_id == kDecomposePetgFilamentId)
return kDecomposePetgBasicType;
if (filament_id == kDecomposePlaFilamentId)
if (printer_filament_id == kDecomposePlaFilamentId)
return kDecomposePlaBasicType;
}
}
@@ -82,9 +88,14 @@ std::string decompose_basic_type_from_source(size_t source_config_idx,
std::string decompose_basic_filament_id(const std::string& basic_type)
{
if (basic_type == kDecomposePetgBasicType)
return kDecomposePetgFilamentId;
return kDecomposePlaFilamentId;
// The result becomes DecomposeOfficialComponent::filament_id, which the rest of this file
// reads as one of our OF ids (translating back before it compares against the printer's
// ids), so translate on the way out; kDecompose*FilamentId itself stays the printer-side
// literal. The only place that would carry it further, project_config's "filament_id", is
// dead code: that key is not in PresetBundle's s_project_options.
const std::string printer_filament_id = basic_type == kDecomposePetgBasicType ? kDecomposePetgFilamentId : kDecomposePlaFilamentId;
auto* agent = wxGetApp().getAgent();
return agent ? agent->to_orca_filament_id(printer_filament_id) : printer_filament_id;
}
void set_created_standard_component_metadata(size_t config_idx, const DecomposeOfficialComponent& component)
@@ -98,8 +109,11 @@ void set_created_standard_component_metadata(size_t config_idx, const DecomposeO
}
}
const std::string type = component.filament_id == kDecomposePetgFilamentId ? kDecomposePetgShortType :
component.filament_id == kDecomposePlaFilamentId ? kDecomposePlaShortType : "";
// component.filament_id is our OF id; the two constants are the printer's own ids.
auto* agent = wxGetApp().getAgent();
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(component.filament_id) : component.filament_id;
const std::string type = printer_filament_id == kDecomposePetgFilamentId ? kDecomposePetgShortType :
printer_filament_id == kDecomposePlaFilamentId ? kDecomposePlaShortType : "";
if (!type.empty()) {
if (auto* type_opt = project_config.option<ConfigOptionStrings>("filament_type")) {
while (type_opt->values.size() <= config_idx)
@@ -151,7 +165,12 @@ DecomposeOfficialComponent lookup_decompose_official_component(
continue;
if (item.contains("fila_color") && item["fila_color"].is_array() && !item["fila_color"].empty())
result.color_hex = decompose_normalize_color_hex(item["fila_color"][0].get<std::string>());
result.filament_id = item.value("fila_id", result.filament_id);
// fila_id from this shipped, Bambu-keyed color table is a printer-side id; translate it so
// result.filament_id stays an OF id like the rest of this struct (the fallback default,
// result.filament_id, is already OF and passes through unchanged).
const std::string fila_id = item.value("fila_id", result.filament_id);
auto* agent = wxGetApp().getAgent();
result.filament_id = agent ? agent->to_orca_filament_id(fila_id) : fila_id;
return result;
}
}
@@ -211,8 +230,11 @@ int find_existing_decompose_component(
auto* type_opt = project_config.option<ConfigOptionStrings>("filament_type");
const PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
const size_t num_physical = physical_colors.size();
const std::string expected_basic_type = component.filament_id == kDecomposePetgFilamentId ? kDecomposePetgBasicType :
component.filament_id == kDecomposePlaFilamentId ? kDecomposePlaBasicType : "";
// component.filament_id is our OF id; the two constants are the printer's own ids.
auto* agent = wxGetApp().getAgent();
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(component.filament_id) : component.filament_id;
const std::string expected_basic_type = printer_filament_id == kDecomposePetgFilamentId ? kDecomposePetgBasicType :
printer_filament_id == kDecomposePlaFilamentId ? kDecomposePlaBasicType : "";
const std::string expected_short_type = expected_basic_type == kDecomposePetgBasicType ? kDecomposePetgShortType :
expected_basic_type == kDecomposePlaBasicType ? kDecomposePlaShortType : "";
const std::string expected_preset_part = expected_basic_type.empty() ? "" : std::string(kDecomposeBambuPresetPrefix) + expected_basic_type;
+13 -6
View File
@@ -453,7 +453,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->opt_bool("alternate_extra_wall") &&
(config->opt_enum<EnsureVerticalShellThickness>("ensure_vertical_shell_thickness") == evstAll)) {
wxString msg_text = _(L("Alternate extra wall does't work well when ensure vertical shell thickness is set to All."));
wxString msg_text = _(L("Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All."));
if (is_global_config)
msg_text += "\n\n" + _(L("Change these settings automatically?\n"
@@ -642,7 +642,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None &&
config->get_abs_value("seam_slope_start_height") >= layer_height) {
const wxString msg_text = _(L("seam_slope_start_height need to be smaller than layer_height.\nReset to 0."));
const wxString msg_text = _(L("seam_slope_start_height needs to be smaller than layer_height.\nReset to 0."));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -656,7 +656,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
float skin_depth = config->opt_float("skin_infill_depth");
if (config->opt_float("infill_lock_depth") > skin_depth) {
// xgettext:no-c-format, no-boost-format
const wxString msg_text = _(L("Lock depth should smaller than skin depth.\nReset to 50% of skin depth."));
const wxString msg_text = _(L("Lock depth should be smaller than skin depth.\nReset to 50% of skin depth."));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -741,14 +741,21 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
bool have_infill = config->option<ConfigOptionPercent>("sparse_infill_density")->value > 0;
// sparse_infill_filament_id uses the same logic as in Print::extruders()
for (auto el : { "sparse_infill_pattern", "infill_combination", "fill_multiline","infill_direction",
"minimum_sparse_infill_area", "sparse_infill_filament_id", "infill_anchor", "infill_anchor_max","infill_shift_step","sparse_infill_rotate_template","symmetric_infill_y_axis"})
"minimum_sparse_infill_area", "sparse_infill_filament_id","infill_shift_step","sparse_infill_rotate_template","symmetric_infill_y_axis"})
toggle_line(el, have_infill);
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
// Orca: the concentric patterns follow the surface outline instead of crossing it, so there is
// nothing for an infill anchor to attach to. Hide the anchor settings for them.
bool have_infill_anchor = have_infill && pattern != ipConcentric && pattern != ipSpiralInset;
toggle_line("infill_anchor", have_infill_anchor);
toggle_line("infill_anchor_max", have_infill_anchor);
bool have_combined_infill = config->opt_bool("infill_combination") && have_infill;
toggle_line("infill_combination_max_layer_height", have_combined_infill);
// Infill patterns that support multiline infill.
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb || pattern == ipConcentric ||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic|| pattern == ipTriangles || pattern == ipQuarterCubic|| pattern == ipArchimedeanChords || pattern == ipHilbertCurve || pattern == ipOctagramSpiral;
@@ -831,7 +838,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
toggle_line("separated_infills", is_internal_infill_separable);
// Fill order is only meaningful for the center-based surface fill patterns; hide it otherwise.
auto is_centered_fill = [](InfillPattern p) { return p == ipConcentric || p == ipArchimedeanChords || p == ipOctagramSpiral; };
auto is_centered_fill = [](InfillPattern p) { return p == ipConcentric || p == ipSpiralInset || p == ipArchimedeanChords || p == ipOctagramSpiral; };
toggle_line("top_surface_fill_order", has_top_shell && is_centered_fill(config->opt_enum<InfillPattern>("top_surface_pattern")));
toggle_line("bottom_surface_fill_order", has_bottom_shell && is_centered_fill(config->opt_enum<InfillPattern>("bottom_surface_pattern")));
+245
View File
@@ -0,0 +1,245 @@
#include "ConfigValueFormatter.hpp"
#include <algorithm>
#include <cstdlib>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include "libslic3r/Config.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "I18N.hpp"
#include "GUI.hpp"
#include "Field.hpp"
namespace Slic3r {
namespace GUI {
std::string get_pure_opt_key(const std::string& opt_key)
{
std::string pure_key = opt_key;
const int pos = pure_key.find("#");
if (pos > 0)
boost::erase_tail(pure_key, pure_key.size() - pos);
return pure_key;
}
wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config, bool is_infill, int idx)
{
const ConfigOptionDef& def = config.def()->options.at(opt_key);
const std::vector<std::string>& names = def.enum_labels;//ConfigOptionEnum<T>::get_enum_names();
int val = 0;
if (idx >= 0)
val = dynamic_cast<const ConfigOptionInts*>(config.option(opt_key))->get_at(idx);
else
val = config.option(opt_key)->getInt();
// Each infill doesn't use all list of infill declared in PrintConfig.hpp.
// So we should "convert" val to the correct one
if (is_infill) {
for (auto key_val : *def.enum_keys_map)
if (int(key_val.second) == val) {
auto it = std::find(def.enum_values.begin(), def.enum_values.end(), key_val.first);
if (it == def.enum_values.end())
return "";
return from_u8(_utf8(names[it - def.enum_values.begin()]));
}
return _L("Undefined");
}
return from_u8(_utf8(names[val]));
}
wxString get_full_label(const std::string& opt_key, const DynamicPrintConfig& config)
{
const std::string pure_key = get_pure_opt_key(opt_key);
auto option = config.option(pure_key);
if (!option || option->is_nil())
return _L("N/A");
const ConfigOptionDef* opt = config.def()->get(pure_key);
return opt->full_label.empty() ? opt->label : opt->full_label;
}
wxString get_string_value(const std::string& opt_key, const DynamicPrintConfig& config)
{
int orig_opt_idx = -1;
int opt_idx = -1;
int pos = opt_key.find("#");
std::string temp_str = opt_key;
if (pos > 0) {
boost::erase_head(temp_str, pos + 1);
orig_opt_idx = std::atoi(temp_str.c_str());
}
opt_idx = orig_opt_idx >= 0 ? orig_opt_idx : 0;
const std::string pure_key = get_pure_opt_key(opt_key);
auto option = config.option(pure_key);
if (!option) {
return _L("N/A");
}
auto opt_vector = dynamic_cast<const ConfigOptionVectorBase *>(option);
if ((option->is_scalar() && option->is_nil()) ||
(option->is_vector() && opt_vector && opt_idx >= 0 && opt_idx < opt_vector->size() && opt_vector->is_nil(opt_idx)))
return _L("N/A");
wxString out;
const ConfigOptionDef* opt = config.def()->get(pure_key);
bool is_nullable = opt->nullable;
switch (opt->type) {
case coInt:
return from_u8((boost::format("%1%") % config.opt_int(pure_key)).str());
case coInts: {
if (is_nullable) {
auto values = config.opt<ConfigOptionIntsNullable>(pure_key);
if (opt_idx < values->size())
return from_u8((boost::format("%1%") % values->get_at(opt_idx)).str());
}
else {
auto values = config.opt<ConfigOptionInts>(pure_key);
if (orig_opt_idx >= 0 && orig_opt_idx < values->size()) {
return from_u8((boost::format("%1%") % values->get_at(opt_idx)).str());
}
else {
std::string value_str;
for (int i = 0; i < values->size(); i++) {
value_str += std::to_string(values->get_at(i));
if (i != values->size() - 1) {
value_str += ",";
}
}
return from_u8(value_str);
}
}
return _L("Undefined");
}
case coBool:
return config.opt_bool(pure_key) ? "true" : "false";
case coBools: {
if (is_nullable) {
auto values = config.opt<ConfigOptionBoolsNullable>(pure_key);
if (opt_idx < values->size())
return values->get_at(opt_idx) ? "true" : "false";
}
else {
auto values = config.opt<ConfigOptionBools>(pure_key);
if (opt_idx < values->size())
return values->get_at(opt_idx) ? "true" : "false";
}
return _L("Undefined");
}
case coPercent:
return from_u8((boost::format("%1%%%") % int(config.optptr(pure_key)->getFloat())).str());
case coPercents: {
if (is_nullable) {
auto values = config.opt<ConfigOptionPercentsNullable>(pure_key);
if (opt_idx < values->size())
return from_u8((boost::format("%1%%%") % values->get_at(opt_idx)).str());
}
else {
auto values = config.opt<ConfigOptionPercents>(pure_key);
if (opt_idx < values->size())
return from_u8((boost::format("%1%%%") % values->get_at(opt_idx)).str());
}
return _L("Undefined");
}
case coFloat:
return double_to_string(config.opt_float(pure_key));
case coFloats: {
if (is_nullable) {
auto values = config.opt<ConfigOptionFloatsNullable>(pure_key);
if (opt_idx < values->size())
return double_to_string(values->get_at(opt_idx));
}
else {
auto values = config.opt<ConfigOptionFloats>(pure_key);
if (values && opt_idx < values->size())
return double_to_string(values->get_at(opt_idx));
}
return _L("Undefined");
}
case coString:
return from_u8(config.opt_string(pure_key));
case coStrings: {
const ConfigOptionStrings* strings = config.opt<ConfigOptionStrings>(pure_key);
if (strings) {
if (pure_key == "compatible_printers" || pure_key == "compatible_prints") {
if (strings->empty())
return _L("All");
for (size_t id = 0; id < strings->size(); id++)
out += from_u8(strings->get_at(id)) + "\n";
out.RemoveLast(1);
return out;
}
if (!strings->empty() && opt_idx < strings->values.size())
return from_u8(strings->get_at(opt_idx));
}
break;
}
case coFloatOrPercent: {
const ConfigOptionFloatOrPercent* opt = config.opt<ConfigOptionFloatOrPercent>(pure_key);
if (opt)
out = double_to_string(opt->value) + (opt->percent ? "%" : "");
return out;
}
case coEnum: {
return get_string_from_enum(pure_key, config,
pure_key == "top_surface_pattern" ||
pure_key == "bottom_surface_pattern" ||
pure_key == "internal_solid_infill_pattern" ||
pure_key == "sparse_infill_pattern" ||
pure_key == "ironing_pattern" ||
pure_key == "support_ironing_pattern" ||
pure_key == "support_pattern" ||
pure_key == "support_interface_pattern")
;
}
case coEnums: {
return get_string_from_enum(pure_key, config,
pure_key == "top_surface_pattern" ||
pure_key == "bottom_surface_pattern" ||
pure_key == "internal_solid_infill_pattern" ||
pure_key == "sparse_infill_pattern" ||
pure_key == "ironing_pattern" ||
pure_key == "support_ironing_pattern" ||
pure_key == "support_pattern" ||
pure_key == "support_interface_pattern"
, opt_idx);
}
case coPoint: {
Vec2d val = config.opt<ConfigOptionPoint>(pure_key)->value;
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
}
case coPoints: {
//BBS: add bed_exclude_area
if (pure_key == "printable_area" || pure_key == "thumbnails") {
ConfigOptionPoints points = *config.option<ConfigOptionPoints>(pure_key);
//BuildVolume build_volume = {points.values, 0.};
return get_thumbnails_string(points.values);
}
else if (pure_key == "bed_exclude_area") {
return get_thumbnails_string(config.option<ConfigOptionPoints>(pure_key)->values);
}
else if (pure_key == "head_wrap_detect_zone") {
return get_thumbnails_string(config.option<ConfigOptionPoints>(pure_key)->values);
}
else if (pure_key == "wrapping_exclude_area") {
return get_thumbnails_string(config.option<ConfigOptionPoints>(pure_key)->values);
}
Vec2d val = config.opt<ConfigOptionPoints>(pure_key)->get_at(opt_idx);
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
}
default:
break;
}
return out;
}
} // namespace GUI
} // namespace Slic3r
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <wx/string.h>
namespace Slic3r {
class DynamicPrintConfig;
namespace GUI {
// Human-readable value of opt_key (may carry a "#<index>" suffix) in config.
wxString get_string_value(const std::string& opt_key, const DynamicPrintConfig& config);
// Full label of opt_key; "N/A" when the option is not set.
wxString get_full_label(const std::string& opt_key, const DynamicPrintConfig& config);
// Strip the "#<index>" suffix (if any) from the option key.
std::string get_pure_opt_key(const std::string& opt_key);
// Localized label of the currently selected value of an enum option.
wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config, bool is_infill = false, int idx = -1);
} // namespace GUI
} // namespace Slic3r
+1 -1
View File
@@ -2752,7 +2752,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
});
if (wxLinux_gtk3)
this->Bind(wxEVT_SHOW, [this, vsizer](const wxShowEvent& e) {
this->Bind(wxEVT_SHOW, [](const wxShowEvent& e) {
;
});
+7 -5
View File
@@ -599,7 +599,9 @@ static char* read_json_file(const std::string &preset_path)
return NULL;
}
fread(json_contents, 1, file_size, json_file);
const size_t read_bytes = fread(json_contents, 1, file_size, json_file);
if (read_bytes != static_cast<size_t>(file_size))
BOOST_LOG_TRIVIAL(error) << "Read " << read_bytes << " of " << file_size << " bytes from the JSON file";
fclose(json_file);
return json_contents;
@@ -1885,7 +1887,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_nozzle_diameter_item(wxWindow *par
m_custom_nozzle_diameter_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE);
m_custom_nozzle_diameter_ctrl->SetHint(_L("Input Custom Nozzle Diameter"));
m_custom_nozzle_diameter_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) {
m_custom_nozzle_diameter_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent &event) {
int key = event.GetKeyCode();
if (key != 44 && key != 46 && cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed
event.Skip(false);
@@ -3867,14 +3869,14 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *,
m_preset_sizer->Add(create_checkbox(m_presets_window, preset.second, printer_name, m_preset), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT,
FromDIP(5));
}
m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip."));
m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive."));
} else if (export_type == m_exprot_type.filament_preset) {
for (std::pair<std::string, std::vector<std::pair<std::string, Preset *>>> filament_name_to_preset : m_filament_name_to_presets) {
if (filament_name_to_preset.second.empty()) continue;
wxString filament_name = wxString::FromUTF8(filament_name_to_preset.first);
m_preset_sizer->Add(create_checkbox(m_presets_window, filament_name, m_printer_name), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5));
}
m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a zip."));
m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a ZIP archive."));
} else if (export_type == m_exprot_type.process_preset) {
for (std::pair<std::string, std::vector<Preset *>> presets : m_process_presets) {
Preset * printer_preset = preset_bundle->printers.find_preset(presets.first, false);
@@ -3890,7 +3892,7 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *,
}
}
m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a zip."));
m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a ZIP archive."));
}
//m_presets_window->SetSizerAndFit(m_preset_sizer);
m_presets_window->Layout();
-1
View File
@@ -74,7 +74,6 @@ private:
std::unordered_set<std::string> m_system_filament_types_set;
std::set<std::string> m_visible_printers;
CreateType m_create_type;
Button * m_button_cancel = nullptr;
ComboBox * m_filament_vendor_combobox = nullptr;
::CheckBox * m_can_not_find_vendor_checkbox = nullptr;
ComboBox * m_filament_type_combobox = nullptr;
-1
View File
@@ -245,7 +245,6 @@ DailyTipsPanel::DailyTipsPanel(bool can_expand, DailyTipsLayout layout)
m_width(0),
m_height(0),
m_can_expand(can_expand),
m_layout(layout),
m_uid(DailyTipsPanel::uid++),
m_dailytips_renderer(std::make_unique<DailyTipsDataRenderer>(layout))
{
-1
View File
@@ -51,7 +51,6 @@ private:
int m_uid;
bool m_first_enter{ false };
bool m_is_dark{ false };
DailyTipsLayout m_layout{ DailyTipsLayout::Vertical };
float m_fade_opacity{ 1.0f };
};
+1 -1
View File
@@ -54,7 +54,7 @@ public:
void ParseCalibrationConfig(const json& print_json); //cali
private:
MachineObject* m_obj;
[[maybe_unused]] MachineObject* m_obj;
/*configure vals*/
// chamber
+1 -1
View File
@@ -31,7 +31,7 @@ protected:
DevExtensionTool(MachineObject* obj);
private:
MachineObject* m_owner = nullptr;
[[maybe_unused]] MachineObject* m_owner = nullptr;
enum MountState
{
@@ -28,7 +28,7 @@ public:
void SetAutoRefillEnabled(bool enable) { m_enable_auto_refill = enable; }
private:
DevFilaSystem* m_owner = nullptr;
[[maybe_unused]] DevFilaSystem* m_owner = nullptr;
std::optional<bool> m_enable_detect_on_insert = false;
bool m_enable_detect_on_powerup = false;
@@ -241,8 +241,11 @@ void check_filaments(const DevFilaBlacklist::CheckFilamentInfo& check_info, DevF
std::set<std::string> white_fila_ids = filament_item.contains("white_fila_ids") ? filament_item["white_fila_ids"].get<std::set<std::string>>() : std::set<std::string>();
if (!white_fila_ids.empty() && !check_info.fila_id.empty())
{
auto it = std::find_if(white_fila_ids.begin(), white_fila_ids.end(), [&check_info](const std::string& white_fila_id) {
return white_fila_id == check_info.fila_id;
// check_info.fila_id is our OF id; white_fila_ids in filaments_blacklist.json holds the printer's own.
auto* agent = Slic3r::GUI::wxGetApp().getAgent();
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(check_info.fila_id) : check_info.fila_id;
auto it = std::find_if(white_fila_ids.begin(), white_fila_ids.end(), [&printer_filament_id](const std::string& white_fila_id) {
return white_fila_id == printer_filament_id;
});
if (it != white_fila_ids.end()) { continue; }
}
+12 -3
View File
@@ -5,6 +5,7 @@
// TODO: remove this include
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "DevUtil.h"
#include "DevUtilBackend.h"
@@ -95,7 +96,12 @@ std::string DevAmsTray::get_filament_type()
if (m_fila_type == "Sup.ABS") { return "ABS-S"; }
if (m_fila_type == "Support W") { return "PLA-S"; }
if (m_fila_type == "Support G") { return "PA-S"; }
if (m_fila_type == "Support") { if (setting_id == "GFS00") { m_fila_type = "PLA-S"; } else if (setting_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; } }
// setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
if (m_fila_type == "Support") {
auto* agent = GUI::wxGetApp().getAgent();
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(setting_id) : setting_id;
if (printer_filament_id == "GFS00") { m_fila_type = "PLA-S"; } else if (printer_filament_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; }
}
return m_fila_type;
}
@@ -654,11 +660,14 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
curr_tray->setting_id = (*tray_it)["tray_info_idx"].get<std::string>();
//std::string type = (*tray_it)["tray_type"].get<std::string>();
std::string type = MachineObject::setting_id_to_type(curr_tray->setting_id, (*tray_it)["tray_type"].get<std::string>());
if (curr_tray->setting_id == "GFS00")
// curr_tray->setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
auto* agent = GUI::wxGetApp().getAgent();
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(curr_tray->setting_id) : curr_tray->setting_id;
if (printer_filament_id == "GFS00")
{
curr_tray->m_fila_type = "PLA-S";
}
else if (curr_tray->setting_id == "GFS01")
else if (printer_filament_id == "GFS01")
{
curr_tray->m_fila_type = "PA-S";
}
+1 -1
View File
@@ -58,7 +58,7 @@ public:
std::string id;
std::string tag_uid; // tag_uid
std::string setting_id; // tray_info_idx
std::string setting_id; // tray_info_idx, map to the filament_id
std::string filament_setting_id; // setting_id
std::string m_fila_type;
std::string sub_brands;
+1 -1
View File
@@ -21,7 +21,7 @@ public:
const std::vector<DevHMSItem>& GetHMSItems() const { return m_hms_list; };
private:
MachineObject* m_object = nullptr;
[[maybe_unused]] MachineObject* m_object = nullptr;
// all hms for this machine
std::vector<DevHMSItem> m_hms_list;
+1 -1
View File
@@ -34,7 +34,7 @@ private:
//std::string m_connect_type;
//std::string m_bind_state;
MachineObject* m_owner = nullptr;
[[maybe_unused]] MachineObject* m_owner = nullptr;
};
} // namespace Slic3r
+1 -1
View File
@@ -872,7 +872,7 @@ namespace Slic3r
obj->m_is_online = elem["dev_online"].get<bool>();
if (elem.contains("dev_model_name") && !elem["dev_model_name"].is_null()) {
auto printer_type = elem["dev_model_name"].get<std::string>();
for (const std::pair<std::string, std::vector<std::string>> &pair : device_subseries) {
for (const auto &pair : device_subseries) {
auto it = std::find(pair.second.begin(), pair.second.end(), printer_type);
if (it != pair.second.end())
{
+1 -1
View File
@@ -36,7 +36,7 @@ public:
void ParseStatus(const nlohmann::json& print_jj);
private:
MachineObject *m_owner = nullptr;
[[maybe_unused]] MachineObject *m_owner = nullptr;
std::optional<DevJobState> m_job_state; // could be nullopt for some old firmware
};
+1 -1
View File
@@ -31,7 +31,7 @@ public:
bool is_timelapse_storage_low(const std::string& storage) const;
private:
MachineObject *m_owner;
[[maybe_unused]] MachineObject *m_owner;
SdcardState m_sdcard_state { NO_SDCARD };
// timelapse storage space info (from device push cam data)
int tl_internal_free_kb{-1};
+27 -4
View File
@@ -110,7 +110,9 @@ bool Slic3r::is_stringing_prone_filament(const std::string& filament_id, float n
if (filament_id.empty()) return false;
const auto* set = pick_stringing_set(nozzle_diameter);
if (!set) return false;
return set->count(filament_id) > 0;
// filament_id is one of our content-addressed OF ids; the table above is keyed by the printer's own.
auto* agent = Slic3r::GUI::wxGetApp().getAgent();
return set->count(agent ? agent->from_orca_filament_id(filament_id) : filament_id) > 0;
}
wxString Slic3r::get_stage_string(int stage)
@@ -5048,10 +5050,13 @@ DevAmsTray MachineObject::parse_vt_tray(json vtray)
vt_tray.setting_id = vtray["tray_info_idx"].get<std::string>();
//std::string type = vtray["tray_type"].get<std::string>();
std::string type = setting_id_to_type(vt_tray.setting_id, vtray["tray_type"].get<std::string>());
if (vt_tray.setting_id == "GFS00") {
// vt_tray.setting_id is our OF id (translated on the way in); the two support ids below are the printer's own.
auto* agent = GUI::wxGetApp().getAgent();
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(vt_tray.setting_id) : vt_tray.setting_id;
if (printer_filament_id == "GFS00") {
vt_tray.m_fila_type = "PLA-S";
}
else if (vt_tray.setting_id == "GFS01") {
else if (printer_filament_id == "GFS01") {
vt_tray.m_fila_type = "PA-S";
}
else {
@@ -5592,7 +5597,10 @@ void MachineObject::update_filament_list()
for (auto it = filament_list.begin(); it != filament_list.end(); it++) {
if (m_filament_list.find(it->first) != m_filament_list.end()) {
assert(it->first.size() == 8 && it->first[0] == 'P');
// User roots may legitimately carry adopted system-shaped ids (GF*/OF*/P-hex
// system), so a non-'P' id here is expected, not an invariant violation.
if (it->first.size() != 8 || it->first[0] != 'P')
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": user-root filament_id is not user-shaped: " << it->first;
if (it->second.first != m_filament_list[it->first].first) {
BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first;
@@ -5654,6 +5662,17 @@ void MachineObject::update_printer_preset_name()
void MachineObject::check_ams_filament_valid()
{
PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle;
// A tray id carried by ANY system filament preset is not a dangling user-preset id
// (ten shipped P-hex system ids pass the 'P' shape gates below), so the destructive
// tray-wipe / temp-rewrite handling must never fire for it.
auto is_system_filament_id = [preset_bundle](const std::string &id) {
if (!preset_bundle)
return false;
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++)
if (it->is_system && it->filament_id == id)
return true;
return false;
};
auto printer_model = DevPrinterConfigUtil::get_printer_display_name(this->printer_type);
std::map<std::string, std::set<std::string>> need_checked_filament_id;
for (auto &ams_pair : m_fila_system->GetAmsList()) {
@@ -5675,6 +5694,8 @@ void MachineObject::check_ams_filament_valid()
auto &checked_filament = data.checked_filament;
for (const auto &[slot_id, curr_tray] : ams->GetTrays()) {
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && is_system_filament_id(curr_tray->setting_id))
continue;
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && filament_list.find(curr_tray->setting_id) == filament_list.end()) {
if (checked_filament.find(curr_tray->setting_id) != checked_filament.end()) {
need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id);
@@ -5735,6 +5756,8 @@ void MachineObject::check_ams_filament_valid()
auto &data = m_nozzle_filament_data[nozzle_diameter_str];
auto &checked_filament = data.checked_filament;
auto &filament_list = data.filament_list;
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && is_system_filament_id(vt_tray.setting_id))
continue;
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && filament_list.find(vt_tray.setting_id) == filament_list.end()) {
if (checked_filament.find(vt_tray.setting_id) != checked_filament.end()) {
need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id);
@@ -705,7 +705,7 @@ ReselectMachineDialog::ReselectMachineDialog(wxWindow* parent)
Centre();
}
void ReselectMachineDialog::Update(MachineObject* obj, const std::map<int, int>& best_pos_map, const std::vector<FilamentInfo>& ams_mapping, wxString save_time)
void ReselectMachineDialog::UpdateInfo(MachineObject* obj, const std::map<int, int>& best_pos_map, const std::vector<FilamentInfo>& ams_mapping, wxString save_time)
{
if (suggestText)
@@ -188,7 +188,7 @@ class ReselectMachineDialog : public wxDialog
public:
ReselectMachineDialog(wxWindow* parent);
~ReselectMachineDialog();
void Update(MachineObject* obj,
void UpdateInfo(MachineObject* obj,
const std::map<int, int>& best_pos_map,
const std::vector<FilamentInfo>& ams_mapping,
wxString save_time);
@@ -98,7 +98,7 @@ void uiAmsPercentHumidityDryPopup::Create()
Refresh();
}
void uiAmsPercentHumidityDryPopup::Update(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature)
void uiAmsPercentHumidityDryPopup::UpdateInfo(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature)
{
if (m_humidity_level != humidiy_level || m_humidity_percent != humidity_percent ||
m_left_dry_time != left_dry_time || m_current_temperature != current_temperature)
@@ -38,14 +38,14 @@ public:
~uiAmsPercentHumidityDryPopup() = default;
public:
void Update(uiAmsHumidityInfo *info) { m_ams_id = info->ams_id; Update(info->humidity_display_idx, info->humidity_percent, info->left_dry_time, info->current_temperature); };
void UpdateInfo(uiAmsHumidityInfo *info) { m_ams_id = info->ams_id; UpdateInfo(info->humidity_display_idx, info->humidity_percent, info->left_dry_time, info->current_temperature); };
std::string get_owner_ams_id() const { return m_ams_id; }
void msw_rescale();
private:
void Update(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature);
void UpdateInfo(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature);
void UpdateContents();
void Create();
@@ -399,7 +399,7 @@ void wgtDeviceNozzleRackArea::UpdateNozzleItems(const std::unordered_map<int, wg
{
for (auto iter : nozzle_items)
{
iter.second->Update(nozzle_rack);
iter.second->UpdateInfo(nozzle_rack);
}
/*update nozzle possition and background*/
@@ -837,7 +837,7 @@ void wgtDeviceNozzleRackNozzleItem::SetSelected(bool selected)
}
}
void wgtDeviceNozzleRackNozzleItem::Update(const std::shared_ptr<DevNozzleRack> rack, bool on_rack /*= true*/)
void wgtDeviceNozzleRackNozzleItem::UpdateInfo(const std::shared_ptr<DevNozzleRack> rack, bool on_rack /*= true*/)
{
m_rack = rack;
@@ -200,7 +200,7 @@ public:
wgtDeviceNozzleRackNozzleItem(wxWindow* parent, int nozzle_id);
public:
void Update(const std::shared_ptr<DevNozzleRack> rack, bool on_rack = true); // on_rack is false means extruder nozzle
void UpdateInfo(const std::shared_ptr<DevNozzleRack> rack, bool on_rack = true); // on_rack is false means extruder nozzle
int GetNozzleId() const { return m_nozzle_id; }
void SetDisplayIdText(const wxString& text) { m_nozzle_label_id->SetLabel(text);};
@@ -114,7 +114,7 @@ static void s_update_nozzle_info(wgtDeviceNozzleRackNozzleItem* item,
std::shared_ptr<DevNozzleRack> rack,
const DevNozzle& nozzle_info)
{
item->Update(rack, nozzle_info.IsOnRack());
item->UpdateInfo(rack, nozzle_info.IsOnRack());
if (nozzle_info.IsUnknown()) {
if (item->GetToolTipText() != _L("Nozzle information needs to be read")) {
item->SetToolTip(_L("Nozzle information needs to be read"));
+1
View File
@@ -3,6 +3,7 @@
#include "wx/bitmap.h"
#include "wx/dragimag.h"
#include "wx/panel.h"
namespace Slic3r { namespace GUI {
+28 -32
View File
@@ -2,6 +2,7 @@
#include "GUI_App.hpp"
#include "MsgDialog.hpp"
#include "libslic3r/Preset.hpp"
#include <algorithm>
#include "I18N.hpp"
#include <boost/log/trivial.hpp>
#include <wx/dcgraph.h>
@@ -599,8 +600,10 @@ void ExtrusionCalibration::update_combobox_filaments()
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
if (preset_bundle && obj) {
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
std::string printer_type = obj->printer_type;
std::set<std::string> printer_preset_list;
double nozzle_value = 0.4;
m_comboBox_nozzle_dia->GetValue().ToDouble(&nozzle_value);
std::vector<PresetWithVendorProfile> printer_profiles;
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
// only use system printer preset
if (!printer_it->is_system) continue;
@@ -610,49 +613,42 @@ void ExtrusionCalibration::update_combobox_filaments()
ConfigOptionFloats* printer_nozzle_vals = nullptr;
if (printer_nozzle_opt)
printer_nozzle_vals = dynamic_cast<ConfigOptionFloats*>(printer_nozzle_opt);
double nozzle_value = 0.4;
wxString nozzle_value_str = m_comboBox_nozzle_dia->GetValue();
try {
nozzle_value_str.ToDouble(&nozzle_value);
} catch(...) {
;
}
if (!model_id.empty() && model_id.compare(obj->printer_type) == 0
&& printer_nozzle_vals
&& abs(printer_nozzle_vals->get_at(0) - nozzle_value) < 1e-3) {
printer_preset_list.insert(printer_it->name);
printer_profiles.push_back(preset_bundle->printers.get_preset_with_vendor_profile(*printer_it));
BOOST_LOG_TRIVIAL(trace) << "extrusion_cali: printer_model = " << model_id;
} else {
BOOST_LOG_TRIVIAL(error) << "extrusion_cali: printer_model = " << model_id;
}
}
// Unlike the AMS dialogs this one offers every matching preset by full name rather than one
// root preset per alias, so it filters the collection itself instead of calling
// PresetBundle::get_filament_presets_for_machine().
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
ConfigOption* printer_opt = filament_it->config.option("compatible_printers");
ConfigOptionStrings* printer_strs = dynamic_cast<ConfigOptionStrings*>(printer_opt);
for (auto printer_str : printer_strs->values) {
if (printer_preset_list.find(printer_str) != printer_preset_list.end()) {
user_filaments.push_back(&(*filament_it));
const PresetWithVendorProfile filament = preset_bundle->filaments.get_preset_with_vendor_profile(*filament_it);
if (std::none_of(printer_profiles.begin(), printer_profiles.end(),
[&filament](const PresetWithVendorProfile &printer) { return is_compatible_with_printer(filament, printer); }))
continue;
// set default filament id
filament_index++;
if (filament_it->is_system
&& !ams_filament_id.empty()
&& filament_it->filament_id == ams_filament_id
) {
curr_selection = filament_index;
}
user_filaments.push_back(&(*filament_it));
if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty())
{
curr_selection = filament_index;
}
wxString filament_name = wxString::FromUTF8(filament_it->name);
filament_items.Add(filament_name);
break;
}
// set default filament id
filament_index++;
if (filament_it->is_system
&& !ams_filament_id.empty()
&& filament_it->filament_id == ams_filament_id
) {
curr_selection = filament_index;
}
if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty())
{
curr_selection = filament_index;
}
filament_items.Add(wxString::FromUTF8(filament_it->name));
}
m_comboBox_filament->Set(filament_items);
m_comboBox_filament->SetSelection(curr_selection);
+18 -5
View File
@@ -941,7 +941,11 @@ void TextCtrl::BUILD() {
temp->SetToolTip(get_tooltip_text(text_value));
if (!m_opt.multiline) {
text_ctrl->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent &e)
text_ctrl->Bind(wxEVT_TEXT_ENTER, ([
#if !defined(__WXGTK__)
temp,
#endif // __WXGTK__
this](wxEvent &e)
{
#if !defined(__WXGTK__)
e.Skip();
@@ -973,7 +977,11 @@ void TextCtrl::BUILD() {
temp->GetToolTip()->Enable(flag);
}), text_ctrl->GetId());
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent &e)
temp->Bind(wxEVT_KILL_FOCUS, ([
#if !defined(__WXGTK__)
temp,
#endif // __WXGTK__
this](wxEvent &e)
{
e.Skip();
#if !defined(__WXGTK__)
@@ -1324,7 +1332,7 @@ void SpinCtrl::BUILD() {
bEnterPressed = true;
}), temp->GetId());
temp->GetTextCtrl()->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent e)
temp->GetTextCtrl()->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
{
// # On OSX / Cocoa, SpinInput::GetValue() doesn't return the new value
// # when it was changed from the text control, so the on_change callback
@@ -2597,7 +2605,11 @@ void ColourPicker::BUILD()
// // recast as a wxWindow to fit the calling convention
window = dynamic_cast<wxWindow*>(temp);
temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([this,temp](wxCommandEvent e) {
temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([
#ifdef __WXMSW__
temp,
#endif
this](wxCommandEvent e) {
#ifdef __WXMSW__
draw_bmp_btn(temp, temp->GetColour());
#endif
@@ -2699,7 +2711,8 @@ void ColourPicker::set_value(const boost::any& value, bool change_event)
auto field = dynamic_cast<wxColourPickerCtrl*>(window);
#ifdef __WXMSW__
wxColour clr = (clr_str.IsEmpty() || !clr.IsOk()) ? wxTransparentColour : clr_str;
const wxColour parsed_clr(clr_str);
wxColour clr = (clr_str.IsEmpty() || !parsed_clr.IsOk()) ? wxTransparentColour : parsed_clr;
field->SetColour(clr);
draw_bmp_btn(field, clr);
#else
+425 -1
View File
@@ -1,16 +1,66 @@
#include <wx/dcmemory.h>
#include <wx/dcgraph.h>
#include <wx/graphics.h>
#include <wx/settings.h>
#include <wx/window.h>
#include <algorithm>
#include <cmath>
#include <map>
#include <numeric>
#include <string>
#include <tuple>
#include "EncodedFilament.hpp"
#include "FilamentBitmapUtils.hpp"
#include "GUI_App.hpp"
#include "GuiColor.hpp"
#include "I18N.hpp"
#include "Widgets/Label.hpp"
#include "Widgets/StateColor.hpp"
#include "libslic3r/FilamentMixer.hpp"
#include "libslic3r/PrintConfig.hpp"
namespace Slic3r { namespace GUI {
// Barycentric utilities for a ternary (triangle) ratio picker.
double tri_signed_area2(TriPoint a, TriPoint b, TriPoint c)
{
return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}
bool tri_contains(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2)
{
double total = tri_signed_area2(v0, v1, v2);
if (std::abs(total) < 1e-9) return false;
double s0 = tri_signed_area2(p, v1, v2) / total;
double s1 = tri_signed_area2(v0, p, v2) / total;
double s2 = 1.0 - s0 - s1;
return s0 >= -0.001 && s1 >= -0.001 && s2 >= -0.001;
}
void tri_barycentric(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2,
double& w0, double& w1, double& w2)
{
double total = std::abs(tri_signed_area2(v0, v1, v2));
if (total < 1e-9) { w0 = w1 = w2 = 1.0 / 3.0; return; }
w0 = std::abs(tri_signed_area2(p, v1, v2)) / total;
w1 = std::abs(tri_signed_area2(v0, p, v2)) / total;
w2 = 1.0 - w0 - w1;
w0 = std::clamp(w0, 0.0, 1.0);
w1 = std::clamp(w1, 0.0, 1.0);
w2 = std::clamp(w2, 0.0, 1.0);
double s = w0 + w1 + w2;
if (s > 0) { w0 /= s; w1 /= s; w2 /= s; }
}
TriPoint tri_clamp(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2)
{
double w0, w1, w2;
tri_barycentric(p, v0, v1, v2, w0, w1, w2);
return {w0 * v0.x + w1 * v1.x + w2 * v2.x,
w0 * v0.y + w1 * v1.y + w2 * v2.y};
}
void fill_gradient_rect_east(wxDC& dc, const wxRect& rect, const wxColour& from, const wxColour& to)
{
if (rect.width <= 0 || rect.height <= 0) return;
@@ -73,7 +123,7 @@ std::vector<wxColour> sample_gradient_ramp(const wxColour& first,
// Resolve the curve a gradient slot is sampled with, mirroring the slicer's fallback in
// ToolOrdering: a custom curve wins, otherwise a straight line between gradient_range's
// endpoints, otherwise the 0.10 -> 0.90 default.
static Slic3r::GradientCurve mixed_gradient_curve(const Slic3r::DynamicPrintConfig& cfg, size_t slot)
Slic3r::GradientCurve mixed_gradient_curve(const Slic3r::DynamicPrintConfig& cfg, size_t slot)
{
const auto* curve_opt = cfg.option<ConfigOptionStrings>("filament_mixed_gradient_curve");
if (curve_opt && slot < curve_opt->values.size() && !curve_opt->values[slot].empty()) {
@@ -449,4 +499,378 @@ void recompute_mixed_slot_colors(std::vector<wxColour>& colors,
}
}
namespace {
// Layout ratios of the gradient plot rect, copied from GradientCurveEditor so the read-only
// preview and the interactive editor stay pixel-identical. Plot rect is square 1:1; the
// right/bottom margins host the axis arrows and labels.
constexpr double kPlotLeftRatio = 0.0316;
constexpr double kPlotRightRatio = 0.6766;
constexpr double kPlotTopRatio = 0.1529;
constexpr double kPlotBottomRatio = 0.8474;
constexpr int kGridDivisions = 9; // 10 grid lines including the outer borders.
constexpr int kStrokeAxis = 2; // axis line width (px, no DPI scaling)
constexpr int kAxisArrowHalf = 5; // half-base of the axis arrow triangle (DIP)
constexpr int kAxisArrowLen = 10; // length of the axis arrow triangle (DIP)
constexpr int kPointRadius = 4; // anchor outer radius (DIP)
constexpr float kBgSimilarThreshold = 15.0f;
constexpr int kOutlineExtraDip = 2;
constexpr double kTriangleMarginDip = 20.0;
// Quadratic blend that never goes out of gamut, matching MixedFilamentDialog::blend_colors.
wxColour lerp_blend(const wxColour& a, const wxColour& b, double ratio_a)
{
unsigned char r, g, bl;
Slic3r::filament_mixer_lerp(a.Red(), a.Green(), a.Blue(),
b.Red(), b.Green(), b.Blue(),
static_cast<float>(1.0 - ratio_a), &r, &g, &bl);
return wxColour(r, g, bl);
}
// DIP conversion for these free functions: unlike the wxWindow member FromDIP, it needs the
// window parameter explicitly; nullptr picks the app's default DPI like the Publish dialog does.
int dip_px(int v) { return wxWindow::FromDIP(v, nullptr); }
} // namespace
wxRect mixed_gradient_plot_rect(const wxSize& sz)
{
const int x = static_cast<int>(std::lround(sz.x * kPlotLeftRatio));
const int y = static_cast<int>(std::lround(sz.y * kPlotTopRatio));
const int x2 = static_cast<int>(std::lround(sz.x * kPlotRightRatio));
const int y2 = static_cast<int>(std::lround(sz.y * kPlotBottomRatio));
const int side = std::max(1, std::min(x2 - x, y2 - y));
return wxRect(x, y, side, side);
}
void draw_mixed_gradient_plot(wxDC& raw_dc, const wxSize& canvas,
const std::vector<MixedGradientCurve>& curves,
const std::vector<wxPoint2DDouble>& anchors,
const MixedGradientTheme& theme)
{
// Draw into an internal opaque buffer so wxGCDC text/curves anti-alias against a solid
// background (never a transparent one), then blit the finished image onto the caller's
// buffered paint DC. wxGCDC cannot wrap a generic wxDC&, so the buffer is always a
// wxMemoryDC -- the one type wxGCDC accepts on every platform.
if (canvas.x <= 0 || canvas.y <= 0)
return;
const wxRect rc = mixed_gradient_plot_rect(canvas);
if (rc.width <= 0 || rc.height <= 0)
return;
wxBitmap buf(canvas);
wxMemoryDC memdc(buf);
memdc.SetBackground(wxBrush(theme.background));
memdc.Clear();
wxGCDC dc(memdc);
wxGraphicsContext* gc = dc.GetGraphicsContext();
// 10x10 light grid (10 lines including outer borders, 9 equal divisions).
dc.SetPen(wxPen(theme.grid, 1));
for (int i = 0; i <= kGridDivisions; ++i) {
const int x = rc.x + rc.width * i / kGridDivisions;
const int y = rc.y + rc.height * i / kGridDivisions;
dc.DrawLine(x, rc.y, x, rc.y + rc.height);
dc.DrawLine(rc.x, y, rc.x + rc.width, y);
}
// Set the label font first so text width measurements drive arrow / label placement.
wxFont label_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
label_font.SetPointSize(std::max(7, label_font.GetPointSize() - 1));
dc.SetFont(label_font);
const wxString axis_y_title = _L("Material Ratio");
const wxString axis_x_title = _L("Model Height");
const wxString pct_text = wxT("100%");
const wxSize x_title_sz = dc.GetTextExtent(axis_x_title);
const wxSize y_title_sz = dc.GetTextExtent(axis_y_title);
wxFont strong_font = label_font;
strong_font.SetWeight(wxFONTWEIGHT_SEMIBOLD);
dc.SetFont(strong_font);
const wxSize pct_text_sz = dc.GetTextExtent(pct_text);
dc.SetFont(label_font);
// Axes (grey 700) with filled triangle arrows. Y-axis extends above the plot top to the
// canvas top edge; X-axis extends past the plot right toward the canvas right edge.
const int arrow_half = dip_px(kAxisArrowHalf);
const int arrow_len = dip_px(kAxisArrowLen);
dc.SetPen(wxPen(theme.axis, kStrokeAxis));
dc.SetBrush(wxBrush(theme.axis));
const int y_axis_x = rc.x;
const int y_title_pct_gap = dip_px(1);
const int y_title_bottom_pad = dip_px(2);
const int y_title_y = std::max(0, rc.y - y_title_sz.y - y_title_pct_gap - pct_text_sz.y - y_title_bottom_pad);
const int y_arrow_tip_y = y_title_y;
const int y_arrow_ty = y_arrow_tip_y + arrow_len;
dc.DrawLine(y_axis_x, y_arrow_ty, y_axis_x, rc.y + rc.height);
{
wxPoint tri[3] = {
wxPoint(y_axis_x, y_arrow_tip_y),
wxPoint(y_axis_x - arrow_half, y_arrow_ty),
wxPoint(y_axis_x + arrow_half, y_arrow_ty),
};
dc.DrawPolygon(3, tri);
}
const int x_axis_y = rc.y + rc.height;
const int x_label_gap = dip_px(4);
const int x_edge_pad = dip_px(6);
const int x_arrow_ideal = rc.x + rc.width + dip_px(10);
const int x_arrow_max = canvas.x - x_title_sz.x - x_label_gap - x_edge_pad - arrow_len;
const int x_arrow_tx = std::max(rc.x + rc.width + arrow_len, std::min(x_arrow_ideal, x_arrow_max));
const int x_arrow_tip_x = x_arrow_tx + arrow_len;
const int x_title_x = x_arrow_tip_x + x_label_gap;
dc.DrawLine(rc.x, x_axis_y, x_arrow_tx, x_axis_y);
{
wxPoint tri[3] = {
wxPoint(x_arrow_tip_x, x_axis_y),
wxPoint(x_arrow_tx, x_axis_y - arrow_half),
wxPoint(x_arrow_tx, x_axis_y + arrow_half),
};
dc.DrawPolygon(3, tri);
}
// Labels: "Material Ratio" and the leading "100%" share the same left x; the trailing
// "Model Height" follows the X-axis arrow tip (already clamped to make room).
const int label_left_x = y_axis_x + dip_px(10);
dc.SetTextForeground(theme.label);
dc.DrawText(axis_y_title, label_left_x, y_title_y);
dc.SetFont(strong_font);
dc.SetTextForeground(theme.label_strong);
dc.DrawText(pct_text, label_left_x, y_title_y + y_title_sz.y + y_title_pct_gap);
dc.DrawText(pct_text, rc.x + rc.width - pct_text_sz.x, x_axis_y);
dc.SetFont(label_font);
dc.SetTextForeground(theme.label);
dc.DrawText(axis_x_title, x_title_x, x_axis_y - x_title_sz.y / 2);
if (!gc)
return;
// Outline only when the curve colour is perceptually close to the background; otherwise the
// plain filament colour reads fine and the extra stroke would look heavy.
auto needs_outline = [&](const wxColour& c) {
return calc_color_distance(c, theme.background) < kBgSimilarThreshold;
};
// Only the geometry goes through the graphics context: dc.DrawLines() takes integer wxPoint
// and would quantize the curve back to whole pixels. The pen is still set on the dc, which
// forwards it here while keeping its own cached state in sync for later dc drawing.
auto draw_polyline = [&](const MixedGradientCurve& curve) {
if (curve.points.size() < 2)
return;
dc.SetPen(wxPen(curve.colour, dip_px(curve.stroke_dip)));
gc->StrokeLines(curve.points.size(), curve.points.data());
};
for (const MixedGradientCurve& curve : curves) {
if (needs_outline(curve.colour))
draw_polyline({curve.points, theme.outline, curve.stroke_dip + kOutlineExtraDip});
draw_polyline(curve);
}
// Control points: hollow circle with axis-colour border, theme-aware fill, drawn with a
// sub-pixel centre so the ring stays centred on the curve.
if (!anchors.empty()) {
const double r = dip_px(kPointRadius);
dc.SetPen(wxPen(theme.axis, 1));
dc.SetBrush(wxBrush(theme.point_fill));
for (const wxPoint2DDouble& p : anchors)
gc->DrawEllipse(p.m_x - r, p.m_y - r, r * 2, r * 2);
}
memdc.SelectObject(wxNullBitmap);
raw_dc.DrawBitmap(buf, 0, 0);
}
void draw_mixed_ratio_blend_bar(wxDC& dc, const wxRect& rect, const wxColour& first,
const wxColour& second, double second_fraction)
{
if (rect.width <= 0 || rect.height <= 0)
return;
for (int x = 0; x < rect.width; ++x) {
const double t = rect.width > 1 ? double(x) / rect.width : 0.0;
const wxColour c = lerp_blend(first, second, 1.0 - t);
dc.SetPen(wxPen(c));
dc.DrawLine(rect.x + x, rect.y, rect.x + x, rect.y + rect.height);
}
// Fixed in both themes, like the triangle picker's drag handle: the divider is drawn over
// blended filament colour, so it has to keep its contrast against data rather than chrome.
const int div_x = rect.x + static_cast<int>(second_fraction * rect.width);
dc.SetPen(wxPen(wxColour(80, 80, 80), dip_px(4)));
dc.DrawLine(div_x, rect.y, div_x, rect.y + rect.height);
dc.SetPen(wxPen(*wxWHITE, dip_px(2)));
dc.DrawLine(div_x, rect.y, div_x, rect.y + rect.height);
}
void draw_mixed_ratio_segments(wxDC& dc, const wxRect& rect, const std::vector<wxColour>& colours,
const std::vector<double>& shares)
{
const size_t n = std::min(colours.size(), shares.size());
if (n == 0 || rect.width <= 0 || rect.height <= 0)
return;
std::vector<double> norm = shares;
double total = 0.0;
for (double s : norm)
total += s;
if (total <= 0.0) {
norm.assign(n, 1.0 / n);
total = 1.0;
}
auto share_to_px = [&](double share_sum) { return rect.x + int(std::lround(share_sum / total * double(rect.width))); };
int x0 = rect.x;
std::vector<wxRect> segs(n);
for (size_t i = 0; i < n; ++i) {
int x1 = rect.x + rect.width;
if (i + 1 < n)
x1 = share_to_px(std::accumulate(norm.begin(), norm.begin() + i + 1, 0.0));
segs[i] = wxRect(x0, rect.y, std::max(1, x1 - x0), rect.height);
x0 = segs[i].GetRight() + 1;
}
for (size_t i = 0; i < n; ++i) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(colours[i]));
dc.DrawRectangle(segs[i]);
}
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.SetPen(wxPen(StateColor::darkModeColorFor(wxColour("#ACACAC")), 1));
dc.DrawRectangle(rect);
}
namespace {
struct TriCacheKey
{
int w, h;
int c0r, c0g, c0b, c1r, c1g, c1b, c2r, c2g, c2b;
int bg_r, bg_g, bg_b, ol_r, ol_g, ol_b;
bool operator<(const TriCacheKey& o) const
{
return std::tie(w, h, c0r, c0g, c0b, c1r, c1g, c1b, c2r, c2g, c2b, bg_r, bg_g, bg_b, ol_r, ol_g, ol_b) <
std::tie(o.w, o.h, o.c0r, o.c0g, o.c0b, o.c1r, o.c1g, o.c1b, o.c2r, o.c2g, o.c2b, o.bg_r, o.bg_g, o.bg_b, o.ol_r, o.ol_g, o.ol_b);
}
};
std::map<TriCacheKey, wxBitmap>& tri_cache()
{
static std::map<TriCacheKey, wxBitmap> cache;
return cache;
}
} // namespace
std::array<TriPoint, 3> mixed_triangle_vertices(const wxSize& size, double margin_dip)
{
const double pw = size.GetWidth(), ph = size.GetHeight();
const double margin = dip_px(int(margin_dip));
const double avail = std::min(pw, ph) - 2.0 * margin;
const double side = avail;
const double tri_h = side * std::sqrt(3.0) / 2.0;
const double cx = pw / 2.0;
const double top_y = (ph - tri_h) / 2.0;
return {{{cx, top_y}, {cx - side / 2.0, top_y + tri_h}, {cx + side / 2.0, top_y + tri_h}}};
}
void draw_mixed_triangle_picker(wxDC& dc, const wxSize& size, const std::array<wxColour, 3>& colours,
const std::array<double, 3>& weights, const MixedTriangleTheme& theme)
{
if (size.GetWidth() <= 0 || size.GetHeight() <= 0)
return;
const std::array<TriPoint, 3> v = mixed_triangle_vertices(size, kTriangleMarginDip);
dc.SetBrush(wxBrush(theme.background));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());
const wxColour& c0 = colours[0];
const wxColour& c1 = colours[1];
const wxColour& c2 = colours[2];
const TriCacheKey key{size.GetWidth(), size.GetHeight(),
c0.Red(), c0.Green(), c0.Blue(),
c1.Red(), c1.Green(), c1.Blue(),
c2.Red(), c2.Green(), c2.Blue(),
theme.background.Red(), theme.background.Green(), theme.background.Blue(),
theme.outline.Red(), theme.outline.Green(), theme.outline.Blue()};
wxBitmap& bmp = tri_cache()[key];
if (!bmp.IsOk()) {
bmp = wxBitmap(size.GetWidth(), size.GetHeight(), 24);
wxMemoryDC mdc(bmp);
mdc.SetBrush(wxBrush(theme.background));
mdc.SetPen(*wxTRANSPARENT_PEN);
mdc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());
const int min_y = int(std::min({v[0].y, v[1].y, v[2].y}));
const int max_y = int(std::max({v[0].y, v[1].y, v[2].y}));
const int min_x = int(std::min({v[0].x, v[1].x, v[2].x}));
const int max_x = int(std::max({v[0].x, v[1].x, v[2].x}));
for (int py = min_y; py <= max_y; ++py) {
for (int px = min_x; px <= max_x; ++px) {
const TriPoint p = {double(px), double(py)};
if (!tri_contains(p, v[0], v[1], v[2]))
continue;
double w0, w1, w2;
tri_barycentric(p, v[0], v[1], v[2], w0, w1, w2);
unsigned char mr, mg, mb;
if (w0 + w1 > 1e-6) {
float t01 = float(w1 / (w0 + w1));
Slic3r::filament_mixer_lerp(c0.Red(), c0.Green(), c0.Blue(), c1.Red(), c1.Green(), c1.Blue(), t01, &mr, &mg, &mb);
Slic3r::filament_mixer_lerp(mr, mg, mb, c2.Red(), c2.Green(), c2.Blue(), float(w2), &mr, &mg, &mb);
} else {
mr = c2.Red(); mg = c2.Green(); mb = c2.Blue();
}
mdc.SetPen(wxPen(wxColour(mr, mg, mb)));
mdc.DrawPoint(px, py);
}
}
mdc.SetPen(wxPen(theme.outline, 1));
mdc.SetBrush(*wxTRANSPARENT_BRUSH);
const wxPoint pts[3] = {{int(v[0].x), int(v[0].y)}, {int(v[1].x), int(v[1].y)}, {int(v[2].x), int(v[2].y)}};
mdc.DrawPolygon(3, pts);
mdc.SelectObject(wxNullBitmap);
// Keep the cache from growing without bound across DPI/size changes.
if (tri_cache().size() > 6) {
auto& cache = tri_cache();
cache.erase(cache.begin());
}
}
dc.DrawBitmap(bmp, 0, 0);
// Published-ratio marker (read-only twin of the editor's drag handle).
const double w0 = weights[0], w1 = weights[1], w2 = weights[2];
const int hx = int(w0 * v[0].x + w1 * v[1].x + w2 * v[2].x);
const int hy = int(w0 * v[0].y + w1 * v[1].y + w2 * v[2].y);
dc.SetBrush(*wxWHITE_BRUSH);
dc.SetPen(wxPen(theme.ring, dip_px(2)));
dc.DrawCircle(hx, hy, dip_px(5));
}
void draw_mixed_triangle_labels(wxDC& dc, const wxSize& size, const std::array<double, 3>& weights,
const MixedTriangleTheme& theme)
{
const std::array<TriPoint, 3> v = mixed_triangle_vertices(size, kTriangleMarginDip);
dc.SetFont(::Label::Body_12);
dc.SetTextForeground(theme.label);
// "Ratio" title, sitting above the top vertex.
const wxString title = _L("Ratio");
dc.DrawText(title, dip_px(2), std::max(0, int(v[0].y - dc.GetTextExtent(title).GetHeight() - dip_px(4))));
for (int i = 0; i < 3; ++i) {
const wxString text = wxString::Format("%d%%", int(std::lround(weights[i] * 100.0)));
const wxSize tsz = dc.GetTextExtent(text);
int lx = int(v[i].x - tsz.GetWidth() / 2.0);
int ly = (i == 0) ? int(v[i].y - tsz.GetHeight() - dip_px(4)) : int(v[i].y + dip_px(3));
ly = std::clamp(ly, 0, size.GetHeight() - tsz.GetHeight());
lx = std::clamp(lx, 0, size.GetWidth() - tsz.GetWidth());
dc.DrawText(text, lx, ly);
}
}
}} // namespace Slic3r::GUI
+94
View File
@@ -5,6 +5,9 @@
#include <wx/colour.h>
#include <wx/dc.h>
#include <wx/gdicmn.h>
#include <wx/geometry.h>
#include <wx/graphics.h>
#include <array>
#include <vector>
// Orca: forward-declare so the header is self-contained outside libslic3r_gui's
@@ -13,6 +16,16 @@ namespace Slic3r { class DynamicPrintConfig; struct GradientCurve; }
namespace Slic3r { namespace GUI {
// Barycentric utilities for a ternary (triangle) ratio picker, shared by the mixed-filament
// editor and the Publish dialog's read-only definition preview.
struct TriPoint { double x, y; };
double tri_signed_area2(TriPoint a, TriPoint b, TriPoint c);
bool tri_contains(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2);
void tri_barycentric(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2,
double& w0, double& w1, double& w2);
TriPoint tri_clamp(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2);
// Fills a rect with a west->east linear gradient by drawing solid 1px columns.
// Use instead of wxDC::GradientFillLinear, whose CoreGraphics (CGShading) backend
// fails to render on some macOS builds; solid fills are unaffected.
@@ -51,6 +64,12 @@ std::vector<wxColour> sample_gradient_ramp(const wxColour& first,
// destination's height in pixels.
std::vector<wxColour> mixed_gradient_ramp(const Slic3r::DynamicPrintConfig& cfg, size_t slot, int steps);
// Resolve the curve a gradient slot is sampled with: the custom curve wins when it has at
// least two points, otherwise a straight line between gradient_range's endpoints, otherwise
// the 0.10 -> 0.90 default. Mirrors the slicer's ToolOrdering fallback so every preview
// agrees with what gets sliced. Always returns a two-point curve.
Slic3r::GradientCurve mixed_gradient_curve(const Slic3r::DynamicPrintConfig& cfg, size_t slot);
// Fill rect with a ramp, ramp.front() along the bottom edge.
void fill_gradient_ramp_rect(wxDC& dc, const wxRect& rect, const std::vector<wxColour>& ramp);
@@ -63,6 +82,81 @@ wxBitmap create_gradient_ramp_bitmap(const std::vector<wxColour>& ramp, const wx
void recompute_mixed_slot_colors(std::vector<wxColour>& colors,
const Slic3r::DynamicPrintConfig& cfg);
// --- Gradient plot (shared by GradientCurveEditor and the Publish dialog's read-only
// preview). The plot is a square 1:1 rect laid out with the editor's ratios so both
// render identically; curves are drawn as sub-pixel anti-aliased polylines through
// wxGCDC so they never quantize to whole pixels.
// One curve of the plot: screen-space sub-pixel points already mapped into the plot
// rect, the stroke colour and the stroke width in DIP.
struct MixedGradientCurve
{
std::vector<wxPoint2DDouble> points;
wxColour colour;
int stroke_dip;
};
// Theme tokens, resolved by the caller through StateColor::darkModeColorFor.
struct MixedGradientTheme
{
wxColour background; // for near-background outline detection
wxColour grid; // grid line
wxColour axis; // axis + arrow fill
wxColour label; // "Material Ratio" / "Model Height"
wxColour label_strong; // "100%"
wxColour outline; // near-background curve lift
wxColour point_fill; // anchor fill
};
// Square 1:1 plot rect inside `canvas`, using the editor's plot ratios.
wxRect mixed_gradient_plot_rect(const wxSize& canvas);
// Draw the whole plot (grid, axes + arrowheads, axis labels, each curve with an optional
// near-background outline, and anchor circles). `anchors` are empty when the caller has
// none to show. `dc` is the caller's buffered paint DC; a wxGCDC is created inside so the
// geometry gets anti-aliased.
void draw_mixed_gradient_plot(wxDC& dc, const wxSize& canvas,
const std::vector<MixedGradientCurve>& curves,
const std::vector<wxPoint2DDouble>& anchors,
const MixedGradientTheme& theme);
// --- Ratio bar (2-component continuous blend + divider, matching MixedFilamentDialog).
// Colours blend first->second across the rect; the divider marks `second_fraction` of the
// rect's width (the second component's share, 0..1).
void draw_mixed_ratio_blend_bar(wxDC& dc, const wxRect& rect, const wxColour& first,
const wxColour& second, double second_fraction);
// Fallback ratio bar for N>2 non-gradient slots: one solid segment per component,
// widths proportional to shares. Label text (the "NN%" inside wide-enough segments) is
// the caller's concern.
void draw_mixed_ratio_segments(wxDC& dc, const wxRect& rect, const std::vector<wxColour>& colours,
const std::vector<double>& shares);
// --- Triangle picker (3-component), shared by MixedFilamentDialog and the Publish preview.
struct MixedTriangleTheme
{
wxColour background;
wxColour outline; // triangle border
wxColour ring; // drag-handle ring
wxColour label; // "Ratio" title + per-vertex labels
};
// The three vertices of the read-only/miniature triangle inside a `size` square panel,
// with `margin_dip` inset. Order: top, bottom-left, bottom-right.
std::array<TriPoint, 3> mixed_triangle_vertices(const wxSize& size, double margin_dip = 20.0);
// Draw background, the cached barycentric fill, the outline and the drag-handle marker.
// `weights` are the three barycentric shares (sum 1). The "Ratio" title and per-vertex
// percentage labels are drawn by the caller so the interactive editor can keep its own
// live child labels while the read-only preview draws them as text.
void draw_mixed_triangle_picker(wxDC& dc, const wxSize& size, const std::array<wxColour, 3>& colours,
const std::array<double, 3>& weights, const MixedTriangleTheme& theme);
// Draw the "Ratio" title plus one "NN%" label per vertex (used by the read-only preview;
// the interactive editor positions its own live labels instead).
void draw_mixed_triangle_labels(wxDC& dc, const wxSize& size, const std::array<double, 3>& weights,
const MixedTriangleTheme& theme);
}} // namespace Slic3r::GUI
#endif // slic3r_GUI_FilamentBitmapUtils_hpp_
+1 -1
View File
@@ -241,7 +241,7 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL);
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("Fila Saving") : _L("Auto"), false);
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("File Saving") : _L("Auto"), false);
m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false);
if (show_default)
m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Same as Global"), true);
+12 -32
View File
@@ -642,19 +642,12 @@ void FilamentMapBtnPanel::Select(bool selected)
Refresh();
}
void GUI::FilamentMapBtnPanel::Hide()
bool GUI::FilamentMapBtnPanel::Show(bool show)
{
m_btn->Hide();
m_label->Hide();
m_detail->Hide();
wxPanel::Hide();
}
void GUI::FilamentMapBtnPanel::Show()
{
m_btn->Show();
m_label->Show();
m_detail->Show();
wxPanel::Show();
m_btn->Show(show);
m_label->Show(show);
m_detail->Show(show);
return wxPanel::Show(show);
}
FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode, bool machine_synced) : wxPanel(parent)
@@ -694,18 +687,11 @@ FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mod
Layout();
GUI::wxGetApp().UpdateDarkUIWin(this);
}
void FilamentMapAutoPanel::Hide()
bool FilamentMapAutoPanel::Show(bool show)
{
m_flush_panel->Hide();
m_match_panel->Hide();
wxPanel::Hide();
}
void FilamentMapAutoPanel::Show()
{
m_flush_panel->Show();
m_match_panel->Show();
wxPanel::Show();
m_flush_panel->Show(show);
m_match_panel->Show(show);
return wxPanel::Show(show);
}
void FilamentMapAutoPanel::UpdateStatus()
@@ -743,16 +729,10 @@ FilamentMapDefaultPanel::FilamentMapDefaultPanel(wxWindow *parent) : wxPanel(par
GUI::wxGetApp().UpdateDarkUIWin(this);
}
void FilamentMapDefaultPanel::Hide()
bool FilamentMapDefaultPanel::Show(bool show)
{
m_label->Hide();
wxPanel::Hide();
}
void FilamentMapDefaultPanel::Show()
{
m_label->Show();
wxPanel::Show();
m_label->Show(show);
return wxPanel::Show(show);
}
}} // namespace Slic3r::GUI
+4 -7
View File
@@ -69,10 +69,9 @@ class FilamentMapBtnPanel : public wxPanel
{
public:
FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon_path);
void Hide();
void Show();
bool Show(bool show = true) override;
void Select(bool selected);
bool Enable(bool enable);
bool Enable(bool enable) override;
bool IsEnabled() const { return m_enabled; }
protected:
void OnPaint(wxPaintEvent &event);
@@ -99,8 +98,7 @@ class FilamentMapAutoPanel : public wxPanel
{
public:
FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode, bool machine_synced);
void Hide();
void Show();
bool Show(bool show = true) override;
FilamentMapMode GetMode() const { return m_mode; }
private:
@@ -116,8 +114,7 @@ class FilamentMapDefaultPanel : public wxPanel
{
public:
FilamentMapDefaultPanel(wxWindow *parent);
void Hide();
void Show();
bool Show(bool show = true) override;
private:
Label *m_label;
+2 -2
View File
@@ -426,11 +426,11 @@ wxScrolledWindow* FilamentPickerDialog::CreateColorGrid()
});
// Hover highlight
btn->Bind(wxEVT_ENTER_WINDOW, [btn](wxMouseEvent& evt) {
btn->Bind(wxEVT_ENTER_WINDOW, [](wxMouseEvent& evt) {
evt.Skip();
});
btn->Bind(wxEVT_LEAVE_WINDOW, [btn](wxMouseEvent& evt) {
btn->Bind(wxEVT_LEAVE_WINDOW, [](wxMouseEvent& evt) {
evt.Skip();
});
+39 -22
View File
@@ -785,6 +785,19 @@ void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& fil
}
}
// Byte offset just past the first count characters of str, or its length if it is shorter.
static size_t utf8_offset(const std::string& str, size_t count)
{
const char* const begin = str.c_str();
const char* const end = begin + str.size();
const char* pos = begin;
for (size_t i = 0; i < count && pos < end; ++i) {
unsigned int codepoint = 0;
pos += ImTextCharFromUtf8(&codepoint, pos, end);
}
return pos - begin;
}
//BBS: GUI refactor: move to right
void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, float right, uint64_t curr_line_id) const
{
@@ -796,23 +809,27 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, f
// read line from file
const size_t start = id == 1 ? 0 : m_lines_ends[id - 2];
const size_t original_len = m_lines_ends[id - 1] - start;
const size_t len = std::min(original_len, (size_t) 55);
// A character is four bytes at most, so 55 of them always fit in 220.
const size_t len = std::min(original_len, (size_t) 55 * 4);
std::string gline(m_file.data() + start, len);
// If original line is longer than 55 characters, truncate and append "..."
if (original_len > 55)
gline = gline.substr(0, 52) + "...";
// If original line is longer than 55 characters, truncate and append "...".
// The cut must land on a character boundary or it leaves half a character behind.
if (len < original_len || utf8_offset(gline, 55) < gline.size())
gline = gline.substr(0, utf8_offset(gline, 52)) + "...";
std::string command, parameters, comment;
// extract comment
std::vector<std::string> tokens;
boost::split(tokens, gline, boost::is_any_of(";"), boost::token_compress_on);
command = tokens.front();
if (tokens.size() > 1)
comment = ";" + tokens.back();
const size_t comment_start = gline.find(';');
if (comment_start == std::string::npos)
command = gline;
else {
command = gline.substr(0, comment_start);
comment = gline.substr(comment_start);
}
// extract gcode command and parameters
if (!command.empty()) {
std::vector<std::string> tokens;
boost::split(tokens, command, boost::is_any_of(" "), boost::token_compress_on);
command = tokens.front();
if (tokens.size() > 1) {
@@ -2613,7 +2630,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessor
return ret;
};
auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this](const ColorRGBA& color, const std::vector<std::pair<std::string, float>>& columns_offsets)
auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this](const ColorRGBA& color, const std::vector<std::pair<std::string, float>>& columns_offsets)
{
// render icon
ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y);
@@ -2648,7 +2665,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessor
}
ImGui::Separator();
};
auto get_used_filament_from_volume = [this, imperial_units, &filament_diameters, &filament_densities](double volume, int extruder_id) {
auto get_used_filament_from_volume = [imperial_units, &filament_diameters, &filament_densities](double volume, int extruder_id) {
double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001;
std::pair<double, double> ret = { koef * volume / (PI * sqr(0.5 * filament_diameters[extruder_id])),
volume * filament_densities[extruder_id] * 0.001 };
@@ -3233,7 +3250,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
//ImVec2(pos_rect.x + ImGui::GetWindowWidth() + ImGui::GetFrameHeight(),pos_rect.y + ImGui::GetFrameHeight() + window_padding * 2.5),
//ImGui::GetColorU32(ImVec4(0,0,0,0.3)));
auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this](
auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this](
EItemType type,
const ColorRGBA& color,
const std::vector<std::pair<std::string, float>>& columns_offsets,
@@ -3368,7 +3385,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
return ret;
};
auto calculate_offsets = [&imgui, max_width, window_padding, this](const std::vector<std::pair<std::string, std::vector<::string>>>& title_columns, float extra_size = 0.0f) {
auto calculate_offsets = [max_width, this](const std::vector<std::pair<std::string, std::vector<::string>>>& title_columns, float extra_size = 0.0f) {
const ImGuiStyle& style = ImGui::GetStyle();
std::vector<float> offsets;
// ORCA increase spacing for more readable format. Using direct number requires much less code change in here. GetTextLineHeight for additional spacing for icon_size
@@ -3856,7 +3873,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
columns_offsets.push_back({ distance_text, offsets[3] });
if (full_layout && !count_text.empty())
columns_offsets.push_back({ count_text, distance_text.empty() ? offsets[3] : offsets[4] });
append_item(EItemType::Rect, color, columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type, visible]() {
append_item(EItemType::Rect, color, columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type]() {
m_viewer.toggle_option_visibility(type);
update_moves_slider();
});
@@ -3913,7 +3930,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
columns_offsets.push_back({used_filaments_length[i], offsets[3]});
columns_offsets.push_back({used_filaments_weight[i], offsets[4]});
append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_extrusion_role_color(role)), columns_offsets,
true, offsets.back(), visible, [this, role, visible]() {
true, offsets.back(), visible, [this, role]() {
m_viewer.toggle_extrusion_role_visibility(role);
update_moves_slider();
});
@@ -3932,7 +3949,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
columns_offsets.push_back({ travel_percent, offsets[2] });
columns_offsets.push_back({ travel_distance, offsets[3] }); // Usage column
columns_offsets.push_back({ travel_moves, offsets[4] }); // Usage column
append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, item, visible]() {
append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, item]() {
m_viewer.toggle_option_visibility(item);
update_moves_slider();
});
@@ -3951,7 +3968,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
// refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
update_moves_slider();
@@ -3968,7 +3985,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
// refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
update_moves_slider();
@@ -3985,7 +4002,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
update_moves_slider();
});
@@ -4001,7 +4018,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
update_moves_slider();
});
@@ -4121,7 +4138,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
}
float checkbox_pos = std::max(predictable_icon_pos, color_print_offsets[_u8L("Display")]); // ORCA prefer predictable_icon_pos when header not reacing end
append_item(EItemType::Rect, libvgcode::convert(tool_colors[extruder_idx]), columns_offsets, false, checkbox_pos/*ORCA*/, true, [this, extruder_idx]() {});
append_item(EItemType::Rect, libvgcode::convert(tool_colors[extruder_idx]), columns_offsets, false, checkbox_pos/*ORCA*/, true, []() {});
}
i++;
}
+42 -27
View File
@@ -2191,7 +2191,7 @@ void GLCanvas3D::render(bool only_init)
// Negative coordinate means out of the window, likely because the window was deactivated.
// In that case the tooltip should be hidden.
if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0. || has_mouse_capture()) { // ORCA continue to capture mouse pos mid drag
if ((m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.) || has_mouse_capture()) { // ORCA continue to capture mouse pos mid drag
if (tooltip.empty())
tooltip = m_layers_editing.get_tooltip(*this);
@@ -2891,23 +2891,37 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
DynamicPrintConfig& proj_cfg = wxGetApp().preset_bundle->project_config;
float x = dynamic_cast<const ConfigOptionFloats*>(proj_cfg.option("wipe_tower_x"))->get_at(plate_id);
float y = dynamic_cast<const ConfigOptionFloats*>(proj_cfg.option("wipe_tower_y"))->get_at(plate_id);
float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("prime_tower_width"))->value;
float a = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_rotation_angle"))->value;
// BBS
float v = dynamic_cast<const ConfigOptionFloat*>(m_config->option("prime_volume"))->value;
Vec3d plate_origin = ppl.get_plate(plate_id)->get_origin();
const Print* print = m_process->fff_print();
const Print* current_print = part_plate->fff_print();
if (!need_wipe_tower && part_plate->get_extruders(true).size() < 2) continue;
if (part_plate->get_objects_on_this_plate().empty()) continue;
float brim_width = print->wipe_tower_data(filaments_count).brim_width;
int nozzle_nums = wxGetApp().preset_bundle->get_printer_extruder_count();
Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(full_config, w, v, nozzle_nums, 0, false, dynamic_cast<const ConfigOptionBool*>(dconfig.option("enable_wrapping_detection"))->value);
// Body and brim from this plate's own estimate: m_process->fff_print() is the
// selected plate's, so an auto brim drew every tower with that plate's brim.
const WipeTowerFootprint footprint = part_plate->estimate_wipe_tower_footprint(full_config);
// The estimate is also the answer to whether this plate prints a tower;
// deciding it here as well only gave the two room to drift.
if (footprint.depth <= 0.) continue;
float brim_width = float(footprint.brim_width);
Vec3d wipe_tower_size(footprint.width, footprint.depth, footprint.height);
// set_default_wipe_tower_pos_for_plate doesn't rerun when painting changes the
// filament count, so redo its clamp here on every reload — unconditionally: a
// paint-triggered reload can arrive before the background process invalidates
// psWipeTower, so gating on it would skip the clamp exactly when it is needed.
{
Vec3d clamped_pos, clamped_size;
part_plate->estimate_wipe_tower_polygon(full_config, plate_id, clamped_pos, clamped_size);
if (std::abs(x - (float) clamped_pos(0)) > EPSILON || std::abs(y - (float) clamped_pos(1)) > EPSILON) {
x = (float) clamped_pos(0);
y = (float) clamped_pos(1);
ConfigOptionFloat wt_x_opt(x), wt_y_opt(y);
dynamic_cast<ConfigOptionFloats*>(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_id, 0);
dynamic_cast<ConfigOptionFloats*>(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_id, 0);
}
}
// The stored position is already clamped onto the bed, by
// set_default_wipe_tower_pos_for_plate and again on every drag.
if (!current_print->is_step_done(psWipeTower) || !current_print->wipe_tower_data().wipe_tower_mesh_data) {
// update for wipe tower position
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(1000 + plate_id, x + plate_origin(0), y + plate_origin(1),
@@ -4168,7 +4182,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// https://github.com/OrcaSlicer/OrcaSlicer/pull/14999#issuecomment-5151344759
// We solve this by correcting the state of the event from the actual mouse state querying with `wxGetMouseState()`
// so it works like on other platforms.
{
// Only fill in state the event does not carry, to preserve wx's synthetic right button for Ctrl+left.
if (!evt.ButtonIsDown(wxMOUSE_BTN_ANY)) {
const auto state = wxGetMouseState();
evt.SetLeftDown(state.LeftIsDown());
evt.SetMiddleDown(state.MiddleIsDown());
@@ -9236,7 +9251,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImVec2 size = ImVec2(button_width, button_height);
ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y);
// ORCA show additional information depends on state
auto draw_info_btn = [end_pos, f_scale, margin, window_bg](std::string str, ImVec4 bg_color, ImVec4 fg_color){
auto draw_info_btn = [end_pos, f_scale, margin](std::string str, ImVec4 bg_color, ImVec4 fg_color){
GImGui->FontSize = 15.0f * f_scale;
ImVec2 txt_slice_sz = ImGui::CalcTextSize(str.c_str());
ImVec2 btn_pad = ImVec2(8.f, 1.f) * f_scale;
@@ -9492,7 +9507,7 @@ void GLCanvas3D::_render_canvas_toolbar()
Plater* p = wxGetApp().plater();
AppConfig* cfg = wxGetApp().app_config;
auto create_menu_item = [this, sc](
auto create_menu_item = [sc](
const std::string& name,
bool enable,
bool condition,
@@ -9509,7 +9524,7 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("3D Navigator")),
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
wxGetApp().show_3d_navigator(),
[this]{
[]{
wxGetApp().toggle_show_3d_navigator();
ImGui::CloseCurrentPopup(); // Close popup to show changes on UI
}
@@ -9518,7 +9533,7 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("Zoom button")),
true, // work on all
wxGetApp().show_canvas_zoom_button(),
[this]{
[]{
wxGetApp().toggle_canvas_zoom_button();
ImGui::CloseCurrentPopup(); // Close popup to show changes on UI
}
@@ -9529,13 +9544,13 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("Overhangs")),
m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare
p->is_view3D_overhang_shown(),
[this, p]{p->show_view3D_overhang(!p->is_view3D_overhang_shown());}
[p]{p->show_view3D_overhang(!p->is_view3D_overhang_shown());}
);
create_menu_item( _utf8(L("Outline")),
m_canvas_type != ECanvasType::CanvasPreview, // not work on preview
wxGetApp().show_outline(),
[this]{wxGetApp().toggle_show_outline();}
[]{wxGetApp().toggle_show_outline();}
);
create_menu_item( _utf8(L("Wireframe")),
@@ -9547,7 +9562,7 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("Realistic View")),
m_canvas_type != ECanvasType::CanvasPreview, // not work on preview
cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE),
[this, &cfg]{
[&cfg]{
cfg->set_bool(SETTING_OPENGL_REALISTIC_MODE, !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE));
cfg->save();
}
@@ -9558,7 +9573,7 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("Perspective")),
true, // work on all
cfg->get_bool("use_perspective_camera"),
[this, &cfg]{
[&cfg]{
cfg->set_bool("use_perspective_camera", !(cfg->get_bool("use_perspective_camera")));
wxGetApp().update_ui_from_settings();
}
@@ -9575,7 +9590,7 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("Gridlines")),
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
wxGetApp().show_plate_gridlines(),
[this]{wxGetApp().toggle_show_plate_gridlines();}
[]{wxGetApp().toggle_show_plate_gridlines();}
);
ImGui::Separator();
@@ -9583,7 +9598,7 @@ void GLCanvas3D::_render_canvas_toolbar()
create_menu_item( _utf8(L("Labels")),
m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare
p->are_view3D_labels_shown(),
[this, p]{p->show_view3D_labels(!p->are_view3D_labels_shown());}
[p]{p->show_view3D_labels(!p->are_view3D_labels_shown());}
);
ImGui::PopItemFlag();
@@ -9765,18 +9780,18 @@ void GLCanvas3D::_render_paint_toolbar() const
ImVec2 number_label_size = ImGui::CalcTextSize(std::to_string(i + 1).c_str());
ImGui::SetCursorPosY(cursor_y + text_offset_y);
ImGui::SetCursorPosX(spacing + i * (spacing + button_size.x) + (button_size.x - number_label_size.x) / 2);
ImGui::TextColored(text_color, std::to_string(i + 1).c_str());
ImGui::TextColored(text_color, "%s", std::to_string(i + 1).c_str());
imgui.pop_bold_font();
ImVec2 filament_first_line_label_size = ImGui::CalcTextSize(filament_text_first_line[i].c_str());
ImGui::SetCursorPosY(cursor_y + text_offset_y + number_label_size.y);
ImGui::SetCursorPosX(spacing + i * (spacing + button_size.x) + (button_size.x - filament_first_line_label_size.x) / 2);
ImGui::TextColored(text_color, filament_text_first_line[i].c_str());
ImGui::TextColored(text_color, "%s", filament_text_first_line[i].c_str());
ImVec2 filament_second_line_label_size = ImGui::CalcTextSize(filament_text_second_line[i].c_str());
ImGui::SetCursorPosY(cursor_y + text_offset_y + number_label_size.y + filament_first_line_label_size.y);
ImGui::SetCursorPosX(spacing + i * (spacing + button_size.x) + (button_size.x - filament_second_line_label_size.x) / 2);
ImGui::TextColored(text_color, filament_text_second_line[i].c_str());
ImGui::TextColored(text_color, "%s", filament_text_second_line[i].c_str());
}
if (ImGui::GetWindowWidth() == constraint_window_width) {
@@ -10003,9 +10018,9 @@ void GLCanvas3D::_render_assemble_info() const
double size1 = m_selection.get_bounding_box().size()(1);
double size2 = m_selection.get_bounding_box().size()(2);
if (!m_selection.is_empty()) {
ImGui::Text(_L("Volume:").ToUTF8()); ImGui::SameLine(caption_max);
ImGui::Text("%s", _L("Volume:").ToUTF8().data()); ImGui::SameLine(caption_max);
ImGui::Text("%.2f", size0 * size1 * size2);
ImGui::Text(_L("Size:").ToUTF8()); ImGui::SameLine(caption_max);
ImGui::Text("%s", _L("Size:").ToUTF8().data()); ImGui::SameLine(caption_max);
ImGui::Text("%.2f x %.2f x %.2f", size0, size1, size2);
}
imgui->end();
+9 -7
View File
@@ -9,8 +9,10 @@
#include "slic3r/GUI/TaskManager.hpp"
#include "format.hpp"
#include "libslic3r_version.h"
#include "BuildCommit.hpp"
#include "Downloader.hpp"
#include <boost/chrono/duration.hpp>
#include <boost/locale/encoding_utf.hpp>
#include <boost/log/detail/native_typeof.hpp>
#include <libslic3r/Config.hpp>
#include <mutex>
@@ -2580,7 +2582,7 @@ void GUI_App::init_app_config()
set_log_path_and_level(log_filename, 3);
#endif
BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1% build %2%") % SoftFever_VERSION % GIT_COMMIT_HASH;
BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1% build %2%") % SoftFever_VERSION % build_commit_label;
//BBS: remove GCodeViewer as seperate APP logic
if (!app_config)
@@ -2641,7 +2643,7 @@ std::string GUI_App::get_bbl_client_version()
void GUI_App::on_start_subscribe_again(std::string dev_id)
{
auto start_subscribe_timer = new wxTimer(this, wxID_ANY);
Bind(wxEVT_TIMER, [this, start_subscribe_timer, dev_id](auto& e) {
Bind(wxEVT_TIMER, [start_subscribe_timer, dev_id](auto& e) {
start_subscribe_timer->Stop();
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) return;
@@ -3231,7 +3233,7 @@ bool GUI_App::on_init_inner()
}
});
Bind(EVT_SHOW_NO_NEW_VERSION, [this](const wxCommandEvent& evt) {
Bind(EVT_SHOW_NO_NEW_VERSION, [](const wxCommandEvent& evt) {
wxString msg = _L("This is the newest version.");
InfoDialog dlg(nullptr, _L("Info"), msg);
dlg.ShowModal();
@@ -5256,7 +5258,7 @@ std::string GUI_App::handle_web_request(std::string cmd)
}
}
else if (command_str.compare("begin_network_plugin_download") == 0) {
CallAfter([this] { wxGetApp().ShowDownNetPluginDlg(); });
CallAfter([] { wxGetApp().ShowDownNetPluginDlg(); });
}
else if (command_str.compare("get_web_shortcut") == 0) {
if (root.get_child_optional("key_event") != boost::none) {
@@ -6806,7 +6808,7 @@ bool GUI_App::check_preset_parent_available(const std::pair<std::string, std::ma
void GUI_App::add_pending_vendor_preset(const std::pair<std::string, std::map<std::string, std::string>>& preset_data)
{
Preset::Type type;
Preset::Type type = Preset::Type::TYPE_INVALID;
if (preset_data.second.at(BBL_JSON_KEY_TYPE) == PRESET_IOT_PRINT_TYPE)
type = Preset::Type::TYPE_PRINT;
else if (preset_data.second.at(BBL_JSON_KEY_TYPE) == PRESET_IOT_PRINTER_TYPE)
@@ -8297,7 +8299,7 @@ bool GUI_App::show_modal_ip_address_enter_dialog(bool input_sn, wxString title)
dlg.set_machine_obj(obj);
if (!title.empty()) dlg.update_title(title);
dlg.Bind(EVT_ENTER_IP_ADDRESS, [this, obj](wxCommandEvent& e) {
dlg.Bind(EVT_ENTER_IP_ADDRESS, [obj](wxCommandEvent& e) {
auto selection_data_arr = wxSplit(e.GetString().ToStdString(), '|');
if (selection_data_arr.size() == 2) {
@@ -8777,7 +8779,7 @@ bool GUI_App::check_and_keep_current_preset_changes(const wxString& caption, con
if (!no_need_change && dlg.ShowModal() == wxID_CANCEL)
return false;
auto reset_modifications = [this, is_called_from_configwizard]() {
auto reset_modifications = [this]() {
//if (is_called_from_configwizard)
// return; // no need to discared changes. It will be done fromConfigWizard closing
+1 -1
View File
@@ -217,7 +217,7 @@ void AuxiliaryList::on_context_menu(wxDataViewEvent& evt)
}
else {
append_menu_item(menu, wxID_ANY, _L("Open"), wxEmptyString,
[this, node](wxCommandEvent&)
[node](wxCommandEvent&)
{
wxLaunchDefaultApplication(node->path, 0);
});
+7 -7
View File
@@ -1414,7 +1414,7 @@ void MenuFactory::create_default_menu()
append_menu_check_item(&m_default_menu, wxID_ANY, _L("Show Labels"), "",
[](wxCommandEvent&) { plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, &m_default_menu,
[]() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent);
[]() { return plater()->is_view3D_shown(); }, []() { return plater()->are_view3D_labels_shown(); }, m_parent);
}
void MenuFactory::create_common_object_menu(wxMenu* menu)
@@ -2090,7 +2090,7 @@ void MenuFactory::append_menu_item_clone(wxMenu* menu)
static const wxString ctrl = _L("Ctrl+");
#endif
append_menu_item(menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "",
[this](wxCommandEvent&) {
[](wxCommandEvent&) {
plater()->clone_selection();
}, "", nullptr,
[]() {
@@ -2115,7 +2115,7 @@ void MenuFactory::append_menu_item_smooth_mesh(wxMenu *menu)
void MenuFactory::append_menu_item_center(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Center") , "",
[this](wxCommandEvent&) {
[](wxCommandEvent&) {
plater()->center_selection();
}, "", nullptr,
[]() {
@@ -2134,7 +2134,7 @@ void MenuFactory::append_menu_item_center(wxMenu* menu)
void MenuFactory::append_menu_item_drop(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Drop") , "",
[this](wxCommandEvent&) {
[](wxCommandEvent&) {
plater()->drop_selection();
}, "", nullptr,
[]() {
@@ -2309,7 +2309,7 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
}
}
wxMenuItem* menu_item_set_printable = append_menu_check_item(menu, wxID_ANY, _L("Printable") + "\t" + "V", "", [this, all_printable](wxCommandEvent&) {
wxMenuItem* menu_item_set_printable = append_menu_check_item(menu, wxID_ANY, _L("Printable") + "\t" + "V", "", [all_printable](wxCommandEvent&) {
Selection& selection = plater()->canvas3D()->get_selection();
selection.set_printable(!all_printable);
}, menu);
@@ -2329,7 +2329,7 @@ void MenuFactory::append_menu_item_set_auto_drop(wxMenu* menu)
wxString menu_tooltip = _L("Automatically snaps the selected object to the build plate.");
wxMenuItem* menu_item_set_auto_drop = append_menu_check_item(
menu, wxID_ANY, menu_text, menu_tooltip,
[this, current_auto_drop](wxCommandEvent&) {
[current_auto_drop](wxCommandEvent&) {
Selection& selection = plater()->canvas3D()->get_selection();
selection.set_auto_drop(!current_auto_drop);
},
@@ -2384,7 +2384,7 @@ void MenuFactory::append_menu_item_plate_name(wxMenu *menu)
auto item = append_menu_item(
menu, wxID_ANY, name, "",
[plate](wxCommandEvent &e) {
[](wxCommandEvent &e) {
int hover_idx =plater()->canvas3D()->GetHoverId();
if (hover_idx == -1) {
int plate_idx=plater()->GetPlateIndexByRightMenuInLeftUI();
+2 -2
View File
@@ -48,7 +48,7 @@ void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_ed
* And as a result we couldn't edit this control.
* */
#ifdef __WXOSX__
wxTheApp->CallAfter([editor]() {
wxTheApp->CallAfter([]() {
#endif
//editor->SetFocus();
//editor->SelectAll();
@@ -223,7 +223,7 @@ void ObjectLayers::update_layers_list()
// only call sizer->Clear(true) via CallAfter, otherwise crash happens in Linux when press enter in Height Range
// because an element cannot be destroyed while there are pending events for this element.(https://github.com/wxWidgets/Phoenix/issues/1854)
wxGetApp().CallAfter([this, type, objects_ctrl, range]() {
wxGetApp().CallAfter([this, type, range]() {
m_og->ctrl_parent()->Freeze();
// Delete all controls from options group
+4 -4
View File
@@ -2324,7 +2324,7 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
bool split_compound = wxGetApp().app_config->get_bool("is_split_compound");
model = Model::read_from_step(
input_file, LoadStrategy::LoadModel, nullptr, nullptr,
[this, &is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value,
[&is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value,
double& angle_value, bool& is_split) -> int {
if (wxGetApp().app_config->get_bool("enable_step_mesh_setting")) {
StepMeshDialog mesh_dlg(nullptr, file, linear, angle);
@@ -3317,7 +3317,7 @@ void ObjectList::boolean()
}
}
TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1, [this](const std::string& msg) {return wxGetApp().notification_manager()->push_plater_error_notification(msg); });
TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1, [](const std::string& msg) {return wxGetApp().notification_manager()->push_plater_error_notification(msg); });
// add mesh to model as a new object, keep the original object's name and config
Model* model = object->get_model();
@@ -6267,7 +6267,7 @@ void GUI::ObjectList::smooth_mesh()
get_selection_indexes(obj_idxs, vol_idxs);
auto object_idx = obj_idxs.front();
ModelObject *obj{nullptr};
auto show_warning_dlg = [this](int cur_face_count,std::string name,bool is_part) {
auto show_warning_dlg = [](int cur_face_count,std::string name,bool is_part) {
int limit_face_count = 1000000;
if (cur_face_count > limit_face_count) {
auto name_str = wxString::FromUTF8(name);
@@ -6280,7 +6280,7 @@ void GUI::ObjectList::smooth_mesh()
}
return false;
};
auto show_smooth_mesh_error_dlg = [this](std::string name) {
auto show_smooth_mesh_error_dlg = [](std::string name) {
auto name_str = wxString::FromUTF8(name);
auto content = wxString::Format(_L("\"%s\" part's mesh contains errors. Please repair it first."), name_str);
WarningDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe), content, wxEmptyString, wxOK);
+2 -2
View File
@@ -3520,13 +3520,13 @@ void GridCellTextEditor::BeginEdit(int row, int col, wxGrid *grid)
Text()->GetTextCtrl()->SetInsertionPointEnd();
m_control->Bind(wxEVT_TEXT_ENTER, [this, row, col, grid](wxCommandEvent &e) {
m_control->Bind(wxEVT_TEXT_ENTER, [grid](wxCommandEvent &e) {
grid->HideCellEditControl();
grid->SaveEditControlValue();
e.Skip();
});
m_control->Bind(wxEVT_CHAR_HOOK, [this, row, col, grid](wxKeyEvent &e) {
m_control->Bind(wxEVT_CHAR_HOOK, [grid](wxKeyEvent &e) {
if (e.GetKeyCode() == WXK_ESCAPE) {
grid->HideCellEditControl();
grid->SaveEditControlValue();
-7
View File
@@ -591,16 +591,11 @@ private:
wxColour m_hover_colour;
wxBoxSizer* m_top_sizer{nullptr};
wxBoxSizer* m_page_sizer{nullptr};
wxBoxSizer* m_page_top_sizer{nullptr};
wxTextCtrl* m_search_line{ nullptr };
ObjectGrid* m_object_grid{nullptr};
ObjectGridTable* m_object_grid_table{nullptr};
wxStaticText* m_page_text{nullptr};
ScalableButton* m_global_reset{nullptr};
wxScrolledWindow* m_side_window{nullptr};
ObjectTableSettings* m_object_settings{ nullptr };
Model* m_model{nullptr};
ModelConfig* m_config {nullptr};
Plater* m_plater{nullptr};
int m_cur_row { -1 };
@@ -625,8 +620,6 @@ class ObjectTableDialog : public GUI::DPIDialog
const int POPUP_HEIGHT = FromDIP(1024);
//wxPanel* m_panel{ nullptr };
wxBoxSizer* m_top_sizer{ nullptr };
wxStaticText* m_static_title{ nullptr };
//wxTimer* m_refresh_timer;
ObjectTablePanel* m_obj_panel{ nullptr };
Model* m_model{ nullptr };
+10 -7
View File
@@ -184,7 +184,7 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_
btn->Bind(EVT_LOCK_ENABLE, [this, btn](auto &e) { btn->SetBitmap(m_bmp_reset_focus.bmp()); });
#endif
btn->Bind(wxEVT_BUTTON, [btn, opt_key, this, is_object, object, config, group_category](wxEvent &event) {
btn->Bind(wxEVT_BUTTON, [opt_key, this, is_object, object, config, group_category](wxEvent &event) {
//wxGetApp().plater()->take_snapshot(from_u8((boost::format(_utf8(L("Reset Option %s"))) % opt_key).str()));
config->erase(opt_key);
//btn->Hide();
@@ -204,10 +204,13 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_
this->m_parent->Thaw();
#ifdef __WXOSX_MAC__
if (!btn->IsEnabled()) {
btn->SetBitmap(m_bmp_reset_disable.bmp());
} else {
btn->SetBitmap(m_bmp_reset_focus.bmp());
// The handler is bound on the button, so the event source is that button.
if (auto *btn = dynamic_cast<ScalableButton *>(event.GetEventObject())) {
if (!btn->IsEnabled()) {
btn->SetBitmap(m_bmp_reset_disable.bmp());
} else {
btn->SetBitmap(m_bmp_reset_focus.bmp());
}
}
#endif
});
@@ -284,13 +287,13 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_
m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
m_og_settings.push_back(optgroup);
auto toggle_field = [this, optgroup](const t_config_option_key & opt_key, bool toggle, int opt_index)
auto toggle_field = [optgroup](const t_config_option_key & opt_key, bool toggle, int opt_index)
{
Field* field = optgroup->get_fieldc(opt_key, opt_index);;
if (field)
field->toggle(toggle);
};
auto toggle_line = [this, optgroup](const t_config_option_key &opt_key, bool toggle, int opt_index)
auto toggle_line = [optgroup](const t_config_option_key &opt_key, bool toggle, int opt_index)
{
Line* line = optgroup->get_line(opt_key);
if (line) line->toggle_visible = toggle;
+2 -2
View File
@@ -102,7 +102,7 @@ CopyFileResult copy_file_gui(const std::string &from, const std::string &to, std
result = ReadFile(handlesrc, buff, size, &dwRead, NULL);
if (!result) {
DWORD errCode = GetLastError();
error_message = "Error: " + errCode;
error_message = "Error: " + std::to_string(errCode);
ret = FAIL_COPY_FILE;
goto __finished;
}
@@ -110,7 +110,7 @@ CopyFileResult copy_file_gui(const std::string &from, const std::string &to, std
result = WriteFile(handledst,buff,size,&dwWrite,NULL);
if (!result) {
DWORD errCode = GetLastError();
error_message = "Error: " + errCode;
error_message = "Error: " + std::to_string(errCode);
ret = FAIL_COPY_FILE;
goto __finished;
}
+1 -1
View File
@@ -342,7 +342,7 @@ bool GLGizmoBrimEars::on_mouse(const wxMouseEvent& mouse_event)
// concludes that the event was not intended for it, it should return false.
bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down)
{
if (action != SLAGizmoEventType::MouseWheelDown || action != SLAGizmoEventType::MouseWheelUp || action != SLAGizmoEventType::Moving) {
if (action != SLAGizmoEventType::MouseWheelDown && action != SLAGizmoEventType::MouseWheelUp && action != SLAGizmoEventType::Moving) {
apply_radius_change();
}
+1 -1
View File
@@ -3596,7 +3596,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
// model_name failing reason
std::vector<std::pair<std::string, std::string>> failed_models;
auto plater = wxGetApp().plater();
auto fix_and_update_progress = [this, plater, keep_painting](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg,
auto fix_and_update_progress = [keep_painting](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg,
std::vector<std::string> &succes_models, std::vector<std::pair<std::string, std::string>> &failed_models) {
wxString msg = _L("Repairing model object");
msg += ": " + from_u8(model_name) + "\n";
-1
View File
@@ -94,7 +94,6 @@ class GLGizmoCut3D : public GLGizmoBase
GLModel m_reference_radius;
GLModel m_angle_arc;
Vec3d m_old_center;
Vec3d m_cut_normal;
struct InvalidConnectorsStatistics
+1 -1
View File
@@ -122,7 +122,7 @@ bool GLGizmoFdmSupports::on_init()
{ctrl + _L("Mouse wheel"), _L("Gap area")}
};
memset(&m_print_instance, 0, sizeof(m_print_instance));
m_print_instance = PrintInstance();
return true;
}
+1 -1
View File
@@ -223,7 +223,7 @@ void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_l
const int select_btn_length = 2 * ImGui::GetStyle().FramePadding.x + std::max(ImGui::CalcTextSize(("1 " + _u8L("selected")).c_str()).x, ImGui::CalcTextSize(_u8L("Select").c_str()).x);
auto selectable = [this](const std::string& label, bool selected, const ImVec2& size_arg) {
auto selectable = [](const std::string& label, bool selected, const ImVec2& size_arg) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 });
ImGuiWindow* window = ImGui::GetCurrentWindow();
+1 -1
View File
@@ -1456,7 +1456,7 @@ void TriangleSelectorPatch::update_triangles_per_patch()
return touching_triangles;
};
auto calc_fragment_area = [this](const TrianglePatch& patch, float max_limit_area, int stride) {
auto calc_fragment_area = [](const TrianglePatch& patch, float max_limit_area, int stride) {
double total_area = 0.f;
const std::vector<int>& ti = patch.triangle_indices;
/*for (int i = 0; i < ti.size() / 3; i++) {
+2 -2
View File
@@ -343,12 +343,12 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(10,20));
if (is_worker_running) { // apply or preview
// draw progress bar
std::string progress_text = GUI::format("%1%", std::to_string(progress)) + "%%";
std::string progress_text = GUI::format("%1%", std::to_string(progress)) + "%";
ImVec2 progress_size(bottom_left_width - space_size, 0.0f);
ImGui::BBLProgressBar2(progress / 100., progress_size);
ImGui::SameLine();
ImGui::AlignTextToFramePadding();
ImGui::TextColored(ImVec4(0.42f, 0.42f, 0.42f, 1.00f), progress_text.c_str());
ImGui::TextColored(ImVec4(0.42f, 0.42f, 0.42f, 1.00f), "%s", progress_text.c_str());
ImGui::SameLine(bottom_left_width + slider_width + m_imgui->scaled(1.0f));
} else {
ImGui::Dummy(ImVec2(bottom_left_width - space_size, -1));
+1 -1
View File
@@ -1003,7 +1003,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
// number waits briefly for a second one.
const int digit = keyCode - '0';
const int shortcut_max = int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT);
auto can_start_two_digit = [shortcut_max](int d) { return d > 0 && d * 10 <= shortcut_max; };
auto can_start_two_digit = [](int d) { return d > 0 && d * 10 <= shortcut_max; };
auto select = [mmu_seg](int number) { return number > 0 && mmu_seg->on_number_key_down(number); };
if (m_timer_set_color.IsRunning() && m_pending_color_shortcut_tens > 0) {
@@ -239,7 +239,7 @@ void GizmoObjectManipulation::update_if_dirty()
};
for (int i = 0; i < 3; ++ i) {
auto update = [this, i](Vec3d &cached, Vec3d &cached_rounded, const Vec3d &new_value) {
auto update = [i](Vec3d &cached, Vec3d &cached_rounded, const Vec3d &new_value) {
//wxString new_text = double_to_string(new_value(i), 2);
double new_rounded = round(new_value(i)*100)/100.0;
//new_text.ToDouble(&new_rounded);
+45 -186
View File
@@ -1,4 +1,5 @@
#include "GradientCurveEditor.hpp"
#include "FilamentBitmapUtils.hpp"
#include "GUI_App.hpp"
#include "GuiColor.hpp"
#include "I18N.hpp"
@@ -19,23 +20,13 @@ namespace GUI {
wxDEFINE_EVENT(wxEVT_GRADIENT_CURVE_CHANGED, wxCommandEvent);
namespace {
// Layout ratios of the plot rect within the widget, taken from a 214 x 180 px reference drawing.
// Plot rect occupies the upper-left region; right + bottom margins host axis arrows / labels.
constexpr double kPlotLeftRatio = 0.0316;
constexpr double kPlotRightRatio = 0.6766;
constexpr double kPlotTopRatio = 0.1529;
constexpr double kPlotBottomRatio = 0.8474;
constexpr int kGridDivisions = 9; // 10 grid lines including the outer borders.
// Hit / stroke (DIP).
// Hit / stroke (DIP). The plot-rect ratios, grid divisions, axis/arrow geometry and the
// near-background outline threshold now live in FilamentBitmapUtils so the read-only Publish
// preview and this editor stay pixel-identical.
constexpr int kHitRadius = 6;
constexpr int kCurveHitRadius = 5;
constexpr int kPointRadius = 4; // anchor outer radius (DIP)
constexpr int kStrokeUnselected = 2;
constexpr int kStrokeSelected = 4;
constexpr int kStrokeAxis = 2; // axis line width (px, no DPI scaling - matches kGridColor pen and 2DBed convention)
constexpr int kAxisArrowHalf = 5; // half-base of the axis arrow triangle (DIP)
constexpr int kAxisArrowLen = 10; // length of the axis arrow triangle (DIP)
// Light-mode design tokens. Resolved through StateColor::darkModeColorFor()
// at paint time so the editor follows the app theme (#EEEEEE -> #4C4C55, #6B6B6B ->
@@ -46,12 +37,6 @@ const wxColour kAxisColor (107, 107, 107); // #6B6B6B grey 700
const wxColour kLabelMuted (107, 107, 107); // #6B6B6B grey 700
const wxColour kLabelStrong ( 38, 46, 48); // #262E30 grey 900
const wxColour kOutlineColor(172, 172, 172); // #ACACAC dimmed elements
// LAB (DeltaE76) threshold for "curve color is too close to the background": below it the curve
// gets a subtle outline so it does not visually vanish, otherwise it is drawn plain. Looser than
// the 5.0 of FlushPredict::is_similar_color, so a pastel pink on white still gets an outline.
constexpr float kBgSimilarThreshold = 15.0f;
constexpr int kOutlineExtraDip = 2;
} // namespace
GradientCurveEditor::GradientCurveEditor(wxWindow* parent,
@@ -177,15 +162,8 @@ void GradientCurveEditor::emit_changed()
wxRect GradientCurveEditor::plot_rect() const
{
const wxSize sz = GetClientSize();
const int x = static_cast<int>(std::lround(sz.x * kPlotLeftRatio));
const int y = static_cast<int>(std::lround(sz.y * kPlotTopRatio));
const int x2 = static_cast<int>(std::lround(sz.x * kPlotRightRatio));
const int y2 = static_cast<int>(std::lround(sz.y * kPlotBottomRatio));
// Force square 1:1 so X/Y axes share the same scale and grid cells stay square. Anchor at
// the top-left so the "100%" labels on the bottom/right still align with the plot edges.
const int side = std::max(1, std::min(x2 - x, y2 - y));
return wxRect(x, y, side, side);
// Square 1:1 plot, shared with the Publish dialog's read-only preview.
return mixed_gradient_plot_rect(GetClientSize());
}
wxPoint2DDouble GradientCurveEditor::data_to_px_f(double x, double y) const
@@ -330,171 +308,52 @@ void GradientCurveEditor::on_paint(wxPaintEvent& /*evt*/)
raw_dc.SetBackground(wxBrush(bg));
raw_dc.Clear();
// Render through wxGCDC so curves, arrows and anchor circles get anti-aliased; the buffered
// DC is the actual back buffer that gets blitted to the window.
wxGCDC dc(raw_dc);
// The curve and its anchors are drawn straight on the graphics context so their
// coordinates stay sub-pixel accurate (see data_to_px_f).
wxGraphicsContext* gc = dc.GetGraphicsContext();
const wxRect rc = plot_rect();
if (rc.width <= 0 || rc.height <= 0)
return;
// 10x10 light grid (10 lines including outer borders, 9 equal divisions).
dc.SetPen(wxPen(grid_color, 1));
for (int i = 0; i <= kGridDivisions; ++i) {
const int x = rc.x + rc.width * i / kGridDivisions;
const int y = rc.y + rc.height * i / kGridDivisions;
dc.DrawLine(x, rc.y, x, rc.y + rc.height);
dc.DrawLine(rc.x, y, rc.x + rc.width, y);
}
// Set the label font first so text width measurements drive arrow / label placement.
wxFont label_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
label_font.SetPointSize(std::max(7, label_font.GetPointSize() - 1));
dc.SetFont(label_font);
const wxString axis_y_title = _L("Material Ratio");
const wxString axis_x_title = _L("Model Height");
const wxString pct_text = wxT("100%");
const wxSize x_title_sz = dc.GetTextExtent(axis_x_title);
const wxSize y_title_sz = dc.GetTextExtent(axis_y_title);
wxFont strong_font = label_font;
strong_font.SetWeight(wxFONTWEIGHT_SEMIBOLD);
dc.SetFont(strong_font);
const wxSize pct_text_sz = dc.GetTextExtent(pct_text);
dc.SetFont(label_font);
// Axes (grey 700) with filled triangle arrows. Y-axis extends above the plot top to the
// canvas top edge; X-axis extends past the plot right toward the canvas right edge.
const int arrow_half = FromDIP(kAxisArrowHalf);
const int arrow_len = FromDIP(kAxisArrowLen);
const wxSize sz = GetClientSize();
dc.SetPen(wxPen(axis_color, kStrokeAxis));
dc.SetBrush(wxBrush(axis_color));
// Y-axis: vertical line at plot_left, from arrow tip near canvas top down to plot bottom.
const int y_axis_x = rc.x;
const int y_title_pct_gap = FromDIP(1);
const int y_title_bottom_pad = FromDIP(2);
const int y_title_y = std::max(0, rc.y - y_title_sz.y - y_title_pct_gap - pct_text_sz.y - y_title_bottom_pad);
const int y_arrow_tip_y = y_title_y;
const int y_arrow_ty = y_arrow_tip_y + arrow_len;
dc.DrawLine(y_axis_x, y_arrow_ty, y_axis_x, rc.y + rc.height);
{
wxPoint tri[3] = {
wxPoint(y_axis_x, y_arrow_tip_y),
wxPoint(y_axis_x - arrow_half, y_arrow_ty),
wxPoint(y_axis_x + arrow_half, y_arrow_ty),
// Render the plot (grid, axes, labels, curves, anchors) through the shared painter so the
// interactive editor and the Publish dialog's read-only preview stay pixel-identical. The
// curves are handed over as sub-pixel polylines and anti-alias inside the helper.
std::vector<MixedGradientCurve> curves;
std::vector<wxPoint2DDouble> anchors;
if (m_points.size() >= 2) {
auto color_for_curve = [&](int curve_idx) -> wxColour {
wxColour c = (curve_idx == 0) ? m_color_low : m_color_high;
// Transparent filaments (alpha == 0, e.g. #FFFFFF00) would be invisible.
if (c.Alpha() == 0)
c.Set(c.Red(), c.Green(), c.Blue(), 150);
return c;
};
dc.DrawPolygon(3, tri);
}
// X-axis arrow tip: stays just past the plot ideally, but is clamped so the trailing
// "Material Ratio" label still fits inside the canvas without overlapping the arrow.
const int x_axis_y = rc.y + rc.height;
const int x_label_gap = FromDIP(4);
const int x_edge_pad = FromDIP(6);
const int x_arrow_ideal = rc.x + rc.width + FromDIP(10);
const int x_arrow_max = sz.x - x_title_sz.x - x_label_gap - x_edge_pad - arrow_len;
const int x_arrow_tx = std::max(rc.x + rc.width + arrow_len,
std::min(x_arrow_ideal, x_arrow_max));
const int x_arrow_tip_x = x_arrow_tx + arrow_len;
const int x_title_x = x_arrow_tip_x + x_label_gap;
dc.DrawLine(rc.x, x_axis_y, x_arrow_tx, x_axis_y);
{
wxPoint tri[3] = {
wxPoint(x_arrow_tip_x, x_axis_y),
wxPoint(x_arrow_tx, x_axis_y - arrow_half),
wxPoint(x_arrow_tx, x_axis_y + arrow_half),
auto build_polyline = [&](int curve_idx) -> std::vector<wxPoint2DDouble> {
const int samples = std::max(128, plot_rect().width * 2);
std::vector<wxPoint2DDouble> poly;
poly.reserve(samples + 1);
for (int s = 0; s <= samples; ++s) {
const double x = double(s) / samples;
const double y0 = sample_curve_y(x);
const double vy = to_visual_y(curve_idx, y0);
poly.push_back(data_to_px_f(x, vy));
}
return poly;
};
dc.DrawPolygon(3, tri);
}
// Labels.
// "Model Height" and "100%" share the same left x; the gap is larger than the
// axis-arrow half-base so the text never visually touches the Y-axis arrow.
const int label_left_x = y_axis_x + FromDIP(10);
dc.SetTextForeground(label_muted);
dc.DrawText(axis_y_title, label_left_x, y_title_y);
dc.SetFont(strong_font);
dc.SetTextForeground(label_strong);
dc.DrawText(pct_text, label_left_x, y_title_y + y_title_sz.y + y_title_pct_gap);
// Bottom-right "100%" sits under the right end of the plot; "Material Ratio" follows the
// X-axis arrow tip (placement was already clamped above to leave room).
dc.DrawText(pct_text, rc.x + rc.width - pct_text_sz.x, x_axis_y);
dc.SetFont(label_font);
dc.SetTextForeground(label_muted);
dc.DrawText(axis_x_title, x_title_x, x_axis_y - x_title_sz.y / 2);
if (m_points.size() < 2 || !gc)
return;
auto color_for_curve = [&](int curve_idx) -> wxColour {
wxColour c = (curve_idx == 0) ? m_color_low : m_color_high;
// Transparent filaments (alpha == 0, e.g. #FFFFFF00) would be invisible.
// Lift alpha so the curve stays visible while still hinting at transparency.
if (c.Alpha() == 0)
c.Set(c.Red(), c.Green(), c.Blue(), 150);
return c;
};
auto build_polyline = [&](int curve_idx) -> std::vector<wxPoint2DDouble> {
const int samples = std::max(128, rc.width * 2);
std::vector<wxPoint2DDouble> poly;
poly.reserve(samples + 1);
for (int s = 0; s <= samples; ++s) {
const double x = double(s) / samples;
const double y0 = sample_curve_y(x);
const double vy = to_visual_y(curve_idx, y0);
poly.push_back(data_to_px_f(x, vy));
// Draw unselected first so the selected curve sits on top.
const int other = 1 - m_selected_curve;
for (const int idx : {other, m_selected_curve}) {
std::vector<wxPoint2DDouble> pts = build_polyline(idx);
if (pts.empty())
continue;
curves.push_back({std::move(pts), color_for_curve(idx), idx == m_selected_curve ? kStrokeSelected : kStrokeUnselected});
}
return poly;
};
// Only the geometry goes through the graphics context: dc.DrawLines() takes integer wxPoint
// and would quantize the curve back to whole pixels. The pen is still set on the dc, which
// forwards it here while keeping its own cached state in sync for later dc drawing.
auto draw_polyline = [&](const std::vector<wxPoint2DDouble>& poly, const wxColour& col, int stroke_dip) {
dc.SetPen(wxPen(col, FromDIP(stroke_dip)));
gc->StrokeLines(poly.size(), poly.data());
};
// Outline only when the curve color is perceptually close to the background; otherwise
// the plain filament color reads fine and the extra stroke would look heavy.
auto needs_outline = [&](const wxColour& c) {
return calc_color_distance(c, bg) < kBgSimilarThreshold;
};
auto draw_one = [&](int curve_idx, int stroke_dip) {
const auto poly = build_polyline(curve_idx);
const wxColour col = color_for_curve(curve_idx);
if (needs_outline(col))
draw_polyline(poly, outline_color, stroke_dip + kOutlineExtraDip);
draw_polyline(poly, col, stroke_dip);
};
// Draw unselected first so the selected curve sits on top.
const int other = 1 - m_selected_curve;
draw_one(other, kStrokeUnselected);
draw_one(m_selected_curve, kStrokeSelected);
// Control points (selected curve only): hollow circle with axis-color border, theme-aware fill.
// Drawn on the graphics context with a sub-pixel center so the ring stays centered on the
// curve instead of drifting up to half a pixel off it; pen and brush go through the dc for
// the same reason as in draw_polyline above.
const double r = FromDIP(kPointRadius);
dc.SetPen(wxPen(axis_color, 1));
dc.SetBrush(wxBrush(point_fill));
for (size_t i = 0; i < m_points.size(); ++i) {
const double vy = to_visual_y(m_selected_curve, m_points[i].y);
const wxPoint2DDouble p = data_to_px_f(m_points[i].x, vy);
gc->DrawEllipse(p.m_x - r, p.m_y - r, r * 2, r * 2);
// Control points (selected curve only).
anchors.reserve(m_points.size());
for (size_t i = 0; i < m_points.size(); ++i) {
const double vy = to_visual_y(m_selected_curve, m_points[i].y);
anchors.push_back(data_to_px_f(m_points[i].x, vy));
}
}
const MixedGradientTheme theme{bg, grid_color, axis_color, label_muted, label_strong, outline_color, point_fill};
draw_mixed_gradient_plot(raw_dc, GetClientSize(), curves, anchors, theme);
}
void GradientCurveEditor::on_left_down(wxMouseEvent& evt)
+2 -2
View File
@@ -46,7 +46,7 @@ int get_hms_info_version(std::string& version)
std::string url = (boost::format("https://%1%/GetVersion.php?%2%") % hms_host % query_params).str();
Slic3r::Http http = Slic3r::Http::get(url);
http.timeout_max(10)
.on_complete([&result, &version](std::string body, unsigned status){
.on_complete([&version](std::string body, unsigned status){
try {
json j = json::parse(body);
if (j.contains("ver")) {
@@ -95,7 +95,7 @@ int HMSQuery::download_hms_related(const std::string& hms_type, const std::strin
BOOST_LOG_TRIVIAL(info) << "hms: download url = " << url;
Slic3r::Http http = Slic3r::Http::get(url);
http.on_complete([this, receive_json, hms_type, &to_save_local, &j, & local_version](std::string body, unsigned status) {
http.on_complete([receive_json, hms_type, &to_save_local, &j, & local_version](std::string body, unsigned status) {
try {
j = json::parse(body);
if (j.contains("result")) {
-1
View File
@@ -25,7 +25,6 @@ class HMSNotifyItem : public wxPanel
wxStaticBitmap *m_bitmap_notify;
wxStaticBitmap *m_bitmap_arrow;
wxStaticText * m_hms_content;
wxHtmlWindow * m_html;
wxPanel * m_staticline;
wxBitmap m_img_notify_lv1;
-1
View File
@@ -216,7 +216,6 @@ private:
long m_extra_style;
float m_label_koef{1.0};
float m_zero_layer_height = 0.0f;
std::vector<double> m_values;
TickCodeInfo m_ticks;
std::vector<double> m_layers_times;
+1 -2
View File
@@ -265,8 +265,7 @@ arrangement::ArrangePolygon estimate_wipe_tower_info(int plate_index, std::set<i
int extruder_size = extruder_ids.size();
Vec3d wipe_tower_size, wipe_tower_pos;
int nozzle_nums = wxGetApp().preset_bundle->get_printer_extruder_count();
auto arrange_poly = ppl.get_plate(plate_index_valid)->estimate_wipe_tower_polygon(full_config, plate_index, wipe_tower_pos, wipe_tower_size, nozzle_nums, extruder_size);
auto arrange_poly = ppl.get_plate(plate_index_valid)->estimate_wipe_tower_polygon(full_config, plate_index, wipe_tower_pos, wipe_tower_size, extruder_size);
arrange_poly.bed_idx = plate_index;
return arrange_poly;
}
-1
View File
@@ -20,7 +20,6 @@ class BindJob : public Job
std::string m_sec_link;
std::string m_ssdp_version;
bool m_job_finished{ false };
int m_print_job_completed_id = 0;
bool m_improved{false};
public:
+1 -1
View File
@@ -184,7 +184,7 @@ void FillBedJob::prepare()
ap.poly = m_selected.front().poly;
ap.bed_idx = PartPlateList::MAX_PLATES_COUNT;
ap.itemid = -1;
ap.setter = [this, mi, offset](const ArrangePolygon &p) {
ap.setter = [this, offset](const ArrangePolygon &p) {
ModelObject *mo = m_plater->model().objects[m_object_idx];
ModelObject *obj;
if (m_instances) {
+4 -1
View File
@@ -79,9 +79,12 @@ class PlaterWorker: public Worker {
steady_clock::time_point finalize_end = steady_clock::now();
long long finalize_duration = duration_cast<milliseconds>(finalize_end - finalize_start).count();
// Bound first so typeid's operand is not a call. typeid evaluates it for a
// polymorphic type, which clang reports as -Wpotentially-evaluated-expression.
const Job &job = *m_job;
BOOST_LOG_TRIVIAL(info)
<< std::fixed // do not use scientific notations
<< "Job '" << typeid(*m_job).name() << "' "
<< "Job '" << typeid(job).name() << "' "
<< "spend " << m_process_duration + finalize_duration << "ms "
<< "(process " << m_process_duration << "ms + finalize " << finalize_duration << "ms)";
+1 -4
View File
@@ -135,7 +135,6 @@ void PrintJob::process(Ctl &ctl)
{
/* display info */
std::string msg;
wxString error_str;
int curr_percent = 10;
NetworkAgent* m_agent = wxGetApp().getAgent();
AppConfig* config = wxGetApp().app_config;
@@ -402,9 +401,7 @@ void PrintJob::process(Ctl &ctl)
&is_try_lan_mode,
&is_try_lan_mode_failed,
&msg,
&error_str,
&curr_percent,
&error_text,
StagePercentPoint
](int stage, int code, std::string info) {
@@ -491,7 +488,7 @@ void PrintJob::process(Ctl &ctl)
DeviceManager* dev = wxGetApp().getDeviceManager();
MachineObject* obj = dev->get_selected_machine();
auto wait_fn = [this, &ctl, curr_percent, &obj](int state, std::string job_info) {
auto wait_fn = [&ctl, &obj](int state, std::string job_info) {
BOOST_LOG_TRIVIAL(info) << "print_job: get_job_info = " << job_info;
if (!obj->is_support_wait_sending_finish) {
+1 -1
View File
@@ -55,7 +55,7 @@ void RotoptimizeJob::process(Ctl &ctl)
sla::RotOptimizeParams{}
.accuracy(m_accuracy)
.print_config(&m_default_print_cfg)
.statucb([this, &prev_status, &ctl/*, &statustxt*/](int s)
.statucb([&ctl/*, &statustxt*/](int s)
{
return !ctl.was_canceled();
});
+1 -2
View File
@@ -213,7 +213,6 @@ void SendJob::process(Ctl &ctl)
params.password = m_access_code;
params.use_ssl_for_ftp = m_local_use_ssl_for_ftp;
params.use_ssl_for_mqtt = m_local_use_ssl;
wxString error_text;
std::string msg_text;
const int StagePercentPoint[(int)PrintingStageFinished + 1] = {
@@ -227,7 +226,7 @@ void SendJob::process(Ctl &ctl)
};
auto update_fn = [this, &ctl,
&msg, &curr_percent, &error_text, StagePercentPoint](int stage, int code, std::string info) {
&msg, &curr_percent, StagePercentPoint](int stage, int code, std::string info) {
if (stage == SendingPrintJobStage::PrintingStageCreate) {
if (this->connection_type == "lan") {
msg = _u8L("Sending G-code file over LAN");
@@ -27,7 +27,6 @@ class UpgradeNetworkJob : public Job
wxWindow * m_event_handle{nullptr};
std::function<void()> m_success_fun{nullptr};
bool m_job_finished{ false };
int m_print_job_completed_id = 0;
InstallProgressFn pro_fn { nullptr };
+1
View File
@@ -174,6 +174,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "O", L("Open Project") },
{ ctrl + "S", L("Save Project") },
{ ctrl + shift + "S", L("Save Project as")},
{ ctrl + shift + "E", L("Publish 3MF") },
// File>Import
{ ctrl + "I", L("Import geometry data from STL/STEP/3MF/OBJ/AMF files") },
// File>Export
+71 -30
View File
@@ -39,7 +39,6 @@
#include "Plater.hpp"
#include "WebViewDialog.hpp"
#include "../Utils/Process.hpp"
#include "format.hpp"
// BBS
#include "PartPlate.hpp"
#include "Preferences.hpp"
@@ -49,11 +48,9 @@
#include "../Utils/NetworkAgentFactory.hpp"
#include "../Utils/PrintHost.hpp"
#include <fstream>
#include <string_view>
#include "GUI_App.hpp"
#include "UnsavedChangesDialog.hpp"
#include "PublishSettingsDialog.hpp"
#include "MsgDialog.hpp"
#include "Notebook.hpp"
#include "GUI_Factories.hpp"
@@ -743,10 +740,14 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
if (m_plater) { m_plater->add_file(); }
return;
}
if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'E') {
if (can_export_model()) publish_project();
return;
}
evt.Skip();
});
Bind(wxEVT_SHOW, [this](wxShowEvent &evt) {
Bind(wxEVT_SHOW, [](wxShowEvent &evt) {
DeviceManager *manger = wxGetApp().getDeviceManager();
if (manger) {
evt.IsShown() ? manger->start_refresher() : manger->stop_refresher();
@@ -1739,6 +1740,22 @@ bool MainFrame::save_project_as(const wxString& filename)
return ret;
}
void MainFrame::publish_project()
{
if (m_plater == nullptr)
return;
// Seed the dialog from the session selection (a remembered state or a freshly loaded
// published 3MF); a null pointer means "fresh", keeping the dirty defaults.
std::vector<std::string> pending_keys;
std::vector<Slic3r::PublishedMaterialEntry> pending_material;
const bool has_prior = m_plater->get_pending_published(pending_keys, pending_material);
PublishSettingsDialog dlg(this, has_prior ? &pending_keys : nullptr, has_prior ? &pending_material : nullptr);
if (dlg.ShowModal() != wxID_OK)
return;
m_plater->set_pending_published(dlg.GetPublishedKeys(), dlg.GetPublishedMaterialKeys());
m_plater->export_published_3mf(dlg.GetPublishedKeys(), dlg.GetPublishedMaterialKeys());
}
bool MainFrame::can_upload() const
{
return true;
@@ -2834,6 +2851,20 @@ void MainFrame::init_menubar_as_editor()
[this](){return m_plater != nullptr && can_save_as(); }, this);
#endif
// BBS: publish
fileMenu->AppendSeparator();
auto publish_handler = [this](wxCommandEvent&) { publish_project(); };
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Publish 3MF") + dots + "\t" + ctrl + shift + "E", _L("Export a 3MF file with the selected settings embedded"),
publish_handler, "menu_publish", nullptr,
[this](){return can_export_model(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Publish 3MF") + dots + "\t" + ctrl + shift + "E", _L("Export a 3MF file with the selected settings embedded"),
publish_handler, "", nullptr,
[this](){return can_export_model(); }, this);
#endif
fileMenu->AppendSeparator();
@@ -2850,12 +2881,12 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { if (m_plater) { m_plater->add_model(); } }, "", nullptr,
[this](){return can_add_models(); }, this);
#endif
append_menu_item(import_menu, wxID_ANY, _L("Import Zip Archive") + dots, _L("Load models contained within a zip archive"),
append_menu_item(import_menu, wxID_ANY, _L("Import ZIP Archive") + dots, _L("Load models contained within a ZIP archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_zip_archive(); }, "menu_import", nullptr,
[this]() { return can_add_models(); });
append_menu_item(import_menu, wxID_ANY, _L("Import Configs") + dots /*+ "\t" + ctrl + "I"*/, _L("Load configs"),
[this](wxCommandEvent&) { load_config_file(); }, "menu_import", nullptr,
[this](){return true; }, this);
[](){return true; }, this);
append_submenu(fileMenu, import_menu, wxID_ANY, _L("Import"), "");
@@ -2968,7 +2999,7 @@ void MainFrame::init_menubar_as_editor()
_L("Duplicate the current plate"),[this](wxCommandEvent&) {
m_plater->duplicate_plate();
},
"menu_remove", nullptr, [this](){return true;}, this);
"menu_remove", nullptr, [](){return true;}, this);
editMenu->AppendSeparator();
#else
// BBS undo
@@ -3068,10 +3099,10 @@ void MainFrame::init_menubar_as_editor()
"", nullptr, [this](){return can_clone(); }, this);
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _L("Duplicate Current Plate"),
_L("Duplicate the current plate"),[this, handle_key_event](wxCommandEvent&) {
_L("Duplicate the current plate"),[this](wxCommandEvent&) {
m_plater->duplicate_plate();
},
"", nullptr, [this](){return true;}, this);
"", nullptr, [](){return true;}, this);
editMenu->AppendSeparator();
#endif
@@ -3135,13 +3166,13 @@ void MainFrame::init_menubar_as_editor()
//BBS perspective view
wxWindowID camera_id_base = wxWindow::NewControlId(int(wxID_CAMERA_COUNT));
auto perspective_item = append_menu_radio_item(viewMenu, wxID_CAMERA_PERSPECTIVE + camera_id_base, _L("Use Perspective View"), _L("Use Perspective View"),
[this](wxCommandEvent&) {
[](wxCommandEvent&) {
wxGetApp().app_config->set_bool("use_perspective_camera", true);
wxGetApp().update_ui_from_settings();
}, nullptr);
//BBS orthogonal view
auto orthogonal_item = append_menu_radio_item(viewMenu, wxID_CAMERA_ORTHOGONAL + camera_id_base, _L("Use Orthogonal View"), _L("Use Orthogonal View"),
[this](wxCommandEvent&) {
[](wxCommandEvent&) {
wxGetApp().app_config->set_bool("use_perspective_camera", false);
wxGetApp().update_ui_from_settings();
}, nullptr);
@@ -3157,7 +3188,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
},
this, [this]() { return is_prepare_or_preview_tab(); },
[this]() { return wxGetApp().app_config->get_bool("auto_perspective"); }, this);
[]() { return wxGetApp().app_config->get_bool("auto_perspective"); }, this);
viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &G-code Window") + sep + "C", _L("Show G-code window in Preview scene."),
@@ -3166,7 +3197,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
},
this, [this]() { return m_tabpanel->GetSelectedPageName() == TAB_ID_PREVIEW; },
[this]() { return wxGetApp().show_gcode_window(); }, this);
[]() { return wxGetApp().show_gcode_window(); }, this);
append_menu_check_item(
viewMenu, wxID_ANY, _L("Show 3D Navigator"), _L("Show 3D navigator in Prepare and Preview scene."),
@@ -3175,7 +3206,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
},
this, [this]() { return is_prepare_or_preview_tab(); },
[this]() { return wxGetApp().show_3d_navigator(); }, this);
[]() { return wxGetApp().show_3d_navigator(); }, this);
append_menu_check_item(viewMenu, wxID_ANY, _L("Show Gridlines"), _L("Show Gridlines on plate"),
[this](wxCommandEvent&) {
@@ -3183,7 +3214,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
}, this,
[this]() { return is_prepare_or_preview_tab(); },
[this]() { return wxGetApp().show_plate_gridlines(); }, this);
[]() { return wxGetApp().show_plate_gridlines(); }, this);
append_menu_item(
viewMenu, wxID_ANY, _L("Reset Window Layout"), _L("Reset to default window layout"),
@@ -3212,7 +3243,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
},
this, [this]() { return m_tabpanel->GetSelectedPageName() == TAB_ID_PREPARE; },
[this]() { return wxGetApp().show_outline(); }, this);
[]() { return wxGetApp().show_outline(); }, this);
/*viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Wireframe") + "\t" + ctrl + shift + _L("Enter"), _L("Show wireframes in 3D scene."),
@@ -3338,11 +3369,11 @@ void MainFrame::init_menubar_as_editor()
//parent_menu->Insert(0, about_item);
append_menu_item(
parent_menu, wxID_ANY, _L(about_title), "",
[this](wxCommandEvent &) { Slic3r::GUI::about();},
[](wxCommandEvent &) { Slic3r::GUI::about();},
"", nullptr, []() { return true; }, this, 0);
append_menu_item(
parent_menu, wxID_ANY, _L("Preferences") + "\t" + ctrl + ",", "",
[this](wxCommandEvent &) {
[](wxCommandEvent &) {
wxGetApp().open_preferences();
},
"", nullptr, []() { return true; }, this, 1);
@@ -3361,7 +3392,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(
m_topbar->GetTopMenu(), wxID_ANY, _L("Preferences") + "\t" + ctrl + "P", "",
[this](wxCommandEvent &) {
[](wxCommandEvent &) {
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
wxGetApp().open_preferences();
},
@@ -3393,14 +3424,14 @@ void MainFrame::init_menubar_as_editor()
into_u8(_L("Syncing presets from cloud\u2026")));
wxGetApp().restart_sync_user_preset();
}, "", nullptr,
[this]() {
[]() {
return wxGetApp().is_user_login() && !wxGetApp().app_config->get_stealth_mode();
}, this);
top_menu->AppendSeparator();
append_menu_item(
top_menu, wxID_ANY, _L("Plugins") + "\t", "",
[this](wxCommandEvent &) {
[](wxCommandEvent &) {
wxGetApp().open_plugins_dialog();
},
"", nullptr, []() { return true; }, this);
@@ -3501,7 +3532,7 @@ void MainFrame::init_menubar_as_editor()
[this]() {return m_plater->is_view3D_shown();; }, this);
// help
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Calibration Guide"), _L("Calibration Guide"), [this](wxCommandEvent &)
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Calibration Guide"), _L("Calibration Guide"), [](wxCommandEvent &)
{ wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/calibration_guide", wxBROWSER_NEW_WINDOW); }, "", nullptr, [this]()
{return m_plater->is_view3D_shown();; }, this);
@@ -3530,13 +3561,13 @@ void MainFrame::init_menubar_as_editor()
into_u8(_L("Syncing presets from cloud\u2026")));
wxGetApp().restart_sync_user_preset();
}, "", nullptr,
[this]() {
[]() {
return wxGetApp().is_user_login() && !wxGetApp().app_config->get_stealth_mode();
}, this);
fileMenu->AppendSeparator();
append_menu_item(
fileMenu, wxID_ANY, _L("Plugins"), "", [this](wxCommandEvent&) { wxGetApp().open_plugins_dialog(); }, "", nullptr,
fileMenu, wxID_ANY, _L("Plugins"), "", [](wxCommandEvent&) { wxGetApp().open_plugins_dialog(); }, "", nullptr,
[]() { return true; }, this);
fileMenu->AppendSeparator();
@@ -3640,7 +3671,7 @@ void MainFrame::init_menubar_as_editor()
[this]() {return m_plater->is_view3D_shown();; }, this);
// help
append_menu_item(calib_menu, wxID_ANY, _L("Calibration Guide"), _L("Calibration Guide"),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/calibration_guide", wxBROWSER_NEW_WINDOW); }, "", nullptr,
[](wxCommandEvent&) { wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/calibration_guide", wxBROWSER_NEW_WINDOW); }, "", nullptr,
[this]() {return m_plater->is_view3D_shown();; }, this);
m_menubar->Append(calib_menu,wxString::Format("&%s", _L("Calibration")));
@@ -4212,15 +4243,23 @@ std::wstring MainFrame::FileHistory::GetThumbnailUrl(int index) const
return wss.str();
}
bool MainFrame::FileHistory::GetPublished(int index) const
{
return index >= 0 && index < static_cast<int>(m_published_files.size()) && m_published_files[index];
}
void MainFrame::FileHistory::AddFileToHistory(const wxString &file)
{
if (this->m_fileMaxFiles == 0)
return;
wxFileHistory::AddFileToHistory(file);
if (m_load_called)
if (m_load_called) {
m_thumbnails.push_front(bbs_3mf_get_thumbnail(into_u8(file).c_str()));
else
m_published_files.push_front(bbs_3mf_is_published(into_u8(file)));
} else {
m_thumbnails.push_front("");
m_published_files.push_front(false);
}
}
void MainFrame::FileHistory::RemoveFileFromHistory(size_t i)
@@ -4229,6 +4268,7 @@ void MainFrame::FileHistory::RemoveFileFromHistory(size_t i)
return;
wxFileHistory::RemoveFileFromHistory(i);
m_thumbnails.erase(m_thumbnails.begin() + i);
m_published_files.erase(m_published_files.begin() + i);
}
size_t MainFrame::FileHistory::FindFileInHistory(const wxString & file)
@@ -4244,6 +4284,7 @@ void MainFrame::FileHistory::LoadThumbnails()
if (!thumbnail.empty()) {
m_thumbnails[i] = thumbnail;
}
m_published_files[i] = bbs_3mf_is_published(into_u8(GetHistoryFile(i)));
}
});
m_load_called = true;
@@ -4264,6 +4305,7 @@ void MainFrame::get_recent_projects(boost::property_tree::wptree &tree, int imag
std::wstring proj = m_recent_projects.GetHistoryFile(i).ToStdWstring();
item.put(L"project_name", proj.substr(proj.find_last_of(L"/\\") + 1));
item.put(L"path", proj);
item.put(L"published", m_recent_projects.GetPublished(i) ? L"1" : L"0");
boost::system::error_code ec;
std::time_t t = boost::filesystem::last_write_time(proj, ec);
if (!ec) {
@@ -4488,10 +4530,9 @@ std::string MainFrame::get_dir_name(const wxString &full_name) const
// ----------------------------------------------------------------------------
SettingsDialog::SettingsDialog(MainFrame* mainframe)
:DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "settings_dialog"),
:DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "settings_dialog")
//: DPIDialog(mainframe, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize,
// wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX, "settings_dialog"),
m_main_frame(mainframe)
{
if (wxGetApp().is_gcode_viewer())
return;
+4 -1
View File
@@ -94,7 +94,6 @@ class SettingsDialog : public DPIDialog//DPIDialog
{
//wxNotebook* m_tabpanel { nullptr };
Notebook* m_tabpanel{ nullptr };
MainFrame* m_main_frame { nullptr };
wxMenuBar* m_menubar{ nullptr };
public:
SettingsDialog(MainFrame* mainframe);
@@ -179,6 +178,7 @@ class MainFrame : public DPIFrame
{
FileHistory(int max) : wxFileHistory(max) {}
std::wstring GetThumbnailUrl(int index) const;
bool GetPublished(int index) const;
virtual void AddFileToHistory(const wxString &file);
virtual void RemoveFileFromHistory(size_t i);
@@ -189,6 +189,7 @@ class MainFrame : public DPIFrame
void SetMaxFiles(int max);
private:
std::deque<std::string> m_thumbnails;
std::deque<bool> m_published_files; // parallel to m_thumbnails: is it a published 3mf?
bool m_load_called = false;
};
@@ -342,6 +343,8 @@ public:
bool can_upload() const;
void save_project();
bool save_project_as(const wxString& filename = wxString());
// Open the Publish dialog and export the selected settings as a published 3MF.
void publish_project();
void add_to_recent_projects(const wxString& filename);
void get_recent_projects(boost::property_tree::wptree &tree, int images);
+4 -4
View File
@@ -71,7 +71,7 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl3 *media_ctrl, const w
auto ip = str.find(' ', ik);
if (ip == wxString::npos) ip = str.Length();
auto v = str.Mid(ik, ip - ik);
if (k == "T:" && v.Length() == 8) {
if (strcmp(k, "T:") == 0 && v.Length() == 8) {
long h = 0,m = 0,s = 0;
v.Left(2).ToLong(&h);
v.Mid(3, 2).ToLong(&m);
@@ -494,13 +494,13 @@ void MediaPlayCtrl::ToggleStream()
DownloadProgressDialog2(MediaPlayCtrl *ctrl) : DownloadProgressDialog(_L("Downloading Virtual Camera Tools")), ctrl(ctrl) {}
struct UpgradeNetworkJob2 : UpgradeNetworkJob
{
UpgradeNetworkJob2(std::shared_ptr<ProgressIndicator> pri) : UpgradeNetworkJob() {
UpgradeNetworkJob2() {
name = "cameratools";
package_name = "camera_tools.zip";
}
};
std::shared_ptr<UpgradeNetworkJob> make_job(std::shared_ptr<ProgressIndicator> pri)
{ return std::make_shared<UpgradeNetworkJob2>(pri); }
std::unique_ptr<UpgradeNetworkJob> make_job() override
{ return std::make_unique<UpgradeNetworkJob2>(); }
void on_finish() override
{
ctrl->CallAfter([ctrl = this->ctrl] { ctrl->ToggleStream(); });

Some files were not shown because too many files have changed in this diff Show More