Add Expert user mode (#13348)

Add Expert user mode with three-way mode switch. the old ModeButton has been removed.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
SoftFever
2026-04-25 18:14:51 +08:00
committed by GitHub
parent 95e6d8d4fd
commit 82e7ee937f
17 changed files with 338 additions and 399 deletions

View File

@@ -199,6 +199,7 @@ enum ConfigOptionType {
enum ConfigOptionMode {
comSimple = 0,
comAdvanced,
comExpert,
comDevelop,
};

View File

@@ -2,6 +2,7 @@
#include "PartPlate.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/DialogButtons.hpp"
#include "Widgets/Label.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "CapsuleButton.hpp"

View File

@@ -4,7 +4,8 @@
#include "GUI.hpp"
#include "DragDropPanel.hpp"
#include "Widgets/SwitchButton.hpp"
#include "wxExtensions.hpp"
#include "Widgets/Label.hpp"
namespace Slic3r { namespace GUI {

View File

@@ -6572,31 +6572,59 @@ Tab* GUI_App::get_layer_tab()
return model_tabs_list[2];
}
ConfigOptionMode GUI_App::get_mode()
namespace
{
ConfigOptionMode saved_mode_from_string(const std::string& mode)
{
return mode == "expert" ? comExpert :
mode == "advanced" ? comAdvanced :
mode == "develop" ? comAdvanced :
comSimple;
}
std::string saved_mode_to_string(ConfigOptionMode mode)
{
return mode == comExpert ? "expert" :
mode == comAdvanced ? "advanced" :
"simple";
}
std::string effective_mode_to_string(ConfigOptionMode mode)
{
return mode == comDevelop ? "develop" : saved_mode_to_string(mode);
}
}
ConfigOptionMode GUI_App::get_saved_mode()
{
if (!app_config->has("user_mode"))
return comSimple;
//BBS
const auto mode = app_config->get("user_mode");
return mode == "advanced" ? comAdvanced :
mode == "simple" ? comSimple :
mode == "develop" ? comDevelop : comSimple;
return saved_mode_from_string(app_config->get("user_mode"));
}
ConfigOptionMode GUI_App::get_mode()
{
return app_config->get_bool("developer_mode") ? comDevelop : get_saved_mode();
}
std::string GUI_App::get_saved_mode_str()
{
return saved_mode_to_string(get_saved_mode());
}
std::string GUI_App::get_mode_str()
{
if (!app_config->has("user_mode"))
return "simple";
return app_config->get("user_mode");
return effective_mode_to_string(get_mode());
}
void GUI_App::save_mode(const /*ConfigOptionMode*/int mode)
{
//BBS
const std::string mode_str = mode == comAdvanced ? "advanced" :
mode == comSimple ? "simple" :
mode == comDevelop ? "develop" : "simple";
app_config->set("user_mode", mode_str);
const auto saved_mode = mode == comExpert ? comExpert :
mode == comAdvanced ? comAdvanced :
mode == comSimple ? comSimple :
get_saved_mode();
app_config->set("user_mode", saved_mode_to_string(saved_mode));
update_mode();
}

View File

@@ -534,7 +534,9 @@ public:
Tab* get_plate_tab();
Tab* get_model_tab(bool part = false);
Tab* get_layer_tab();
ConfigOptionMode get_saved_mode();
ConfigOptionMode get_mode();
std::string get_saved_mode_str();
std::string get_mode_str();
void save_mode(const /*ConfigOptionMode*/int mode) ;
void update_mode();

View File

@@ -115,7 +115,8 @@ namespace {
ConfigOptionMode config_mode = wxGetApp().get_mode();
if (config_mode == ConfigOptionMode::comSimple) return (tag == "simple" ? TagCheckAffirmative : TagCheckNegative);
else if (config_mode == ConfigOptionMode::comAdvanced) return (tag == "advanced" ? TagCheckAffirmative : TagCheckNegative);
//else if (config_mode == ConfigOptionMode::comDevelop) return (tag == "develop" ? TagCheckAffirmative : TagCheckNegative);
else if (config_mode == ConfigOptionMode::comExpert || config_mode == ConfigOptionMode::comDevelop)
return (tag == "expert" ? TagCheckAffirmative : TagCheckNegative);
}
return TagCheckNotCompatible;
}

View File

@@ -87,25 +87,6 @@ void ButtonsListCtrl::OnPaint(wxPaintEvent&)
dc.SetBrush(clr);
dc.DrawRectangle(pos.x, pos.y + size.y, size.x, sz.y - size.y);
}
#if 0
// highlight selected mode button
if (m_mode_sizer) {
const std::vector<ModeButton*>& mode_btns = m_mode_sizer->get_btns();
for (int idx = 0; idx < int(mode_btns.size()); idx++) {
ModeButton* btn = mode_btns[idx];
btn->SetBackgroundColor(btn->is_selected() ? selected_btn_bg : default_btn_bg);
//wxPoint pos = btn->GetPosition();
//wxSize size = btn->GetSize();
//const wxColour& clr = btn->is_selected() ? btn_marker_color : default_btn_bg;
//dc.SetPen(clr);
//dc.SetBrush(clr);
//dc.DrawRectangle(pos.x, pos.y + size.y, size.x, sz.y - size.y);
}
}
#endif
// Draw orange bottom line
dc.SetPen(btn_marker_color);

View File

@@ -6,7 +6,6 @@
#include <wx/bookctrl.h>
#include <wx/sizer.h>
class ModeSizer;
class ScalableButton;
class Button;
@@ -40,7 +39,6 @@ private:
int m_selection {-1};
int m_btn_margin;
int m_line_margin;
//ModeSizer* m_mode_sizer {nullptr};
std::vector<wxString> m_pageLabels; // ORCA
};

