Make sure settings tab are still marked as modified even if modified variant is not currently selected

This commit is contained in:
Noisyfox
2026-05-18 14:09:24 +08:00
parent caa5bb38ea
commit 59c7809ee1
5 changed files with 572 additions and 258 deletions

View File

@@ -430,6 +430,17 @@ enum FilamentMapMode {
extern std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type);
static std::set<NozzleVolumeType> get_valid_nozzle_volume_type() {
std::set<NozzleVolumeType> type;
for (int i = 0; i <= nvtMaxNozzleVolumeType; ++i) {
auto t = static_cast<NozzleVolumeType>(i);
// TODO: Orca: Support hybrid
//if (t == nvtHybrid) continue;
type.insert(t);
}
return type;
}
std::string get_nozzle_volume_type_string(NozzleVolumeType nozzle_volume_type);
static std::string bed_type_to_gcode_string(const BedType type)

View File

@@ -88,6 +88,15 @@ static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_co
static const std::vector<std::string> plate_keys = { "curr_bed_type", "skirt_start_angle", "first_layer_print_sequence", "first_layer_sequence_choice", "other_layers_print_sequence", "other_layers_sequence_choice", "print_sequence", "spiral_mode"};
static std::pair<std::string, std::string> extruder_variant_keys[]{
{}, // invalid
{"print_extruder_id", "print_extruder_variant"}, // Preset::TYPE_PRINT
{}, // invalid
{"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore
{}, // invalid
{"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER
};
void Tab::Highlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/)
{
m_timer.SetOwner(owner, timerid);
@@ -487,12 +496,21 @@ void Tab::create_preset_tab()
m_main_sizer->Add(m_tabctrl, 0, wxEXPAND | wxALL, 0 );
if (dynamic_cast<TabPrinter *>(this) || dynamic_cast<TabPrint *>(this)) {
m_extruder_switch = new SwitchButton(panel);
m_extruder_switch = new MultiSwitchButton(panel);
m_extruder_switch->SetMaxSize({em_unit(this) * 24, -1});
m_extruder_switch->SetLabels(_L("Left"), _L("Right"));
m_extruder_switch->Bind(wxEVT_TOGGLEBUTTON, [this] (auto & evt) {
m_extruder_switch->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this](auto &evt) {
evt.Skip();
switch_excluder(evt.GetInt());
int selection = evt.GetInt();
int extruder_id;
NozzleVolumeType nozzle_type;
parse_extruder_selection(selection, extruder_id, nozzle_type);
int extruder_count = m_preset_bundle->get_printer_extruder_count();
m_actual_nozzle_volumes.resize(extruder_count, NozzleVolumeType::nvtStandard);
if (extruder_id >= 0 && extruder_id < m_preset_bundle->get_printer_extruder_count())
m_actual_nozzle_volumes[extruder_id] = nozzle_type;
switch_excluder(extruder_id);
reload_config();
update_changed_ui();
});
@@ -557,6 +575,79 @@ void Tab::create_preset_tab()
m_completed = true;
}
void Tab::parse_extruder_selection(int selection, int &extruder_id, NozzleVolumeType &nozzle_type)
{
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
int extruder_nums = m_preset_bundle->get_printer_extruder_count();
int current_index = 0;
for (int i = 0; i < extruder_nums; ++i) {
NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]);
// TODO: Orca: Support hybrid
//if (volume_type == NozzleVolumeType::nvtHybrid) {
// if (selection == current_index) {
// extruder_id = i;
// nozzle_type = NozzleVolumeType::nvtStandard;
// return;
// } else if (selection == current_index + 1) {
// extruder_id = i;
// nozzle_type = NozzleVolumeType::nvtHighFlow;
// return;
// }
// current_index += 2;
//} else {
if (selection == current_index) {
extruder_id = i;
nozzle_type = volume_type;
return;
}
current_index += 1;
//}
}
extruder_id = 0;
nozzle_type = NozzleVolumeType::nvtStandard;
}
int Tab::calculate_selection_index_for_extruder(int extruder_id, NozzleVolumeType nozzle_type)
{
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
int extruder_nums = m_preset_bundle->get_printer_extruder_count();
int index = 0;
for (int i = 0; i < extruder_nums; ++i) {
if (i == extruder_id) {
// TODO: Orca: Support hybrid
NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]);
/*if (volume_type == NozzleVolumeType::nvtHybrid) {
return nozzle_type == NozzleVolumeType::nvtHighFlow ? index + 1 : index;
} else*/ {
return index;
}
}
NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]);
index += /*(volume_type == NozzleVolumeType::nvtHybrid) ? 2 :*/ 1;
}
return 0;
}
int Tab::get_current_active_extruder()
{
if (m_extruder_switch && m_extruder_switch->IsThisEnabled()) {
int selection = m_extruder_switch->GetSelection();
int extruder_id;
NozzleVolumeType nozzle_type;
parse_extruder_selection(selection, extruder_id, nozzle_type);
return extruder_id;
}
return 0;
}
void Tab::add_scaled_button(wxWindow* parent,
ScalableButton** btn,
const std::string& icon_name,
@@ -917,7 +1008,8 @@ void Tab::update_changed_ui()
}
update_custom_dirty(dirty_options, nonsys_options);
update_all_extruder_options_status();
filter_diff_option(dirty_options);
filter_diff_option(nonsys_options);
@@ -936,6 +1028,7 @@ void Tab::update_changed_ui()
}
decorate();
update_extruder_switch_colors();
wxTheApp->CallAfter([this]() {
if (parent()) //To avoid a crash, parent should be exist for a moment of a tree updating
@@ -951,6 +1044,168 @@ void add_correct_opts_to_options_list(const std::string &opt_key, std::map<std::
map.emplace(opt_key + "#0", value);
}
void Tab::update_all_extruder_options_status()
{
if (!m_extruder_switch && !m_variant_combo) {
return;
}
m_all_extruder_options_status.clear();
int extruder_count = m_preset_bundle->get_printer_extruder_count();
auto extruders = m_preset_bundle->printers.get_edited_preset().config.option<ConfigOptionEnumsGeneric>("extruder_type");
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
std::set<int> all_config_indices;
for (int extruder_id = 0; extruder_id < extruder_count; ++extruder_id) {
for (auto nozzle_type : get_valid_nozzle_volume_type()) {
auto variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type];
int config_index = m_config->get_index_for_extruder(
extruder_id + 1,
variant_keys.first,
ExtruderType(extruders->values[extruder_id]),
nozzle_type,
variant_keys.second
);
if (config_index >= 0) {
all_config_indices.insert(config_index);
}
}
}
auto dirty_options = m_presets->current_dirty_options(true);
auto nonsys_options = m_presets->current_different_from_parent_options(true);
auto filter_extruder_options = [](const std::vector<std::string>& options) {
std::vector<std::string> filtered_options;
for (const auto& opt : options) {
if (opt.find('#') != std::string::npos) {
filtered_options.push_back(opt);
}
}
return filtered_options;
};
auto filtered_dirty_options = filter_extruder_options(dirty_options);
auto filtered_nonsys_options = filter_extruder_options(nonsys_options);
for (int config_index : all_config_indices) {
int status_value = m_opt_status_value;
for (const auto &opt_key : filtered_dirty_options) {
m_all_extruder_options_status[opt_key] = status_value & ~osInitValue;
}
for (const auto &opt_key : filtered_nonsys_options) {
auto iter = m_all_extruder_options_status.find(opt_key);
if (iter != m_all_extruder_options_status.end()) {
iter->second &= ~osSystemValue;
} else {
m_all_extruder_options_status[opt_key] = status_value & ~osSystemValue;
}
}
}
}
void Tab::update_extruder_switch_colors()
{
if (!m_extruder_switch && !m_variant_combo) {
return;
}
auto options = generate_extruder_options();
auto extruders = m_preset_bundle->printers.get_edited_preset().config.option<ConfigOptionEnumsGeneric>("extruder_type");
for (size_t switch_index = 0; switch_index < options.size(); ++switch_index) {
int selection = m_extruder_switch ? m_extruder_switch->GetSelection() : (m_variant_combo ? m_variant_combo->GetSelection() : 0);
if (switch_index == selection) continue;
bool sys_extruder = true;
bool modified_extruder = false;
std::vector<PageShp> pages_to_check;
if (m_active_page) {
if (m_active_page->title() == "Speed" || m_active_page->title() == "Motion ability" || m_active_page->title() == "Filament" ||
m_active_page->title() == "Setting Overrides" || m_active_page->title() == "Multimaterial") {
for (auto page_ptr : m_pages) {
if (page_ptr.get() == m_active_page) {
pages_to_check.push_back(page_ptr);
break;
}
}
}
}
if (pages_to_check.empty()) {
continue;
}
check_extruder_options_status(switch_index, sys_extruder, modified_extruder, pages_to_check);
StateColor default_color(std::make_pair(0x6B6B6B, (int) StateColor::NotChecked), std::make_pair(0xFFFFFE, (int) StateColor::Normal));
StateColor color = modified_extruder ? StateColor(m_modified_label_clr) : default_color;
if (m_extruder_switch)
m_extruder_switch->SetButtonTextColor(switch_index, color);
if (m_variant_combo) {
Button *btn = m_variant_combo->GetButton(switch_index);
if (btn) {
m_variant_combo->SetButtonTextColor(switch_index, color);
}
}
}
}
void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check)
{
int config_index = index;
if (m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_PRINTER) {
int extruder_id;
NozzleVolumeType nozzle_type;
parse_extruder_selection(index, extruder_id, nozzle_type);
auto extruders = m_preset_bundle->printers.get_edited_preset().config.option<ConfigOptionEnumsGeneric>("extruder_type");
auto variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type];
config_index = m_config->get_index_for_extruder(
extruder_id + 1,
variant_keys.first,
ExtruderType(extruders->values[extruder_id]),
nozzle_type,
variant_keys.second
);
}
for (auto page : pages_to_check) {
/*if (page->title() != "Speed" && page->title() != "Motion ability" && page->title() != "Filament" && page->title() != "Setting Overrides" && page->title() != "Multimaterial") {
continue;
}*/
for (auto group : page->m_optgroups) {
for (const auto &kvp : group->opt_map()) {
std::string base_opt_key = kvp.second.first;
// For filament tab, common options will not change color when edited
if (m_type == Preset::TYPE_FILAMENT && kvp.second.second == -1) {
continue;
}
std::string target_opt_key = base_opt_key + "#" + std::to_string(config_index);
auto status_iter = m_all_extruder_options_status.find(target_opt_key);
if (status_iter != m_all_extruder_options_status.end()) {
bool found_modified_for_this_config = false;
const bool deep_compare = (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_FILAMENT || m_type == Preset::TYPE_SLA_MATERIAL ||
m_type == Preset::TYPE_MODEL);
auto original_dirty_options = m_presets->current_dirty_options(deep_compare);
for (const std::string &orig_opt : original_dirty_options) {
if (orig_opt == target_opt_key) {
found_modified_for_this_config = true;
break;
}
}
if (found_modified_for_this_config) {
sys_extruder = (status_iter->second & osSystemValue) != 0;
modified_extruder |= (status_iter->second & osInitValue) == 0;
if (!sys_extruder && modified_extruder) { return; }
}
}
}
}
}
}
void Tab::init_options_list()
{
if (!m_options_list.empty())
@@ -1076,6 +1331,13 @@ void Tab::update_changed_tree_ui()
get_sys_and_mod_flags("compatible_printers", sys_page, modified_page);
}
}
if (page->title() == "Speed" || page->title() == "Motion ability" || page->title() == "Filament" || page->title() == "Setting Overrides" || page->title() == "Multimaterial") {
auto options = generate_extruder_options();
for (size_t switch_index = 0; switch_index < options.size(); ++switch_index) {
std::vector<PageShp> pages_to_check = { page };
check_extruder_options_status(switch_index, sys_page, modified_page, pages_to_check);
}
}
for (auto group : page->m_optgroups)
{
if (!sys_page && modified_page)
@@ -1292,9 +1554,9 @@ void Tab::msw_rescale()
bmp->msw_rescale();
if (m_mode_view)
{
m_mode_view->Rescale();
}
if (m_extruder_switch)
m_extruder_switch->Rescale();
if (m_variant_combo)
m_variant_combo->Rescale();
@@ -5372,7 +5634,7 @@ void TabPrinter::toggle_options()
auto get_index_for_extruder =
[this, &extruders, &nozzle_volumes](int extruder_id, int stride = 1) {
return m_config->get_index_for_extruder(extruder_id + 1, "printer_extruder_id",
ExtruderType(extruders->values[extruder_id]), NozzleVolumeType(nozzle_volumes->values[extruder_id]), "printer_extruder_variant", stride);
ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), "printer_extruder_variant", stride);
};
//BBS: whether the preset is Bambu Lab printer
@@ -6460,7 +6722,11 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
// update_undo_buttons();
this->OnActivate();
m_parent->set_active_tab(this);
GetParent()->Layout();
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
if (variant_ctrl) {
m_main_sizer->Show(variant_ctrl, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder "));
GetParent()->Layout();
}
m_page_view->Thaw();
return false;
@@ -6471,11 +6737,9 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
return false;
m_active_page = page;
if (m_extruder_switch) {
m_main_sizer->Show(m_extruder_switch, m_extruder_switch->IsEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder"));
GetParent()->Layout();
} else if (m_variant_combo) {
m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && !m_active_page->m_opt_id_map.empty());
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
if (variant_ctrl) {
m_main_sizer->Show(variant_ctrl, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder"));
GetParent()->Layout();
}
@@ -7303,21 +7567,24 @@ void Tab::update_extruder_variants(int extruder_id)
int extruder_nums = m_preset_bundle->get_printer_extruder_count();
nozzle_volumes->values.resize(extruder_nums);
if (extruder_nums == 2) {
auto nozzle_volumes_def = m_preset_bundle->project_config.def()->get("nozzle_volume_type");
wxString left, right;
for (size_t i = 0; i < nozzle_volumes_def->enum_labels.size(); ++i) {
if (nozzle_volumes->values[0] == i) left = _L(nozzle_volumes_def->enum_labels[i]);
if (nozzle_volumes->values[1] == i) right = _L(nozzle_volumes_def->enum_labels[i]);
auto options = generate_extruder_options();
m_extruder_switch->SetOptions(options);
int selection_index;
if (extruder_id >= 0) {
NozzleVolumeType current_nozzle_type = get_actual_nozzle_volume_type(extruder_id);
selection_index = calculate_selection_index_for_extruder(extruder_id, current_nozzle_type);
} else {
selection_index = m_extruder_switch->GetSelection();
if (selection_index < 0) {
selection_index = 0;
}
}
m_extruder_switch->SetLabels(wxString::Format(_L("Left: %s"), left), wxString::Format(_L("Right: %s"), right));
m_extruder_switch->SetValue(extruder_id == 1);
m_extruder_switch->SetSelection(selection_index);
m_extruder_switch->Enable(true);
assert(m_extruder_switch->IsEnabled());
} else {
m_extruder_switch->Enable(false);
m_main_sizer->Show(m_extruder_switch, false);
GetParent()->Layout();
return;
}
} else if (m_variant_combo) {
if (extruder_id >= 0)
@@ -7333,29 +7600,43 @@ void Tab::update_extruder_variants(int extruder_id)
m_variant_combo->Enable(options.size() > 1);
}
switch_excluder(extruder_id);
if (m_extruder_switch) {
m_main_sizer->Show(m_extruder_switch, m_active_page && !m_active_page->m_opt_id_map.empty());
GetParent()->Layout();
} else if (m_variant_combo) {
m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty());
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
if (variant_ctrl) {
m_main_sizer->Show(variant_ctrl, variant_ctrl->IsThisEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder "));
GetParent()->Layout();
}
}
NozzleVolumeType Tab::get_actual_nozzle_volume_type(int extruder_id)
{
int extruder_count = m_preset_bundle->get_printer_extruder_count();
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
if (extruder_count == 1) {
if (extruder_id < 0)
return NozzleVolumeType::nvtStandard;
return NozzleVolumeType(nozzle_volumes->values[extruder_id]);
}
if (extruder_id < 0 || extruder_id >= extruder_count)
return NozzleVolumeType::nvtStandard;
if (m_actual_nozzle_volumes.size() != static_cast<size_t>(extruder_count))
m_actual_nozzle_volumes.resize(extruder_count, NozzleVolumeType::nvtStandard);
return m_actual_nozzle_volumes[extruder_id];
}
void Tab::switch_excluder(int extruder_id)
{
Preset & printer_preset = m_preset_bundle->printers.get_edited_preset();
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
auto extruders = printer_preset.config.option<ConfigOptionEnumsGeneric>("extruder_type");
std::pair<std::string, std::string> variant_keys[]{
{}, {"print_extruder_id", "print_extruder_variant"}, // Preset::TYPE_PRINT
{}, {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore
{}, {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER
};
if (!m_variant_combo && (extruder_id >= (int)nozzle_volumes->size() || extruder_id >= (int)extruders->size()))
extruder_id = 0;
if (m_extruder_switch && m_type != Preset::TYPE_PRINTER) {
int current_extruder = m_extruder_switch->GetValue() ? 1 : 0;
int current_extruder = get_current_active_extruder();
if (extruder_id == -1)
extruder_id = current_extruder;
else if (extruder_id != current_extruder)
@@ -7370,15 +7651,16 @@ void Tab::switch_excluder(int extruder_id)
return;
}
auto get_index_for_extruder =
[this, &extruders, &nozzle_volumes, variant_keys = variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) {
[this, &extruders, &nozzle_volumes, variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) {
return m_config->get_index_for_extruder(extruder_id + 1, variant_keys.first,
ExtruderType(extruders->values[extruder_id]), NozzleVolumeType(nozzle_volumes->values[extruder_id]), variant_keys.second, stride);
ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), variant_keys.second, stride);
};
auto index = m_variant_combo ? extruder_id : get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id);
if (index < 0)
return;
if (m_variant_combo)
m_variant_combo->SetClientData(reinterpret_cast<void *>(static_cast<std::uintptr_t>(index)));
if (m_extruder_switch) m_extruder_switch->SetClientData(reinterpret_cast<void*>(static_cast<std::uintptr_t>(index)));
if (m_variant_combo) m_variant_combo->SetClientData(reinterpret_cast<void *>(static_cast<std::uintptr_t>(index)));
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
for (auto page : m_pages) {
bool is_extruder = false;
if (m_type == Preset::TYPE_PRINTER) {

View File

@@ -251,6 +251,7 @@ protected:
std::vector<Preset::Type> m_dependent_tabs;
enum OptStatus { osSystemValue = 1, osInitValue = 2 };
std::map<std::string, int> m_options_list;
std::map<std::string, int> m_all_extruder_options_status;
int m_opt_status_value = 0;
bool m_is_modified_values{ false };
@@ -307,8 +308,9 @@ public:
int m_update_cnt = 0;
ModeSwitchButton *m_mode_view = nullptr;
SwitchButton *m_extruder_switch = nullptr;
MultiSwitchButton *m_variant_combo = nullptr;
MultiSwitchButton * m_extruder_switch = nullptr;
MultiSwitchButton * m_variant_combo = nullptr;
std::vector<NozzleVolumeType> m_actual_nozzle_volumes;
public:
// BBS
@@ -361,8 +363,11 @@ public:
void decorate();
void update_changed_ui();
void get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page);
void update_changed_tree_ui();
void update_changed_tree_ui();
void update_undo_buttons();
void update_extruder_switch_colors();
void update_all_extruder_options_status();
void check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check);
void on_roll_back_value(const bool to_sys = false);
@@ -431,7 +436,12 @@ public:
void update_extruder_variants(int extruder_id = -1);
void switch_excluder(int extruder_id = -1);
std::vector<wxString> generate_extruder_options();
void parse_extruder_selection(int selection, int &extruder_id, NozzleVolumeType &nozzle_type);
int calculate_selection_index_for_extruder(int extruder_id, NozzleVolumeType nozzle_type);
int get_current_active_extruder();
std::vector<wxString> generate_extruder_options();
NozzleVolumeType get_actual_nozzle_volume_type(int extruder_id);
protected:
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget);

View File

@@ -395,6 +395,171 @@ void ModeSwitchButton::update_tooltip()
SetToolTip(m_tooltips[m_selection]);
}
SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, size)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
SetBackgroundColour(*wxWHITE);
leftLabel = leftL;
rightLabel = right;
SetMinSize(size);
SetMaxSize(size);
Bind(wxEVT_PAINT, &SwitchBoard::paintEvent, this);
Bind(wxEVT_LEFT_DOWN, &SwitchBoard::on_left_down, this);
Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_HAND); });
Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_ARROW); });
}
void SwitchBoard::updateState(wxString target)
{
if (target.empty()) {
if (!switch_left && !switch_right) {
return;
}
switch_left = false;
switch_right = false;
} else {
if (target == "left") {
if (switch_left && !switch_right) {
return;
}
switch_left = true;
switch_right = false;
} else if (target == "right") {
if (!switch_left && switch_right) {
return;
}
switch_left = false;
switch_right = true;
}
}
Refresh();
}
void SwitchBoard::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
}
void SwitchBoard::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void SwitchBoard::doRender(wxDC &dc)
{
wxColour disable_color = wxColour(0xCECECE);
dc.SetPen(*wxTRANSPARENT_PEN);
if (is_enable) {dc.SetBrush(wxBrush(0xeeeeee));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 8);
/*left*/
if (switch_left) {
is_enable ? dc.SetBrush(wxBrush(wxColour(0, 150, 136))) : dc.SetBrush(disable_color);
dc.DrawRoundedRectangle(0, 0, GetSize().x / 2, GetSize().y, 8);
}
if (switch_left) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.SetFont(::Label::Body_13);
Slic3r::GUI::WxFontUtils::get_suitable_font_size(0.6 * GetSize().GetHeight(), dc);
auto left_txt_size = dc.GetTextExtent(leftLabel);
dc.DrawText(leftLabel, wxPoint((GetSize().x / 2 - left_txt_size.x) / 2, (GetSize().y - left_txt_size.y) / 2));
/*right*/
if (switch_right) {
if (is_enable) {dc.SetBrush(wxBrush(wxColour(0, 150, 136)));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(GetSize().x / 2, 0, GetSize().x / 2, GetSize().y, 8);
}
auto right_txt_size = dc.GetTextExtent(rightLabel);
if (switch_right) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.DrawText(rightLabel, wxPoint((GetSize().x / 2 - right_txt_size.x) / 2 + GetSize().x / 2, (GetSize().y - right_txt_size.y) / 2));
}
void SwitchBoard::on_left_down(wxMouseEvent &evt)
{
if (!is_enable) {
return;
}
int index = -1;
auto pos = ClientToScreen(evt.GetPosition());
auto rect = ClientToScreen(wxPoint(0, 0));
if (pos.x > 0 && pos.x < rect.x + GetSize().x / 2) {
switch_left = true;
switch_right = false;
index = 1;
} else {
switch_left = false;
switch_right = true;
index = 0;
}
if (auto_disable_when_switch)
{
is_enable = false;// make it disable while switching
}
Refresh();
wxCommandEvent event(wxCUSTOMEVT_SWITCH_POS);
event.SetInt(index);
wxPostEvent(this, event);
}
bool SwitchBoard::Enable(bool enable /* = true */)
{
if (is_enable == enable)
{
return false;
}
is_enable = enable;
Refresh();
return true;
}
MultiSwitchButton::MultiSwitchButton(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
: StaticBox(parent, id, pos, size, style)
, m_bg_color(StateColor(
@@ -580,168 +745,3 @@ bool MultiSwitchButton::send_selection_event()
GetEventHandler()->ProcessEvent(evt);
return true;
}
SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, size)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
SetBackgroundColour(*wxWHITE);
leftLabel = leftL;
rightLabel = right;
SetMinSize(size);
SetMaxSize(size);
Bind(wxEVT_PAINT, &SwitchBoard::paintEvent, this);
Bind(wxEVT_LEFT_DOWN, &SwitchBoard::on_left_down, this);
Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_HAND); });
Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_ARROW); });
}
void SwitchBoard::updateState(wxString target)
{
if (target.empty()) {
if (!switch_left && !switch_right) {
return;
}
switch_left = false;
switch_right = false;
} else {
if (target == "left") {
if (switch_left && !switch_right) {
return;
}
switch_left = true;
switch_right = false;
} else if (target == "right") {
if (!switch_left && switch_right) {
return;
}
switch_left = false;
switch_right = true;
}
}
Refresh();
}
void SwitchBoard::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
}
void SwitchBoard::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void SwitchBoard::doRender(wxDC &dc)
{
wxColour disable_color = wxColour(0xCECECE);
dc.SetPen(*wxTRANSPARENT_PEN);
if (is_enable) {dc.SetBrush(wxBrush(0xeeeeee));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 8);
/*left*/
if (switch_left) {
is_enable ? dc.SetBrush(wxBrush(wxColour(0, 150, 136))) : dc.SetBrush(disable_color);
dc.DrawRoundedRectangle(0, 0, GetSize().x / 2, GetSize().y, 8);
}
if (switch_left) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.SetFont(::Label::Body_13);
Slic3r::GUI::WxFontUtils::get_suitable_font_size(0.6 * GetSize().GetHeight(), dc);
auto left_txt_size = dc.GetTextExtent(leftLabel);
dc.DrawText(leftLabel, wxPoint((GetSize().x / 2 - left_txt_size.x) / 2, (GetSize().y - left_txt_size.y) / 2));
/*right*/
if (switch_right) {
if (is_enable) {dc.SetBrush(wxBrush(wxColour(0, 150, 136)));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(GetSize().x / 2, 0, GetSize().x / 2, GetSize().y, 8);
}
auto right_txt_size = dc.GetTextExtent(rightLabel);
if (switch_right) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.DrawText(rightLabel, wxPoint((GetSize().x / 2 - right_txt_size.x) / 2 + GetSize().x / 2, (GetSize().y - right_txt_size.y) / 2));
}
void SwitchBoard::on_left_down(wxMouseEvent &evt)
{
if (!is_enable) {
return;
}
int index = -1;
auto pos = ClientToScreen(evt.GetPosition());
auto rect = ClientToScreen(wxPoint(0, 0));
if (pos.x > 0 && pos.x < rect.x + GetSize().x / 2) {
switch_left = true;
switch_right = false;
index = 1;
} else {
switch_left = false;
switch_right = true;
index = 0;
}
if (auto_disable_when_switch)
{
is_enable = false;// make it disable while switching
}
Refresh();
wxCommandEvent event(wxCUSTOMEVT_SWITCH_POS);
event.SetInt(index);
wxPostEvent(this, event);
}
bool SwitchBoard::Enable(bool enable /* = true */)
{
if (is_enable == enable)
{
return false;
}
is_enable = enable;
Refresh();
return true;
}

View File

@@ -8,12 +8,11 @@
#include <vector>
#include <wx/sizer.h>
#include <wx/tglbtn.h>
#include "Button.hpp"
wxDECLARE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent);
wxDECLARE_EVENT(wxCUSTOMEVT_MULTISWITCH_SELECTION, wxCommandEvent);
class Button;
class SwitchButton : public wxBitmapToggleButton
{
public:
@@ -81,53 +80,6 @@ private:
wxString m_tooltips[3];
};
class MultiSwitchButton : public StaticBox
{
public:
MultiSwitchButton(wxWindow *parent = nullptr, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize, long style = 0);
~MultiSwitchButton();
int AppendOption(const wxString &option, void *clientData = nullptr);
void SetOptions(const std::vector<wxString> &options);
void DeleteAllOptions();
unsigned int GetCount() const;
int GetSelection() const;
void SetSelection(int index);
wxString GetSelectedText() const;
wxString GetOptionText(unsigned int index) const;
void SetOptionText(unsigned int index, const wxString &text);
void *GetOptionData(unsigned int index) const;
void SetOptionData(unsigned int index, void *clientData);
void SetBackgroundColor(const StateColor &color);
void SetTextColor(const StateColor &color);
void SetButtonCornerRadius(double radius);
void SetButtonPadding(const wxSize &padding);
void Rescale();
protected:
void button_clicked(wxCommandEvent &event);
void update_button_styles();
bool send_selection_event();
private:
std::vector<Button *> btns;
wxBoxSizer *sizer = nullptr;
int sel = -1;
StateColor m_bg_color;
StateColor m_text_color;
double m_button_radius;
wxSize m_button_padding;
};
class SwitchBoard : public wxWindow
{
public:
@@ -163,4 +115,63 @@ private:
bool auto_disable_when_switch = false;
};
class MultiSwitchButton : public StaticBox
{
public:
MultiSwitchButton(wxWindow *parent = nullptr, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize, long style = 0);
~MultiSwitchButton();
int AppendOption(const wxString &option, void *clientData = nullptr);
void SetOptions(const std::vector<wxString> &options);
void DeleteAllOptions();
unsigned int GetCount() const;
int GetSelection() const;
void SetSelection(int index);
wxString GetSelectedText() const;
Button* GetButton(unsigned int index) const
{
return index >= 0 && index < btns.size() ? btns[index] : nullptr;
}
wxString GetOptionText(unsigned int index) const;
void SetOptionText(unsigned int index, const wxString &text);
void *GetOptionData(unsigned int index) const;
void SetOptionData(unsigned int index, void *clientData);
void SetBackgroundColor(const StateColor &color);
void SetTextColor(const StateColor &color);
void SetButtonTextColor(int index, const StateColor &color)
{
if (index >= btns.size()) return;
btns[index]->SetTextColor(color);
btns[index]->Refresh();
}
void SetButtonCornerRadius(double radius);
void SetButtonPadding(const wxSize &padding);
void Rescale();
protected:
void button_clicked(wxCommandEvent &event);
void update_button_styles();
bool send_selection_event();
private:
std::vector<Button *> btns;
wxBoxSizer *sizer = nullptr;
int sel = -1;
StateColor m_bg_color;
StateColor m_text_color;
double m_button_radius;
wxSize m_button_padding;
};
#endif // !slic3r_GUI_SwitchButton_hpp_