View File

@@ -22,6 +22,16 @@
namespace Slic3r {
namespace GUI {
namespace
{
int mode_to_selection(ConfigOptionMode mode)
{
return mode == comExpert ? 2 :
mode == comAdvanced ? 1 :
0;
}
}
TipsDialog::TipsDialog(wxWindow *parent, const wxString &title, const wxString &description, std::string app_key, long style,std::map<wxStandardID,wxString> option_map)
: DPIDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX),
@@ -261,15 +271,17 @@ ParamsPanel::ParamsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, c
m_mode_icon = new ScalableButton(m_top_panel, wxID_ANY, "advanced"); // ORCA
m_mode_icon->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) {
if(wxGetApp().get_mode() == comDevelop) return; // prevent change on dev mode
m_mode_view->SetValue(!m_mode_view->GetValue());
wxCommandEvent evt(wxEVT_TOGGLEBUTTON, m_mode_view->GetId()); // ParamsPanel::OnToggled(evt)
evt.SetEventObject(m_mode_view);
m_mode_view->wxEvtHandler::ProcessEvent(evt);
if (wxGetApp().get_mode() == comDevelop || m_mode_view == nullptr)
return; // prevent change on dev mode
const int selection = m_mode_view->GetSelection();
m_mode_view->SelectAndNotify((selection + 1) % 3);
});
m_mode_icon->SetToolTip(_L("Show/Hide advanced parameters"));
m_mode_view = new SwitchButton(m_top_panel, wxID_ABOUT);
m_mode_view->SetToolTip(_L("Show/Hide advanced parameters"));
m_mode_icon->SetToolTip(_L("Cycle settings visibility"));
m_mode_view = new ModeSwitchButton(m_top_panel);
m_mode_view->SetSelection(mode_to_selection(wxGetApp().get_saved_mode()));
if (wxGetApp().get_mode() == comDevelop)
m_mode_view->Enable(false);
// BBS: new layout
//m_search_btn = new ScalableButton(m_top_panel, wxID_ANY, "search", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
@@ -382,9 +394,6 @@ ParamsPanel::ParamsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, c
if (m_mode_region)
m_mode_region->Bind(wxEVT_TOGGLEBUTTON, &ParamsPanel::OnToggled, this);
if (m_mode_view)
m_mode_view->Bind(wxEVT_TOGGLEBUTTON, &ParamsPanel::OnToggled, this);
Bind(wxEVT_TOGGLEBUTTON, &ParamsPanel::OnToggled, this); // For Tab's mode switch
//Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { wxGetApp().plater()->search(false); }, wxID_FIND);
//m_export_to_file->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { wxGetApp().mainframe->export_config(); });
//m_import_from_file->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { wxGetApp().mainframe->load_config_file(); });
@@ -560,28 +569,6 @@ void ParamsPanel::OnToggled(wxCommandEvent& event)
return;
}
if (wxID_ABOUT != event.GetId()) {
return;
}
// this is from tab's mode switch
bool value = dynamic_cast<SwitchButton*>(event.GetEventObject())->GetValue();
int mode_id;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": Advanced mode toogle to %1%") % value;
if (value)
{
//m_mode_region->SetBitmap(m_toggle_on_icon);
mode_id = comAdvanced;
}
else
{
//m_mode_region->SetBitmap(m_toggle_off_icon);
mode_id = comSimple;
}
Slic3r::GUI::wxGetApp().save_mode(mode_id);
event.Skip();
}
@@ -657,27 +644,22 @@ bool ParamsPanel::is_active_and_shown_tab(wxPanel* tab)
void ParamsPanel::update_mode()
{
int app_mode = Slic3r::GUI::wxGetApp().get_mode();
SwitchButton * mode_view = m_current_tab ? dynamic_cast<Tab*>(m_current_tab)->m_mode_view : nullptr;
if (mode_view == nullptr) mode_view = m_mode_view;
if (mode_view == nullptr) return;
auto sync_mode_view = [&](ModeSwitchButton* mode_view) {
if (mode_view == nullptr)
return;
//BBS: disable the mode tab and return directly when enable develop mode
if (app_mode == comDevelop)
{
mode_view->Disable();
return;
}
if (!mode_view->IsEnabled())
mode_view->Enable();
mode_view->SetSelection(mode_to_selection(Slic3r::GUI::wxGetApp().get_saved_mode()));
if (app_mode == comDevelop) {
mode_view->Enable(false);
return;
}
if (app_mode == comAdvanced)
{
mode_view->SetValue(true);
}
else
{
mode_view->SetValue(false);
}
if (!mode_view->IsEnabled())
mode_view->Enable();
};
sync_mode_view(m_mode_view);
sync_mode_view(m_current_tab ? dynamic_cast<Tab*>(m_current_tab)->m_mode_view : nullptr);
}
void ParamsPanel::msw_rescale()
@@ -694,7 +676,9 @@ void ParamsPanel::msw_rescale()
((SwitchButton* )m_mode_region)->Rescale();
if (m_mode_icon) m_mode_icon->msw_rescale();
if (m_mode_view)
((SwitchButton* )m_mode_view)->Rescale();
{
m_mode_view->Rescale();
}
for (auto tab : {m_tab_print, m_tab_print_plate, m_tab_print_object, m_tab_print_part, m_tab_print_layer, m_tab_filament, m_tab_printer}) {
if (tab) dynamic_cast<Tab*>(tab)->msw_rescale();
}
@@ -790,7 +774,6 @@ void ParamsPanel::delete_subwindows()
if (m_mode_view)
{
delete m_mode_view;
m_mode_view = nullptr;
}

View File

@@ -31,6 +31,7 @@
#include "GUI_Utils.hpp"
#include "Widgets/Button.hpp"
class ModeSwitchButton;
class SwitchButton;
class StaticBox;
@@ -85,7 +86,7 @@ class ParamsPanel : public wxPanel
ScalableButton *m_tips_arrow{nullptr};
bool m_tips_arror_blink{false};
ScalableButton* m_mode_icon { nullptr }; // ORCA
SwitchButton* m_mode_view { nullptr };
ModeSwitchButton* m_mode_view { nullptr };
//wxBitmapButton* m_search_button { nullptr };
wxStaticLine* m_staticline_print { nullptr };
//wxBoxSizer* m_print_sizer { nullptr };

View File

@@ -1004,11 +1004,7 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too
if (param == "developer_mode") {
m_developer_mode_def = app_config->get("developer_mode");
if (m_developer_mode_def == "true") {
Slic3r::GUI::wxGetApp().save_mode(comDevelop);
} else {
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
}
Slic3r::GUI::wxGetApp().update_mode();
}
// webview dump_vedio

View File

@@ -43,7 +43,9 @@
#include "MsgDialog.hpp"
#include "Notebook.hpp"
#include "Widgets/ComboBox.hpp"
#include "Widgets/Label.hpp"
#include "Widgets/SwitchButton.hpp"
#include "Widgets/TabCtrl.hpp"
#include "MarkdownTip.hpp"
#include "Search.hpp"
@@ -65,6 +67,16 @@ t_config_option_keys deep_diff(const ConfigBase &config_this, const ConfigBase &
namespace GUI {
namespace
{
int mode_to_selection(ConfigOptionMode mode)
{
return mode == comExpert ? 2 :
mode == comAdvanced ? 1 :
0;
}
}
#define DISABLE_UNDO_SYS
// Forward declaration for early use; definitions live later in this translation unit.
@@ -390,17 +402,19 @@ void Tab::create_preset_tab()
if (dynamic_cast<TabPrint*>(this) == nullptr) {
m_mode_icon = new ScalableButton(m_top_panel, wxID_ANY, "advanced"); // ORCA
m_mode_icon->SetToolTip(_L("Show/Hide advanced parameters"));
m_mode_icon->SetToolTip(_L("Cycle settings visibility"));
m_mode_icon->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) {
if(wxGetApp().get_mode() == comDevelop) return; // prevent change on dev mode
m_mode_view->SetValue(!m_mode_view->GetValue());
wxCommandEvent evt(wxEVT_TOGGLEBUTTON, m_mode_view->GetId()); // ParamsPanel::OnToggled(evt)
evt.SetEventObject(m_mode_view);
m_mode_view->wxEvtHandler::ProcessEvent(evt);
if (wxGetApp().get_mode() == comDevelop || m_mode_view == nullptr)
return; // prevent change on dev mode
const int selection = m_mode_view->GetSelection();
m_mode_view->SelectAndNotify((selection + 1) % 3);
});
m_top_sizer->Add(m_mode_icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(SidebarProps::WideSpacing()));
m_mode_view = new SwitchButton(m_top_panel, wxID_ABOUT);
m_mode_view->SetToolTip(_L("Show/Hide advanced parameters"));
m_mode_view = new ModeSwitchButton(m_top_panel);
m_mode_view->SetSelection(mode_to_selection(wxGetApp().get_saved_mode()));
if (wxGetApp().get_mode() == comDevelop)
m_mode_view->Enable(false);
m_top_sizer->AddSpacer(FromDIP(SidebarProps::ElementSpacing()));
m_top_sizer->Add( m_mode_view, 0, wxALIGN_CENTER_VERTICAL);
}
@@ -414,56 +428,6 @@ void Tab::create_preset_tab()
else
m_top_panel->Hide();
#if 0
#ifdef _MSW_DARK_MODE
// Sizer with buttons for mode changing
if (wxGetApp().tabs_as_menu())
#endif
m_mode_sizer = new ModeSizer(panel, int (0.5*em_unit(this)));
const float scale_factor = /*wxGetApp().*/em_unit(this)*0.1;// GetContentScaleFactor();
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_hsizer, 0, wxEXPAND | wxBOTTOM, 3);
m_hsizer->Add(m_presets_choice, 0, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3);
m_hsizer->AddSpacer(int(4*scale_factor));
m_hsizer->Add(m_btn_save_preset, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(int(4 * scale_factor));
m_hsizer->Add(m_btn_delete_preset, 0, wxALIGN_CENTER_VERTICAL);
if (m_btn_edit_ph_printer) {
m_hsizer->AddSpacer(int(4 * scale_factor));
m_hsizer->Add(m_btn_edit_ph_printer, 0, wxALIGN_CENTER_VERTICAL);
}
m_hsizer->AddSpacer(int(/*16*/8 * scale_factor));
m_hsizer->Add(m_btn_hide_incompatible_presets, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(int(8 * scale_factor));
m_hsizer->Add(m_question_btn, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(int(32 * scale_factor));
m_hsizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(int(32 * scale_factor));
m_hsizer->Add(m_search_btn, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(int(8*scale_factor));
m_hsizer->Add(m_btn_compare_preset, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(int(16*scale_factor));
// m_hsizer->AddStretchSpacer(32);
// StretchSpacer has a strange behavior under OSX, so
// There is used just additional sizer for m_mode_sizer with right alignment
if (m_mode_sizer) {
auto mode_sizer = new wxBoxSizer(wxVERTICAL);
// Don't set the 2nd parameter to 1, making the sizer rubbery scalable in Y axis may lead
// to wrong vertical size assigned to wxBitmapComboBoxes, see GH issue #7176.
mode_sizer->Add(m_mode_sizer, 0, wxALIGN_RIGHT);
m_hsizer->Add(mode_sizer, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, wxOSX ? 15 : 10);
}
//Horizontal sizer to hold the tree and the selected page.
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_hsizer, 1, wxEXPAND, 0);
//left vertical sizer
m_left_sizer = new wxBoxSizer(wxVERTICAL);
m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3);
#endif
// tree
m_tabctrl = new TabCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(20 * m_em_unit, -1),
wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_NONE | wxWANTS_CHARS | wxTR_FULL_ROW_HIGHLIGHT);
@@ -1274,11 +1238,6 @@ void Tab::update_mode()
{
m_mode = wxGetApp().get_mode();
//BBS: GUI refactor
// update mode for ModeSizer
//if (m_mode_sizer)
// m_mode_sizer->SetMode(m_mode);
update_visibility();
update_changed_tree_ui();
@@ -1322,7 +1281,9 @@ void Tab::msw_rescale()
bmp->msw_rescale();
if (m_mode_view)
{
m_mode_view->Rescale();
}
if (m_detach_preset_btn)
m_detach_preset_btn->msw_rescale();

View File

@@ -43,6 +43,8 @@
#include "Widgets/CheckBox.hpp" // ORCA
class TabCtrl;
class ModeSwitchButton;
class SwitchButton;
namespace Slic3r {
@@ -162,8 +164,6 @@ protected:
wxScrolledWindow* m_page_view {nullptr};
//wxBoxSizer* m_page_sizer {nullptr};
//ModeSizer* m_mode_sizer {nullptr};
struct PresetDependencies {
Preset::Type type = Preset::TYPE_INVALID;
::CheckBox* checkbox = nullptr;
@@ -303,7 +303,7 @@ public:
// 3. propagate changed configuration to the Plater when (m_update_cnt == 0) only
int m_update_cnt = 0;
SwitchButton *m_mode_view = nullptr;
ModeSwitchButton *m_mode_view = nullptr;
SwitchButton *m_extruder_switch = nullptr;
public:

View File

@@ -3,6 +3,8 @@
#include "StaticBox.hpp"
#include "../wxExtensions.hpp"
#include "../GUI_App.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "../Utils/MacDarkMode.hpp"
#include "../Utils/WxFontUtils.hpp"
#ifdef __APPLE__
@@ -156,10 +158,10 @@ void SwitchButton::Rescale()
#endif
dc2.SetBrush(wxBrush(track_color.colorForStates(state)));
dc2.SetPen(wxPen(track_color.colorForStates(state)));
dc2.DrawRoundedRectangle(wxRect({0, 0}, trackSize), trackSize.y / 2);
dc2.DrawRoundedRectangle(wxRect({0, 0}, trackSize), trackSize.y / 2.0);
dc2.SetBrush(wxBrush(thumb_color.colorForStates(StateColor::Checked | StateColor::Enabled)));
dc2.SetPen(wxPen(thumb_color.colorForStates(StateColor::Checked | StateColor::Enabled)));
dc2.DrawRoundedRectangle(wxRect({ i == 0 ? BS : (trackSize.x - thumbSize.x - BS), BS}, thumbSize), thumbSize.y / 2);
dc2.DrawRoundedRectangle(wxRect({ i == 0 ? BS : (trackSize.x - thumbSize.x - BS), BS}, thumbSize), thumbSize.y / 2.0);
}
memdc.SetTextForeground(text_color.colorForStates(state ^ StateColor::Checked));
auto text_y = BS + (thumbSize.y - textSize[0].y) / 2;
@@ -202,6 +204,184 @@ void SwitchButton::update()
SetBitmap((GetValue() ? m_on : m_off).bmp());
}
ModeSwitchButton::ModeSwitchButton(wxWindow* parent, wxWindowID id)
{
background_color = StateColor(
std::make_pair(wxColour(0xF1, 0xF1, 0xF1), (int) StateColor::Disabled),
std::make_pair(wxColour(0xE3, 0xE3, 0xE3), (int) StateColor::Pressed),
std::make_pair(wxColour(0xD9, 0xD9, 0xD9), (int) StateColor::Normal));
border_color = StateColor(
std::make_pair(wxColour(0xEA, 0xEA, 0xEA), (int) StateColor::Disabled),
std::make_pair(wxColour(0xBC, 0xBC, 0xBC), (int) StateColor::Hovered),
std::make_pair(wxColour(0xC8, 0xC8, 0xC8), (int) StateColor::Focused),
std::make_pair(wxColour(0xCE, 0xCE, 0xCE), (int) StateColor::Normal));
StaticBox::Create(parent, id, wxDefaultPosition, wxDefaultSize, 0);
SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent));
SetCursor(wxCursor(wxCURSOR_HAND));
m_tooltips[0] = _L("Simple settings");
m_tooltips[1] = _L("Advanced settings");
m_tooltips[2] = _L("Expert settings");
Bind(wxEVT_LEFT_DOWN, &ModeSwitchButton::mouseDown, this);
Bind(wxEVT_LEFT_UP, &ModeSwitchButton::mouseReleased, this);
Bind(wxEVT_LEFT_DCLICK, &ModeSwitchButton::mouseDown, this);
Bind(wxEVT_MOUSE_CAPTURE_LOST, &ModeSwitchButton::mouseCaptureLost, this);
Rescale();
}
void ModeSwitchButton::SetSelection(int selection)
{
m_selection = std::clamp(selection, 0, 2);
update_tooltip();
Refresh();
}
void ModeSwitchButton::SelectAndNotify(int selection)
{
if (!IsEnabled())
return;
SetSelection(selection);
Slic3r::GUI::wxGetApp().save_mode(m_selection);
}
void ModeSwitchButton::Rescale()
{
const wxSize button_size = FromDIP(wxSize(48, 20));
SetMinSize(button_size);
SetMaxSize(button_size);
SetSize(button_size);
SetCornerRadius(button_size.y / 2.0);
Refresh();
}
bool ModeSwitchButton::Enable(bool enable /* = true */)
{
const bool changed = StaticBox::Enable(enable);
if (changed)
Refresh();
return changed;
}
void ModeSwitchButton::doRender(wxDC& dc)
{
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(GetBackgroundColour()));
dc.DrawRectangle(GetClientRect());
const wxRect bounds = GetClientRect().Deflate(1);
if (bounds.width <= 0 || bounds.height <= 0)
return;
const int states = state_handler.states();
const bool hovered = (states & StateHandler::Hovered) != 0;
const bool focused = (states & StateHandler::Focused) != 0;
const bool disabled = !IsEnabled();
const wxColour track_fill = disabled ? wxColour(0xD0, 0xD0, 0xD4) :
m_pressed ? wxColour(0x5A, 0x5D, 0x64) : wxColour(0x66, 0x69, 0x70);
const wxColour track_border = disabled ? wxColour(0xDD, 0xDD, 0xE0) :
focused ? wxColour("#009688") :
hovered ? wxColour(0x7A, 0x7D, 0x84) : wxColour(0x75, 0x78, 0x7F);
const wxColour active_fill = disabled ? wxColour(0x9E, 0xBE, 0xB9) :
m_pressed ? wxColour(0x00877B) : wxColour("#009688");
const wxColour active_dot = disabled ? wxColour(0xEC, 0xF4, 0xF2) : wxColour(0xB7, 0xEB, 0xE3);
const wxColour inactive_dot = disabled ? wxColour(0xF2, 0xF2, 0xF4) : wxColour(0xB5, 0xB7, 0xBD);
const wxColour thumb_fill = disabled ? wxColour(0xFA, 0xFA, 0xFA) : *wxWHITE;
const wxColour thumb_border = disabled ? wxColour(0xE7, 0xE7, 0xEA) : wxColour(0xDD, 0xDF, 0xE3);
dc.SetPen(wxPen(track_border, 1));
dc.SetBrush(wxBrush(track_fill));
dc.DrawRoundedRectangle(bounds, bounds.height / 2.0);
const wxRect thumb = thumb_rect_for(m_selection);
const int fill_right = std::min(bounds.GetRight(), thumb.GetX() + thumb.GetWidth() / 2 + FromDIP(2));
wxRect active(bounds.x, bounds.y, fill_right - bounds.x + 1, bounds.height);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(active_fill));
dc.DrawRoundedRectangle(active, bounds.height / 2.0);
const int dot_radius = std::max(FromDIP(1), thumb.height / 7);
for (int idx = 0; idx < 3; ++idx) {
if (idx == m_selection)
continue;
const wxRect slot = thumb_rect_for(idx);
const wxPoint center(slot.GetX() + slot.GetWidth() / 2, slot.GetY() + slot.GetHeight() / 2);
dc.SetBrush(wxBrush(idx < m_selection ? active_dot : inactive_dot));
dc.DrawCircle(center, dot_radius);
}
dc.SetPen(wxPen(thumb_border, 1));
dc.SetBrush(wxBrush(thumb_fill));
dc.DrawRoundedRectangle(thumb, thumb.height / 2.0);
}
void ModeSwitchButton::mouseDown(wxMouseEvent& event)
{
if (!IsEnabled()) {
event.Skip();
return;
}
m_pressed = true;
if (!HasCapture())
CaptureMouse();
Refresh();
event.Skip();
}
void ModeSwitchButton::mouseReleased(wxMouseEvent& event)
{
if (m_pressed) {
m_pressed = false;
if (HasCapture())
ReleaseMouse();
if (GetClientRect().Contains(event.GetPosition()))
SelectAndNotify(hit_test_selection(event.GetPosition()));
Refresh();
}
event.Skip();
}
void ModeSwitchButton::mouseCaptureLost(wxMouseCaptureLostEvent& event)
{
m_pressed = false;
Refresh();
event.Skip();
}
int ModeSwitchButton::hit_test_selection(const wxPoint& point) const
{
const int width = std::max(1, GetClientSize().x);
const int x = std::clamp(point.x, 0, width - 1);
return std::clamp((x * 3) / width, 0, 2);
}
wxRect ModeSwitchButton::thumb_rect_for(int selection) const
{
const wxRect bounds = GetClientRect().Deflate(3);
const int thumb_diameter = std::max(FromDIP(10), bounds.height - FromDIP(2));
const int y = bounds.y + (bounds.height - thumb_diameter) / 2;
const int travel = std::max(0, bounds.width - thumb_diameter);
const int x = bounds.x + (travel * std::clamp(selection, 0, 2)) / 2;
return wxRect(x, y, thumb_diameter, thumb_diameter);
}
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)
{
@@ -355,24 +535,14 @@ void SwitchBoard::on_left_down(wxMouseEvent &evt)
wxPostEvent(this, event);
}
void SwitchBoard::Enable()
bool SwitchBoard::Enable(bool enable /* = true */)
{
if (is_enable == true)
if (is_enable == enable)
{
return;
return false;
}
is_enable = true;
Refresh();
}
void SwitchBoard::Disable()
{
if (is_enable == false)
{
return;
}
is_enable = false;
is_enable = enable;
Refresh();
return true;
}

View File

@@ -3,10 +3,9 @@
#include "../wxExtensions.hpp"
#include "StateColor.hpp"
#include "StaticBox.hpp"
#include <wx/tglbtn.h>
#include "Label.hpp"
#include "Button.hpp"
wxDECLARE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent);
@@ -46,6 +45,37 @@ private:
StateColor thumb_color;
};
class ModeSwitchButton : public StaticBox
{
public:
ModeSwitchButton(wxWindow* parent = nullptr, wxWindowID id = wxID_ANY);
int GetSelection() const { return m_selection; }
void SetSelection(int selection);
void SelectAndNotify(int selection);
void Rescale();
void msw_rescale() { Rescale(); }
bool Enable(bool enable = true) override;
protected:
void doRender(wxDC& dc) override;
private:
void mouseDown(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void mouseCaptureLost(wxMouseCaptureLostEvent& event);
int hit_test_selection(const wxPoint& point) const;
wxRect thumb_rect_for(int selection) const;
void update_tooltip();
private:
int m_selection { 0 };
bool m_pressed { false };
wxString m_tooltips[3];
};
class SwitchBoard : public wxWindow
{
public:
@@ -62,8 +92,8 @@ public:
void* client_data = nullptr;/*MachineObject* in StatusPanel*/
public:
void Enable();
void Disable();
bool Enable(bool enable = true) override;
bool Disable() { return Enable(false); }
bool IsEnabled(){return is_enable;};
void SetClientData(void* data) { client_data = data; };

View File

@@ -413,15 +413,6 @@ int em_unit(wxWindow* win)
return Slic3r::GUI::wxGetApp().em_unit();
}
int mode_icon_px_size()
{
#ifdef __APPLE__
return 10;
#else
return 12;
#endif
}
wxBitmap create_menu_bitmap(const std::string& bmp_name)
{
return create_scaled_bitmap(bmp_name, nullptr, 16, false, "", true);
@@ -895,141 +886,6 @@ void LockButton::update_button_bitmaps()
// ----------------------------------------------------------------------------
// ModeButton
// ----------------------------------------------------------------------------
ModeButton::ModeButton( wxWindow * parent,
wxWindowID id,
const std::string& icon_name /* = ""*/,
const wxString& mode /* = wxEmptyString*/,
const wxSize& size /* = wxDefaultSize*/,
const wxPoint& pos /* = wxDefaultPosition*/) :
ScalableButton(parent, id, icon_name, mode, size, pos, wxBU_EXACTFIT)
{
Init(mode);
}
ModeButton::ModeButton( wxWindow* parent,
const wxString& mode/* = wxEmptyString*/,
const std::string& icon_name/* = ""*/,
int px_cnt/* = 16*/) :
ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, icon_name, px_cnt), mode, wxBU_EXACTFIT)
{
Init(mode);
}
void ModeButton::Init(const wxString &mode)
{
std::string mode_str = std::string(mode.ToUTF8());
//m_tt_focused = Slic3r::GUI::from_u8((boost::format(_utf8(L("Switch to the %s mode"))) % mode_str).str());
//m_tt_selected = Slic3r::GUI::from_u8((boost::format(_utf8(L("Current mode is %s"))) % mode_str).str());
SetBitmapMargins(3, 0);
//button events
Bind(wxEVT_BUTTON, &ModeButton::OnButton, this);
Bind(wxEVT_ENTER_WINDOW, &ModeButton::OnEnterBtn, this);
Bind(wxEVT_LEAVE_WINDOW, &ModeButton::OnLeaveBtn, this);
}
void ModeButton::OnButton(wxCommandEvent& event)
{
m_is_selected = true;
focus_button(m_is_selected);
event.Skip();
}
void ModeButton::SetState(const bool state)
{
m_is_selected = state;
focus_button(m_is_selected);
SetToolTip(state ? m_tt_selected : m_tt_focused);
}
void ModeButton::focus_button(const bool focus)
{
const wxFont& new_font = focus ?
Slic3r::GUI::wxGetApp().bold_font() :
Slic3r::GUI::wxGetApp().normal_font();
SetFont(new_font);
#ifdef _WIN32
GetParent()->Refresh(); // force redraw a background of the selected mode button
#else
SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT :
#if defined (__linux__) && defined (__WXGTK3__)
wxSYS_COLOUR_GRAYTEXT
#elif defined (__linux__) && defined (__WXGTK2__)
wxSYS_COLOUR_BTNTEXT
#else
wxSYS_COLOUR_BTNSHADOW
#endif
));
#endif /* no _WIN32 */
Refresh();
Update();
}
// ----------------------------------------------------------------------------
// ModeSizer
// ----------------------------------------------------------------------------
ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 0*/) :
wxFlexGridSizer(3, 0, hgap),
m_parent(parent),
m_hgap_unscaled((double)(hgap)/em_unit(parent))
{
SetFlexibleDirection(wxHORIZONTAL);
std::vector < std::pair < wxString, std::string >> buttons = {
//{_(L("Simple")), "mode_simple"},
//{_(L("Advanced")), "mode_advanced"},
//{_CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), "mode_advanced"}
};
auto modebtnfn = [](wxCommandEvent &event, int mode_id) {
Slic3r::GUI::wxGetApp().save_mode(mode_id);
event.Skip();
};
m_mode_btns.reserve(3);
for (const auto& button : buttons) {
m_mode_btns.push_back(new ModeButton(parent, button.first, button.second, mode_icon_px_size()));
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
Add(m_mode_btns.back());
}
}
void ModeSizer::SetMode(const int mode)
{
for (size_t m = 0; m < m_mode_btns.size(); m++)
m_mode_btns[m]->SetState(int(m) == mode);
}
void ModeSizer::set_items_flag(int flag)
{
for (wxSizerItem* item : this->GetChildren())
item->SetFlag(flag);
}
void ModeSizer::set_items_border(int border)
{
for (wxSizerItem* item : this->GetChildren())
item->SetBorder(border);
}
void ModeSizer::msw_rescale()
{
this->SetHGap(std::lround(m_hgap_unscaled * em_unit(m_parent)));
for (size_t m = 0; m < m_mode_btns.size(); m++)
m_mode_btns[m]->msw_rescale();
}
// ----------------------------------------------------------------------------
// MenuWithSeparators
// ----------------------------------------------------------------------------

View File

@@ -52,7 +52,6 @@ class wxDialog;
void edit_tooltip(wxString& tooltip);
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
int em_unit(wxWindow* win);
int mode_icon_px_size();
wxBitmap create_menu_bitmap(const std::string& bmp_name);
@@ -285,76 +284,6 @@ private:
};
// ----------------------------------------------------------------------------
// ModeButton
// ----------------------------------------------------------------------------
class ModeButton : public ScalableButton
{
public:
ModeButton(
wxWindow* parent,
wxWindowID id,
const std::string& icon_name = "",
const wxString& mode = wxEmptyString,
const wxSize& size = wxDefaultSize,
const wxPoint& pos = wxDefaultPosition);
ModeButton(
wxWindow* parent,
const wxString& mode = wxEmptyString,
const std::string& icon_name = "",
int px_cnt = 16);
~ModeButton() {}
void Init(const wxString& mode);
void OnButton(wxCommandEvent& event);
void OnEnterBtn(wxMouseEvent& event) { focus_button(true); event.Skip(); }
void OnLeaveBtn(wxMouseEvent& event) { focus_button(m_is_selected); event.Skip(); }
void SetState(const bool state);
bool is_selected() { return m_is_selected; }
protected:
void focus_button(const bool focus);
private:
bool m_is_selected = false;
wxString m_tt_selected;
wxString m_tt_focused;
};
// ----------------------------------------------------------------------------
// ModeSizer
// ----------------------------------------------------------------------------
class ModeSizer : public wxFlexGridSizer
{
public:
ModeSizer( wxWindow *parent, int hgap = 0);
~ModeSizer() {}
void SetMode(const /*ConfigOptionMode*/int mode);
void set_items_flag(int flag);
void set_items_border(int border);
void msw_rescale();
const std::vector<ModeButton*>& get_btns() { return m_mode_btns; }
private:
std::vector<ModeButton*> m_mode_btns;
wxWindow* m_parent {nullptr};
double m_hgap_unscaled;
};
// ----------------------------------------------------------------------------
// MenuWithSeparators
// ----------------------------------------------------------------------------