From aff3864200e1fb72090427eedbe1f331769e6e58 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 18 Oct 2023 14:46:08 +0200 Subject: [PATCH 01/11] Added some widgets from BambuStudio(http://github.com/bambulab) from the state of https://github.com/bambulab/BambuStudio/tree/96707fc4b4b40c30b7e5610d2489ef283fe952a4 Thanks https://github.com/bambu123, https://github.com/lanewei120 and https://github.com/walterwongbbl for implementation. --- src/slic3r/GUI/Widgets/Button.cpp | 303 +++++++++++++++ src/slic3r/GUI/Widgets/Button.hpp | 78 ++++ src/slic3r/GUI/Widgets/CheckBox.cpp | 125 +++++++ src/slic3r/GUI/Widgets/CheckBox.hpp | 55 +++ src/slic3r/GUI/Widgets/ComboBox.cpp | 301 +++++++++++++++ src/slic3r/GUI/Widgets/ComboBox.hpp | 92 +++++ src/slic3r/GUI/Widgets/DropDown.cpp | 472 ++++++++++++++++++++++++ src/slic3r/GUI/Widgets/DropDown.hpp | 111 ++++++ src/slic3r/GUI/Widgets/Label.cpp | 124 +++++++ src/slic3r/GUI/Widgets/Label.hpp | 49 +++ src/slic3r/GUI/Widgets/SpinInput.cpp | 323 ++++++++++++++++ src/slic3r/GUI/Widgets/SpinInput.hpp | 96 +++++ src/slic3r/GUI/Widgets/StateColor.cpp | 93 +++++ src/slic3r/GUI/Widgets/StateColor.hpp | 84 +++++ src/slic3r/GUI/Widgets/StateHandler.cpp | 122 ++++++ src/slic3r/GUI/Widgets/StateHandler.hpp | 61 +++ src/slic3r/GUI/Widgets/StaticBox.cpp | 214 +++++++++++ src/slic3r/GUI/Widgets/StaticBox.hpp | 62 ++++ src/slic3r/GUI/Widgets/SwitchButton.cpp | 134 +++++++ src/slic3r/GUI/Widgets/SwitchButton.hpp | 40 ++ src/slic3r/GUI/Widgets/TextInput.cpp | 230 ++++++++++++ src/slic3r/GUI/Widgets/TextInput.hpp | 77 ++++ 22 files changed, 3246 insertions(+) create mode 100644 src/slic3r/GUI/Widgets/Button.cpp create mode 100644 src/slic3r/GUI/Widgets/Button.hpp create mode 100644 src/slic3r/GUI/Widgets/CheckBox.cpp create mode 100644 src/slic3r/GUI/Widgets/CheckBox.hpp create mode 100644 src/slic3r/GUI/Widgets/ComboBox.cpp create mode 100644 src/slic3r/GUI/Widgets/ComboBox.hpp create mode 100644 src/slic3r/GUI/Widgets/DropDown.cpp create mode 100644 src/slic3r/GUI/Widgets/DropDown.hpp create mode 100644 src/slic3r/GUI/Widgets/Label.cpp create mode 100644 src/slic3r/GUI/Widgets/Label.hpp create mode 100644 src/slic3r/GUI/Widgets/SpinInput.cpp create mode 100644 src/slic3r/GUI/Widgets/SpinInput.hpp create mode 100644 src/slic3r/GUI/Widgets/StateColor.cpp create mode 100644 src/slic3r/GUI/Widgets/StateColor.hpp create mode 100644 src/slic3r/GUI/Widgets/StateHandler.cpp create mode 100644 src/slic3r/GUI/Widgets/StateHandler.hpp create mode 100644 src/slic3r/GUI/Widgets/StaticBox.cpp create mode 100644 src/slic3r/GUI/Widgets/StaticBox.hpp create mode 100644 src/slic3r/GUI/Widgets/SwitchButton.cpp create mode 100644 src/slic3r/GUI/Widgets/SwitchButton.hpp create mode 100644 src/slic3r/GUI/Widgets/TextInput.cpp create mode 100644 src/slic3r/GUI/Widgets/TextInput.hpp diff --git a/src/slic3r/GUI/Widgets/Button.cpp b/src/slic3r/GUI/Widgets/Button.cpp new file mode 100644 index 0000000000..fa1dc15ee2 --- /dev/null +++ b/src/slic3r/GUI/Widgets/Button.cpp @@ -0,0 +1,303 @@ +#include "Button.hpp" +#include "Label.hpp" + +#include + +BEGIN_EVENT_TABLE(Button, StaticBox) + +EVT_LEFT_DOWN(Button::mouseDown) +EVT_LEFT_UP(Button::mouseReleased) +EVT_MOUSE_CAPTURE_LOST(Button::mouseCaptureLost) +EVT_KEY_DOWN(Button::keyDownUp) +EVT_KEY_UP(Button::keyDownUp) + +// catch paint events +EVT_PAINT(Button::paintEvent) + +END_EVENT_TABLE() + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +Button::Button() + : paddingSize(10, 8) +{ + background_color = StateColor( + std::make_pair(0xF0F0F0, (int) StateColor::Disabled), + std::make_pair(0x37EE7C, (int) StateColor::Hovered | StateColor::Checked), + std::make_pair(0x00AE42, (int) StateColor::Checked), + std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered), + std::make_pair(*wxWHITE, (int) StateColor::Normal)); + text_color = StateColor( + std::make_pair(*wxLIGHT_GREY, (int) StateColor::Disabled), + std::make_pair(*wxBLACK, (int) StateColor::Normal)); +} + +Button::Button(wxWindow* parent, wxString text, wxString icon, long style, int iconSize) + : Button() +{ + Create(parent, text, icon, style, iconSize); +} + +bool Button::Create(wxWindow* parent, wxString text, wxString icon, long style, int iconSize) +{ + StaticBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style); + state_handler.attach({&text_color}); + state_handler.update_binds(); + //BBS set default font + SetFont(Label::Body_14); + wxWindow::SetLabel(text); + if (!icon.IsEmpty()) { + //BBS set button icon default size to 20 + this->active_icon = ScalableBitmap(this, icon.ToStdString(), iconSize > 0 ? iconSize : 20); + } + messureSize(); + return true; +} + +void Button::SetLabel(const wxString& label) +{ + wxWindow::SetLabel(label); + messureSize(); + Refresh(); +} + +void Button::SetIcon(const wxString& icon) +{ + if (!icon.IsEmpty()) { + //BBS set button icon default size to 20 + this->active_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt()); + } + else + { + this->active_icon = ScalableBitmap(); + } + Refresh(); +} + +void Button::SetInactiveIcon(const wxString &icon) +{ + if (!icon.IsEmpty()) { + // BBS set button icon default size to 20 + this->inactive_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt()); + } else { + this->inactive_icon = ScalableBitmap(); + } + Refresh(); +} + +void Button::SetMinSize(const wxSize& size) +{ + minSize = size; + messureSize(); +} + +void Button::SetPaddingSize(const wxSize& size) +{ + paddingSize = size; + messureSize(); +} + +void Button::SetTextColor(StateColor const& color) +{ + text_color = color; + state_handler.update_binds(); + Refresh(); +} + +void Button::SetTextColorNormal(wxColor const &color) +{ + text_color.setColorForStates(color, 0); + Refresh(); +} + +bool Button::Enable(bool enable) +{ + bool result = wxWindow::Enable(enable); + if (result) { + wxCommandEvent e(EVT_ENABLE_CHANGED); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + } + return result; +} + +void Button::SetCanFocus(bool canFocus) { this->canFocus = canFocus; } + +void Button::Rescale() +{ + if (this->active_icon.bmp().IsOk()) + this->active_icon.msw_rescale(); + + if (this->inactive_icon.bmp().IsOk()) + this->inactive_icon.msw_rescale(); + + messureSize(); +} + +void Button::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void Button::render(wxDC& dc) +{ + StaticBox::render(dc); + int states = state_handler.states(); + wxSize size = GetSize(); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + // calc content size + wxSize szIcon; + wxSize szContent = textSize; + + ScalableBitmap icon; + if (m_selected || ((states & (int)StateColor::State::Hovered) != 0)) + icon = active_icon; + else + icon = inactive_icon; + int padding = 5; + if (icon.bmp().IsOk()) { + if (szContent.y > 0) { + //BBS norrow size between text and icon + szContent.x += padding; + } + szIcon = icon.GetBmpSize(); + szContent.x += szIcon.x; + if (szIcon.y > szContent.y) + szContent.y = szIcon.y; + if (szContent.x > size.x) { + int d = std::min(padding, szContent.x - size.x); + padding -= d; + szContent.x -= d; + } + } + // move to center + wxRect rcContent = { {0, 0}, size }; + wxSize offset = (size - szContent) / 2; + if (offset.x < 0) offset.x = 0; + rcContent.Deflate(offset.x, offset.y); + // start draw + wxPoint pt = rcContent.GetLeftTop(); + if (icon.bmp().IsOk()) { + pt.y += (rcContent.height - szIcon.y) / 2; + dc.DrawBitmap(icon.bmp(), pt); + //BBS norrow size between text and icon + pt.x += szIcon.x + padding; + pt.y = rcContent.y; + } + auto text = GetLabel(); + if (!text.IsEmpty()) { + if (pt.x + textSize.x > size.x) + text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x); + pt.y += (rcContent.height - textSize.y) / 2; + dc.SetFont(GetFont()); + dc.SetTextForeground(text_color.colorForStates(states)); + dc.DrawText(text, pt); + } +} + +void Button::messureSize() +{ + wxClientDC dc(this); + textSize = dc.GetTextExtent(GetLabel()); + if (minSize.GetWidth() > 0) { + wxWindow::SetMinSize(minSize); + return; + } + wxSize szContent = textSize; + if (this->active_icon.bmp().IsOk()) { + if (szContent.y > 0) { + //BBS norrow size between text and icon + szContent.x += 5; + } + wxSize szIcon = this->active_icon.GetBmpSize(); + szContent.x += szIcon.x; + if (szIcon.y > szContent.y) + szContent.y = szIcon.y; + } + wxSize size = szContent + paddingSize * 2; + if (minSize.GetHeight() > 0) + size.SetHeight(minSize.GetHeight()); + wxWindow::SetMinSize(size); +} + +void Button::mouseDown(wxMouseEvent& event) +{ + event.Skip(); + pressedDown = true; + if (canFocus) + SetFocus(); + CaptureMouse(); +} + +void Button::mouseReleased(wxMouseEvent& event) +{ + event.Skip(); + if (pressedDown) { + pressedDown = false; + if (HasCapture()) + ReleaseMouse(); + if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition())) + sendButtonEvent(); + } +} + +void Button::mouseCaptureLost(wxMouseCaptureLostEvent &event) +{ + wxMouseEvent evt; + mouseReleased(evt); +} + +void Button::keyDownUp(wxKeyEvent &event) +{ + if (event.GetKeyCode() == WXK_SPACE || event.GetKeyCode() == WXK_RETURN) { + wxMouseEvent evt(event.GetEventType() == wxEVT_KEY_UP ? wxEVT_LEFT_UP : wxEVT_LEFT_DOWN); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + return; + } + if (event.GetEventType() == wxEVT_KEY_DOWN && + (event.GetKeyCode() == WXK_TAB || event.GetKeyCode() == WXK_LEFT || event.GetKeyCode() == WXK_RIGHT + || event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_DOWN)) + HandleAsNavigationKey(event); + else + event.Skip(); +} + +void Button::sendButtonEvent() +{ + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +#ifdef __WIN32__ + +WXLRESULT Button::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + if (nMsg == WM_GETDLGCODE) { return DLGC_WANTMESSAGE; } + if (nMsg == WM_KEYDOWN) { + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam)); + switch (wParam) { + case WXK_RETURN: { // WXK_RETURN key is handled by default button + GetEventHandler()->ProcessEvent(event); + return 0; + } + } + } + return wxWindow::MSWWindowProc(nMsg, wParam, lParam); +} + +#endif + +bool Button::AcceptsFocus() const { return canFocus; } diff --git a/src/slic3r/GUI/Widgets/Button.hpp b/src/slic3r/GUI/Widgets/Button.hpp new file mode 100644 index 0000000000..43aac6b9fb --- /dev/null +++ b/src/slic3r/GUI/Widgets/Button.hpp @@ -0,0 +1,78 @@ +#ifndef slic3r_GUI_Button_hpp_ +#define slic3r_GUI_Button_hpp_ + +#include "../wxExtensions.hpp" +#include "StaticBox.hpp" + +class Button : public StaticBox +{ + wxSize textSize; + wxSize minSize; // set by outer + wxSize paddingSize; + ScalableBitmap active_icon; + ScalableBitmap inactive_icon; + + StateColor text_color; + + bool pressedDown = false; + bool m_selected = true; + bool canFocus = true; + + static const int buttonWidth = 200; + static const int buttonHeight = 50; + +public: + Button(); + + Button(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0); + + bool Create(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0); + + void SetLabel(const wxString& label) override; + + void SetIcon(const wxString& icon); + + void SetInactiveIcon(const wxString& icon); + + void SetMinSize(const wxSize& size) override; + + void SetPaddingSize(const wxSize& size); + + void SetTextColor(StateColor const &color); + + void SetTextColorNormal(wxColor const &color); + + void SetSelected(bool selected = true) { m_selected = selected; } + + bool Enable(bool enable = true) override; + + void SetCanFocus(bool canFocus) override; + + void Rescale(); + +protected: +#ifdef __WIN32__ + WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override; +#endif + + bool AcceptsFocus() const override; + +private: + void paintEvent(wxPaintEvent& evt); + + void render(wxDC& dc); + + void messureSize(); + + // some useful events + void mouseDown(wxMouseEvent& event); + void mouseReleased(wxMouseEvent& event); + void mouseCaptureLost(wxMouseCaptureLostEvent &event); + void keyDownUp(wxKeyEvent &event); + + void sendButtonEvent(); + + DECLARE_EVENT_TABLE() +}; + +#endif // !slic3r_GUI_Button_hpp_ diff --git a/src/slic3r/GUI/Widgets/CheckBox.cpp b/src/slic3r/GUI/Widgets/CheckBox.cpp new file mode 100644 index 0000000000..4ca1ca5ba0 --- /dev/null +++ b/src/slic3r/GUI/Widgets/CheckBox.cpp @@ -0,0 +1,125 @@ +#include "CheckBox.hpp" + +#include "../wxExtensions.hpp" + +CheckBox::CheckBox(wxWindow* parent) + : wxBitmapToggleButton(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE) + , m_on(this, "check_on", 18) + , m_half(this, "check_half", 18) + , m_off(this, "check_off", 18) + , m_on_disabled(this, "check_on_disabled", 18) + , m_half_disabled(this, "check_half_disabled", 18) + , m_off_disabled(this, "check_off_disabled", 18) + , m_on_focused(this, "check_on_focused", 18) + , m_half_focused(this, "check_half_focused", 18) + , m_off_focused(this, "check_off_focused", 18) +{ + //SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); + if (parent) + SetBackgroundColour(parent->GetBackgroundColour()); + Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { m_half_checked = false; update(); e.Skip(); }); +#ifdef __WXOSX__ // State not fully implement on MacOS + Bind(wxEVT_SET_FOCUS, &CheckBox::updateBitmap, this); + Bind(wxEVT_KILL_FOCUS, &CheckBox::updateBitmap, this); + Bind(wxEVT_ENTER_WINDOW, &CheckBox::updateBitmap, this); + Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this); +#endif + SetSize(m_on.GetBmpSize()); + SetMinSize(m_on.GetBmpSize()); + update(); +} + +void CheckBox::SetValue(bool value) +{ + wxBitmapToggleButton::SetValue(value); + update(); +} + +void CheckBox::SetHalfChecked(bool value) +{ + m_half_checked = value; + update(); +} + +void CheckBox::Rescale() +{ + m_on.msw_rescale(); + m_half.msw_rescale(); + m_off.msw_rescale(); + m_on_disabled.msw_rescale(); + m_half_disabled.msw_rescale(); + m_off_disabled.msw_rescale(); + m_on_focused.msw_rescale(); + m_half_focused.msw_rescale(); + m_off_focused.msw_rescale(); + SetSize(m_on.GetBmpSize()); + update(); +} + +void CheckBox::update() +{ + SetBitmapLabel((m_half_checked ? m_half : GetValue() ? m_on : m_off).bmp()); + SetBitmapDisabled((m_half_checked ? m_half_disabled : GetValue() ? m_on_disabled : m_off_disabled).bmp()); +#ifdef __WXMSW__ + SetBitmapFocus((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp()); +#endif + SetBitmapCurrent((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp()); +#ifdef __WXOSX__ + wxCommandEvent e(wxEVT_UPDATE_UI); + updateBitmap(e); +#endif +} + +#ifdef __WXMSW__ + +CheckBox::State CheckBox::GetNormalState() const { return State_Normal; } + +#endif + + +#ifdef __WXOSX__ + +bool CheckBox::Enable(bool enable) +{ + bool result = wxBitmapToggleButton::Enable(enable); + if (result) { + m_disable = !enable; + wxCommandEvent e(wxEVT_ACTIVATE); + updateBitmap(e); + } + return result; +} + +wxBitmap CheckBox::DoGetBitmap(State which) const +{ + if (m_disable) { + return wxBitmapToggleButton::DoGetBitmap(State_Disabled); + } + if (m_focus) { + return wxBitmapToggleButton::DoGetBitmap(State_Current); + } + return wxBitmapToggleButton::DoGetBitmap(which); +} + +void CheckBox::updateBitmap(wxEvent & evt) +{ + evt.Skip(); + if (evt.GetEventType() == wxEVT_ENTER_WINDOW) { + m_hover = true; + } else if (evt.GetEventType() == wxEVT_LEAVE_WINDOW) { + m_hover = false; + } else { + if (evt.GetEventType() == wxEVT_SET_FOCUS) { + m_focus = true; + } else if (evt.GetEventType() == wxEVT_KILL_FOCUS) { + m_focus = false; + } + wxMouseEvent e; + if (m_hover) + OnEnterWindow(e); + else + OnLeaveWindow(e); + } +} + +#endif diff --git a/src/slic3r/GUI/Widgets/CheckBox.hpp b/src/slic3r/GUI/Widgets/CheckBox.hpp new file mode 100644 index 0000000000..53c41b6470 --- /dev/null +++ b/src/slic3r/GUI/Widgets/CheckBox.hpp @@ -0,0 +1,55 @@ +#ifndef slic3r_GUI_CheckBox_hpp_ +#define slic3r_GUI_CheckBox_hpp_ + +#include "../wxExtensions.hpp" + +#include + +class CheckBox : public wxBitmapToggleButton +{ +public: + CheckBox(wxWindow * parent = NULL); + +public: + void SetValue(bool value) override; + + void SetHalfChecked(bool value = true); + + void Rescale(); + +#ifdef __WXOSX__ + virtual bool Enable(bool enable = true) wxOVERRIDE; +#endif + +protected: +#ifdef __WXMSW__ + virtual State GetNormalState() const wxOVERRIDE; +#endif + +#ifdef __WXOSX__ + virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE; + + void updateBitmap(wxEvent & evt); + + bool m_disable = false; + bool m_hover = false; + bool m_focus = false; +#endif + +private: + void update(); + +private: + ScalableBitmap m_on; + ScalableBitmap m_half; + ScalableBitmap m_off; + ScalableBitmap m_on_disabled; + ScalableBitmap m_half_disabled; + ScalableBitmap m_off_disabled; + ScalableBitmap m_on_focused; + ScalableBitmap m_half_focused; + ScalableBitmap m_off_focused; + bool m_half_checked = false; +}; + +#endif // !slic3r_GUI_CheckBox_hpp_ diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp new file mode 100644 index 0000000000..01d7d9614c --- /dev/null +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -0,0 +1,301 @@ +#include "ComboBox.hpp" +#include "Label.hpp" + +#include + +BEGIN_EVENT_TABLE(ComboBox, TextInput) + +EVT_LEFT_DOWN(ComboBox::mouseDown) +//EVT_MOUSEWHEEL(ComboBox::mouseWheelMoved) +EVT_KEY_DOWN(ComboBox::keyDown) + +// catch paint events +END_EVENT_TABLE() + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +ComboBox::ComboBox(wxWindow * parent, + wxWindowID id, + const wxString &value, + const wxPoint & pos, + const wxSize & size, + int n, + const wxString choices[], + long style) + : drop(texts, icons) +{ + if (style & wxCB_READONLY) + style |= wxRIGHT; + text_off = style & CB_NO_TEXT; + TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size, + style | wxTE_PROCESS_ENTER); + drop.Create(this, style & DD_STYLE_MASK); + + if (style & wxCB_READONLY) { + GetTextCtrl()->Hide(); + TextInput::SetFont(Label::Body_14); + TextInput::SetBorderColor(StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), + std::make_pair(0x00AE42, (int) StateColor::Hovered), + std::make_pair(0xDBDBDB, (int) StateColor::Normal))); + TextInput::SetBackgroundColor(StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), + std::make_pair(0xEDFAF2, (int) StateColor::Focused), + std::make_pair(*wxWHITE, (int) StateColor::Normal))); + TextInput::SetLabelColor(StateColor(std::make_pair(0x909090, (int) StateColor::Disabled), + std::make_pair(0x262E30, (int) StateColor::Normal))); + } else { + GetTextCtrl()->Bind(wxEVT_KEY_DOWN, &ComboBox::keyDown, this); + } + drop.Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { + SetSelection(e.GetInt()); + e.SetEventObject(this); + e.SetId(GetId()); + GetEventHandler()->ProcessEvent(e); + }); + drop.Bind(EVT_DISMISS, [this](auto &) { + drop_down = false; + wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP); + GetEventHandler()->ProcessEvent(e); + }); + for (int i = 0; i < n; ++i) Append(choices[i]); +} + +int ComboBox::GetSelection() const { return drop.GetSelection(); } + +void ComboBox::SetSelection(int n) +{ + drop.SetSelection(n); + SetLabel(drop.GetValue()); + if (drop.selection >= 0) + SetIcon(icons[drop.selection]); +} + +void ComboBox::Rescale() +{ + TextInput::Rescale(); + drop.Rescale(); +} + +wxString ComboBox::GetValue() const +{ + return drop.GetSelection() >= 0 ? drop.GetValue() : GetLabel(); +} + +void ComboBox::SetValue(const wxString &value) +{ + drop.SetValue(value); + SetLabel(value); + if (drop.selection >= 0) + SetIcon(icons[drop.selection]); +} + +void ComboBox::SetLabel(const wxString &value) +{ + if (GetTextCtrl()->IsShown() || text_off) + GetTextCtrl()->SetValue(value); + else + TextInput::SetLabel(value); +} + +wxString ComboBox::GetLabel() const +{ + if (GetTextCtrl()->IsShown() || text_off) + return GetTextCtrl()->GetValue(); + else + return TextInput::GetLabel(); +} + +void ComboBox::SetTextLabel(const wxString& label) +{ + TextInput::SetLabel(label); +} + +wxString ComboBox::GetTextLabel() const +{ + return TextInput::GetLabel(); +} + +bool ComboBox::SetFont(wxFont const& font) +{ + if (GetTextCtrl() && GetTextCtrl()->IsShown()) + return GetTextCtrl()->SetFont(font); + else + return TextInput::SetFont(font); +} + +int ComboBox::Append(const wxString &item, const wxBitmap &bitmap) +{ + return Append(item, bitmap, nullptr); +} + +int ComboBox::Append(const wxString &item, + const wxBitmap &bitmap, + void * clientData) +{ + texts.push_back(item); + icons.push_back(bitmap); + datas.push_back(clientData); + types.push_back(wxClientData_None); + drop.Invalidate(); + return texts.size() - 1; +} + +void ComboBox::DoClear() +{ + texts.clear(); + icons.clear(); + datas.clear(); + types.clear(); + drop.Invalidate(true); +} + +void ComboBox::DoDeleteOneItem(unsigned int pos) +{ + if (pos >= texts.size()) return; + texts.erase(texts.begin() + pos); + icons.erase(icons.begin() + pos); + datas.erase(datas.begin() + pos); + types.erase(types.begin() + pos); + drop.Invalidate(true); +} + +unsigned int ComboBox::GetCount() const { return texts.size(); } + +wxString ComboBox::GetString(unsigned int n) const +{ + return n < texts.size() ? texts[n] : wxString{}; +} + +void ComboBox::SetString(unsigned int n, wxString const &value) +{ + if (n >= texts.size()) return; + texts[n] = value; + drop.Invalidate(); + if (n == drop.GetSelection()) SetLabel(value); +} + +wxBitmap ComboBox::GetItemBitmap(unsigned int n) { return icons[n]; } + +int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, + unsigned int pos, + void ** clientData, + wxClientDataType type) +{ + if (pos > texts.size()) return -1; + for (int i = 0; i < items.GetCount(); ++i) { + texts.insert(texts.begin() + pos, items[i]); + icons.insert(icons.begin() + pos, wxNullBitmap); + datas.insert(datas.begin() + pos, clientData ? clientData[i] : NULL); + types.insert(types.begin() + pos, type); + ++pos; + } + drop.Invalidate(true); + return pos - 1; +} + +void *ComboBox::DoGetItemClientData(unsigned int n) const { return n < texts.size() ? datas[n] : NULL; } + +void ComboBox::DoSetItemClientData(unsigned int n, void *data) +{ + if (n < texts.size()) + datas[n] = data; +} + +void ComboBox::mouseDown(wxMouseEvent &event) +{ + SetFocus(); + if (drop_down) { + drop.Hide(); + } else if (drop.HasDismissLongTime()) { + drop.autoPosition(); + drop_down = true; + drop.Popup(); + wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN); + GetEventHandler()->ProcessEvent(e); + } +} + +void ComboBox::mouseWheelMoved(wxMouseEvent &event) +{ + event.Skip(); + if (drop_down) return; + auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? -1 : 1; + unsigned int n = GetSelection() + delta; + if (n < GetCount()) { + SetSelection((int) n); + sendComboBoxEvent(); + } +} + +void ComboBox::keyDown(wxKeyEvent& event) +{ + switch (event.GetKeyCode()) { + case WXK_RETURN: + case WXK_SPACE: + if (drop_down) { + drop.DismissAndNotify(); + } else if (drop.HasDismissLongTime()) { + drop.autoPosition(); + drop_down = true; + drop.Popup(); + wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN); + GetEventHandler()->ProcessEvent(e); + } + break; + case WXK_UP: + case WXK_DOWN: + case WXK_LEFT: + case WXK_RIGHT: + if ((event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_LEFT) && GetSelection() > 0) { + SetSelection(GetSelection() - 1); + } else if ((event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_RIGHT) && GetSelection() + 1 < texts.size()) { + SetSelection(GetSelection() + 1); + } else { + break; + } + { + wxCommandEvent e(wxEVT_COMBOBOX); + e.SetEventObject(this); + e.SetId(GetId()); + e.SetInt(GetSelection()); + GetEventHandler()->ProcessEvent(e); + } + break; + case WXK_TAB: + HandleAsNavigationKey(event); + break; + default: + event.Skip(); + break; + } +} + +void ComboBox::OnEdit() +{ + auto value = GetTextCtrl()->GetValue(); + SetValue(value); +} + +#ifdef __WIN32__ + +WXLRESULT ComboBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + if (nMsg == WM_GETDLGCODE) { + return DLGC_WANTALLKEYS; + } + return TextInput::MSWWindowProc(nMsg, wParam, lParam); +} + +#endif + +void ComboBox::sendComboBoxEvent() +{ + wxCommandEvent event(wxEVT_COMBOBOX, GetId()); + event.SetEventObject(this); + event.SetInt(drop.GetSelection()); + event.SetString(drop.GetValue()); + GetEventHandler()->ProcessEvent(event); +} diff --git a/src/slic3r/GUI/Widgets/ComboBox.hpp b/src/slic3r/GUI/Widgets/ComboBox.hpp new file mode 100644 index 0000000000..0a8e018dce --- /dev/null +++ b/src/slic3r/GUI/Widgets/ComboBox.hpp @@ -0,0 +1,92 @@ +#ifndef slic3r_GUI_ComboBox_hpp_ +#define slic3r_GUI_ComboBox_hpp_ + +#include "TextInput.hpp" +#include "DropDown.hpp" + +#define CB_NO_DROP_ICON DD_NO_CHECK_ICON +#define CB_NO_TEXT DD_NO_TEXT + +class ComboBox : public wxWindowWithItems +{ + std::vector texts; + std::vector icons; + std::vector datas; + std::vector types; + + DropDown drop; + bool drop_down = false; + bool text_off = false; + +public: + ComboBox(wxWindow * parent, + wxWindowID id, + const wxString &value = wxEmptyString, + const wxPoint & pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + int n = 0, + const wxString choices[] = NULL, + long style = 0); + + DropDown & GetDropDown() { return drop; } + + virtual bool SetFont(wxFont const & font) override; + +public: + int Append(const wxString &item, const wxBitmap &bitmap = wxNullBitmap); + + int Append(const wxString &item, const wxBitmap &bitmap, void *clientData); + + unsigned int GetCount() const override; + + int GetSelection() const override; + + void SetSelection(int n) override; + + virtual void Rescale() override; + + wxString GetValue() const; + void SetValue(const wxString &value); + + void SetLabel(const wxString &label) override; + wxString GetLabel() const override; + + void SetTextLabel(const wxString &label); + wxString GetTextLabel() const; + + wxString GetString(unsigned int n) const override; + void SetString(unsigned int n, wxString const &value) override; + + wxBitmap GetItemBitmap(unsigned int n); + +protected: + virtual int DoInsertItems(const wxArrayStringsAdapter &items, + unsigned int pos, + void ** clientData, + wxClientDataType type) override; + virtual void DoClear() override; + + void DoDeleteOneItem(unsigned int pos) override; + + void *DoGetItemClientData(unsigned int n) const override; + void DoSetItemClientData(unsigned int n, void *data) override; + + void OnEdit() override; + +#ifdef __WIN32__ + WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override; +#endif + +private: + + // some useful events + void mouseDown(wxMouseEvent &event); + void mouseWheelMoved(wxMouseEvent &event); + void keyDown(wxKeyEvent &event); + + void sendComboBoxEvent(); + + DECLARE_EVENT_TABLE() +}; + +#endif // !slic3r_GUI_ComboBox_hpp_ diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp new file mode 100644 index 0000000000..c0074b531d --- /dev/null +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -0,0 +1,472 @@ +#include "DropDown.hpp" +#include "Label.hpp" + +#include + +wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent); + +BEGIN_EVENT_TABLE(DropDown, wxPopupTransientWindow) + +EVT_LEFT_DOWN(DropDown::mouseDown) +EVT_LEFT_UP(DropDown::mouseReleased) +EVT_MOUSE_CAPTURE_LOST(DropDown::mouseCaptureLost) +EVT_MOTION(DropDown::mouseMove) +EVT_MOUSEWHEEL(DropDown::mouseWheelMoved) + +// catch paint events +EVT_PAINT(DropDown::paintEvent) + +END_EVENT_TABLE() + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +DropDown::DropDown(std::vector &texts, + std::vector &icons) + : texts(texts) + , icons(icons) + , state_handler(this) + , border_color(0xDBDBDB) + , text_color(0x363636) + , selector_border_color(std::make_pair(0x00AE42, (int) StateColor::Hovered), + std::make_pair(*wxWHITE, (int) StateColor::Normal)) + , selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked), + std::make_pair(*wxWHITE, (int) StateColor::Normal)) +{ +} + +DropDown::DropDown(wxWindow * parent, + std::vector &texts, + std::vector &icons, + long style) + : DropDown(texts, icons) +{ + Create(parent, style); +} + +void DropDown::Create(wxWindow * parent, + long style) +{ + wxPopupTransientWindow::Create(parent); + SetBackgroundStyle(wxBG_STYLE_PAINT); + SetBackgroundColour(*wxWHITE); + state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color}); + state_handler.update_binds(); + if ((style & DD_NO_CHECK_ICON) == 0) + check_bitmap = ScalableBitmap(this, "checked", 16); + text_off = style & DD_NO_TEXT; + + // BBS set default font + SetFont(Label::Body_14); +#ifdef __WXOSX__ + // wxPopupTransientWindow releases mouse on idle, which may cause various problems, + // such as losting mouse move, and dismissing soon on first LEFT_DOWN event. + Bind(wxEVT_IDLE, [] (wxIdleEvent & evt) {}); +#endif +} + +void DropDown::Invalidate(bool clear) +{ + if (clear) { + selection = hover_item = -1; + offset = wxPoint(); + } + assert(selection < (int) texts.size()); + need_sync = true; +} + +void DropDown::SetSelection(int n) +{ + assert(n < (int) texts.size()); + if (n >= (int) texts.size()) + n = -1; + if (selection == n) return; + selection = n; + paintNow(); +} + +wxString DropDown::GetValue() const +{ + return selection >= 0 ? texts[selection] : wxString(); +} + +void DropDown::SetValue(const wxString &value) +{ + auto i = std::find(texts.begin(), texts.end(), value); + selection = i == texts.end() ? -1 : std::distance(texts.begin(), i); +} + +void DropDown::SetCornerRadius(double radius) +{ + this->radius = radius; + paintNow(); +} + +void DropDown::SetBorderColor(StateColor const &color) +{ + border_color = color; + state_handler.update_binds(); + paintNow(); +} + +void DropDown::SetSelectorBorderColor(StateColor const &color) +{ + selector_border_color = color; + state_handler.update_binds(); + paintNow(); +} + +void DropDown::SetTextColor(StateColor const &color) +{ + text_color = color; + state_handler.update_binds(); + paintNow(); +} + +void DropDown::SetSelectorBackgroundColor(StateColor const &color) +{ + selector_background_color = color; + state_handler.update_binds(); + paintNow(); +} + +void DropDown::SetUseContentWidth(bool use) +{ + if (use_content_width == use) + return; + use_content_width = use; + need_sync = true; + messureSize(); +} + +void DropDown::SetAlignIcon(bool align) { align_icon = align; } + +void DropDown::Rescale() +{ + need_sync = true; +} + +bool DropDown::HasDismissLongTime() +{ + auto now = boost::posix_time::microsec_clock::universal_time(); + return !IsShown() && + (now - dismissTime).total_milliseconds() >= 200; +} + +void DropDown::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxBufferedPaintDC dc(this); + render(dc); +} + +/* + * Alternatively, you can use a clientDC to paint on the panel + * at any time. Using this generally does not free you from + * catching paint events, since it is possible that e.g. the window + * manager throws away your drawing when the window comes to the + * background, and expects you will redraw it when the window comes + * back (by sending a paint event). + */ +void DropDown::paintNow() +{ + // depending on your system you may need to look at double-buffered dcs + //wxClientDC dc(this); + //render(dc); + Refresh(); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void DropDown::render(wxDC &dc) +{ + if (texts.size() == 0) return; + int states = state_handler.states(); + dc.SetPen(wxPen(border_color.colorForStates(states))); + dc.SetBrush(wxBrush(GetBackgroundColour())); + // if (GetWindowStyle() & wxBORDER_NONE) + // dc.SetPen(wxNullPen); + + // draw background + wxSize size = GetSize(); + if (radius == 0) + dc.DrawRectangle(0, 0, size.x, size.y); + else + dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius); + + // draw hover rectangle + wxRect rcContent = {{0, offset.y}, rowSize}; + if (hover_item >= 0 && (states & StateColor::Hovered)) { + rcContent.y += rowSize.y * hover_item; + if (rcContent.GetBottom() > 0 && rcContent.y < size.y) { + if (selection == hover_item) + dc.SetBrush(wxBrush(selector_background_color.colorForStates(states | StateColor::Checked))); + dc.SetPen(wxPen(selector_border_color.colorForStates(states))); + rcContent.Deflate(4, 1); + dc.DrawRectangle(rcContent); + rcContent.Inflate(4, 1); + } + rcContent.y = offset.y; + } + // draw checked rectangle + if (selection >= 0 && (selection != hover_item || (states & StateColor::Hovered) == 0)) { + rcContent.y += rowSize.y * selection; + if (rcContent.GetBottom() > 0 && rcContent.y < size.y) { + dc.SetBrush(wxBrush(selector_background_color.colorForStates(states | StateColor::Checked))); + dc.SetPen(wxPen(selector_background_color.colorForStates(states))); + rcContent.Deflate(4, 1); + dc.DrawRectangle(rcContent); + rcContent.Inflate(4, 1); + } + rcContent.y = offset.y; + } + dc.SetBrush(*wxTRANSPARENT_BRUSH); + { + wxSize offset = (rowSize - textSize) / 2; + rcContent.Deflate(0, offset.y); + } + + // draw position bar + if (rowSize.y * texts.size() > size.y) { + int height = rowSize.y * texts.size(); + wxRect rect = {size.x - 6, -offset.y * size.y / height, 4, + size.y * size.y / height}; + dc.SetPen(wxPen(border_color.defaultColor())); + dc.SetBrush(wxBrush(*wxLIGHT_GREY)); + dc.DrawRoundedRectangle(rect, 2); + rcContent.width -= 6; + } + + // draw check icon + rcContent.x += 5; + rcContent.width -= 5; + if (check_bitmap.bmp().IsOk()) { + auto szBmp = check_bitmap.GetBmpSize(); + if (selection >= 0) { + wxPoint pt = rcContent.GetLeftTop(); + pt.y += (rcContent.height - szBmp.y) / 2; + pt.y += rowSize.y * selection; + if (pt.y + szBmp.y > 0 && pt.y < size.y) + dc.DrawBitmap(check_bitmap.bmp(), pt); + } + rcContent.x += szBmp.x + 5; + rcContent.width -= szBmp.x + 5; + } + // draw texts & icons + dc.SetTextForeground(text_color.colorForStates(states)); + for (int i = 0; i < texts.size(); ++i) { + if (rcContent.GetBottom() < 0) { + rcContent.y += rowSize.y; + continue; + } + if (rcContent.y > size.y) break; + wxPoint pt = rcContent.GetLeftTop(); + auto & icon = icons[i]; + if (iconSize.x > 0) { + if (icon.IsOk()) { + pt.y += (rcContent.height - icon.GetSize().y) / 2; + dc.DrawBitmap(icon, pt); + } + pt.x += iconSize.x + 5; + pt.y = rcContent.y; + } else if (icon.IsOk()) { + pt.y += (rcContent.height - icon.GetSize().y) / 2; + dc.DrawBitmap(icon, pt); + pt.x += icon.GetWidth() + 5; + pt.y = rcContent.y; + } + auto text = texts[i]; + if (!text_off && !text.IsEmpty()) { + wxSize tSize = dc.GetMultiLineTextExtent(text); + if (pt.x + tSize.x > rcContent.GetRight()) { + text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, + rcContent.GetRight() - pt.x); + } + pt.y += (rcContent.height - textSize.y) / 2; + dc.SetFont(GetFont()); + dc.DrawText(text, pt); + } + rcContent.y += rowSize.y; + } +} + +void DropDown::messureSize() +{ + if (!need_sync) return; + textSize = wxSize(); + iconSize = wxSize(); + wxClientDC dc(GetParent() ? GetParent() : this); + for (size_t i = 0; i < texts.size(); ++i) { + wxSize size1 = text_off ? wxSize() : dc.GetMultiLineTextExtent(texts[i]); + if (icons[i].IsOk()) { + wxSize size2 = icons[i].GetSize(); + if (size2.x > iconSize.x) iconSize = size2; + if (!align_icon) { + size1.x += size2.x + (text_off ? 0 : 5); + } + } + if (size1.x > textSize.x) textSize = size1; + } + if (!align_icon) iconSize.x = 0; + wxSize szContent = textSize; + szContent.x += 10; + if (check_bitmap.bmp().IsOk()) { + auto szBmp = check_bitmap.bmp().GetSize(); + szContent.x += szBmp.x + 5; + } + if (iconSize.x > 0) szContent.x += iconSize.x + (text_off ? 0 : 5); + if (iconSize.y > szContent.y) szContent.y = iconSize.y; + szContent.y += 10; + if (texts.size() > 15) szContent.x += 6; + if (GetParent()) { + auto x = GetParent()->GetSize().x; + if (!use_content_width || x > szContent.x) + szContent.x = x; + } + rowSize = szContent; + szContent.y *= std::min((size_t)15, texts.size()); + szContent.y += texts.size() > 15 ? rowSize.y / 2 : 0; + wxWindow::SetSize(szContent); + need_sync = false; +} + +void DropDown::autoPosition() +{ + messureSize(); + wxPoint pos = GetParent()->ClientToScreen(wxPoint(0, -6)); + wxPoint old = GetPosition(); + wxSize size = GetSize(); + Position(pos, {0, GetParent()->GetSize().y + 12}); + if (old != GetPosition()) { + size = rowSize; + size.y *= std::min((size_t)15, texts.size()); + size.y += texts.size() > 15 ? rowSize.y / 2 : 0; + if (size != GetSize()) { + wxWindow::SetSize(size); + offset = wxPoint(); + Position(pos, {0, GetParent()->GetSize().y + 12}); + } + } + if (GetPosition().y > pos.y) { + // may exceed + auto drect = wxDisplay(GetParent()).GetGeometry(); + if (GetPosition().y + size.y + 10 > drect.GetBottom()) { + if (use_content_width && texts.size() <= 15) size.x += 6; + size.y = drect.GetBottom() - GetPosition().y - 10; + wxWindow::SetSize(size); + if (selection >= 0) { + if (offset.y + rowSize.y * (selection + 1) > size.y) + offset.y = size.y - rowSize.y * (selection + 1); + else if (offset.y + rowSize.y * selection < 0) + offset.y = -rowSize.y * selection; + } + } + } +} + +void DropDown::mouseDown(wxMouseEvent& event) +{ + // Receivce unexcepted LEFT_DOWN on Mac after OnDismiss + if (!IsShown()) + return; + // force calc hover item again + mouseMove(event); + pressedDown = true; + CaptureMouse(); + dragStart = event.GetPosition(); +} + +void DropDown::mouseReleased(wxMouseEvent& event) +{ + if (pressedDown) { + dragStart = wxPoint(); + pressedDown = false; + if (HasCapture()) + ReleaseMouse(); + if (hover_item >= 0) { // not moved + sendDropDownEvent(); + DismissAndNotify(); + } + } +} + +void DropDown::mouseCaptureLost(wxMouseCaptureLostEvent &event) +{ + wxMouseEvent evt; + mouseReleased(evt); +} + +void DropDown::mouseMove(wxMouseEvent &event) +{ + wxPoint pt = event.GetPosition(); + if (pressedDown) { + wxPoint pt2 = offset + pt - dragStart; + dragStart = pt; + if (pt2.y > 0) + pt2.y = 0; + else if (pt2.y + rowSize.y * texts.size() < GetSize().y) + pt2.y = GetSize().y - rowSize.y * texts.size(); + if (pt2.y != offset.y) { + offset = pt2; + hover_item = -1; // moved + } else { + return; + } + } + if (!pressedDown || hover_item >= 0) { + int hover = (pt.y - offset.y) / rowSize.y; + if (hover >= (int) texts.size()) hover = -1; + if (hover == hover_item) return; + hover_item = hover; + if (hover >= 0) + SetToolTip(texts[hover]); + } + paintNow(); +} + +void DropDown::mouseWheelMoved(wxMouseEvent &event) +{ + auto delta = event.GetWheelRotation() > 0 ? rowSize.y : -rowSize.y; + wxPoint pt2 = offset + wxPoint{0, delta}; + if (pt2.y > 0) + pt2.y = 0; + else if (pt2.y + rowSize.y * texts.size() < GetSize().y) + pt2.y = GetSize().y - rowSize.y * texts.size(); + if (pt2.y != offset.y) { + offset = pt2; + } else { + return; + } + int hover = (event.GetPosition().y - offset.y) / rowSize.y; + if (hover >= (int) texts.size()) hover = -1; + if (hover != hover_item) { + hover_item = hover; + if (hover >= 0) SetToolTip(texts[hover]); + } + paintNow(); +} + +// currently unused events +void DropDown::sendDropDownEvent() +{ + selection = hover_item; + wxCommandEvent event(wxEVT_COMBOBOX, GetId()); + event.SetEventObject(this); + event.SetInt(selection); + event.SetString(GetValue()); + GetEventHandler()->ProcessEvent(event); +} + +void DropDown::OnDismiss() +{ + dismissTime = boost::posix_time::microsec_clock::universal_time(); + hover_item = -1; + wxCommandEvent e(EVT_DISMISS); + GetEventHandler()->ProcessEvent(e); +} diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp new file mode 100644 index 0000000000..b2b7eaa73e --- /dev/null +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -0,0 +1,111 @@ +#ifndef slic3r_GUI_DropDown_hpp_ +#define slic3r_GUI_DropDown_hpp_ + +#include +#include "../wxExtensions.hpp" +#include "StateHandler.hpp" + +#define DD_NO_CHECK_ICON 0x0001 +#define DD_NO_TEXT 0x0002 +#define DD_STYLE_MASK 0x0003 + +wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent); + +class DropDown : public wxPopupTransientWindow +{ + std::vector & texts; + std::vector & icons; + bool need_sync = false; + int selection = -1; + int hover_item = -1; + + double radius = 0; + bool use_content_width = false; + bool align_icon = false; + bool text_off = false; + + wxSize textSize; + wxSize iconSize; + wxSize rowSize; + + StateHandler state_handler; + StateColor text_color; + StateColor border_color; + StateColor selector_border_color; + StateColor selector_background_color; + ScalableBitmap check_bitmap; + + bool pressedDown = false; + boost::posix_time::ptime dismissTime; + wxPoint offset; // x not used + wxPoint dragStart; + +public: + DropDown(std::vector &texts, + std::vector &icons); + + DropDown(wxWindow * parent, + std::vector &texts, + std::vector &icons, + long style = 0); + + void Create(wxWindow * parent, + long style = 0); + +public: + void Invalidate(bool clear = false); + + int GetSelection() const { return selection; } + + void SetSelection(int n); + + wxString GetValue() const; + void SetValue(const wxString &value); + +public: + void SetCornerRadius(double radius); + + void SetBorderColor(StateColor const & color); + + void SetSelectorBorderColor(StateColor const & color); + + void SetTextColor(StateColor const &color); + + void SetSelectorBackgroundColor(StateColor const &color); + + void SetUseContentWidth(bool use); + + void SetAlignIcon(bool align); + +public: + void Rescale(); + + bool HasDismissLongTime(); + +protected: + void OnDismiss() override; + +private: + void paintEvent(wxPaintEvent& evt); + void paintNow(); + + void render(wxDC& dc); + + friend class ComboBox; + void messureSize(); + void autoPosition(); + + // some useful events + void mouseDown(wxMouseEvent& event); + void mouseReleased(wxMouseEvent &event); + void mouseCaptureLost(wxMouseCaptureLostEvent &event); + void mouseMove(wxMouseEvent &event); + void mouseWheelMoved(wxMouseEvent &event); + + void sendDropDownEvent(); + + + DECLARE_EVENT_TABLE() +}; + +#endif // !slic3r_GUI_DropDown_hpp_ diff --git a/src/slic3r/GUI/Widgets/Label.cpp b/src/slic3r/GUI/Widgets/Label.cpp new file mode 100644 index 0000000000..4a541f3478 --- /dev/null +++ b/src/slic3r/GUI/Widgets/Label.cpp @@ -0,0 +1,124 @@ +#include "Label.hpp" +#include "StaticBox.hpp" + +wxFont Label::sysFont(int size, bool bold) +{ +//#ifdef __linux__ +// return wxFont{}; +//#endif +#ifndef __APPLE__ + size = size * 4 / 5; +#endif + + auto face = wxString::FromUTF8("HarmonyOS Sans SC"); + wxFont font{size, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, bold ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL, false, face}; + font.SetFaceName(face); + if (!font.IsOk()) { + font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + if (bold) font.MakeBold(); + font.SetPointSize(size); + } + return font; +} +wxFont Label::Head_24; +wxFont Label::Head_20; +wxFont Label::Head_18; +wxFont Label::Head_16; +wxFont Label::Head_15; +wxFont Label::Head_14; +wxFont Label::Head_13; +wxFont Label::Head_12; +wxFont Label::Head_10; + +wxFont Label::Body_16; +wxFont Label::Body_15; +wxFont Label::Body_14; +wxFont Label::Body_13; +wxFont Label::Body_12; +wxFont Label::Body_11; +wxFont Label::Body_10; +wxFont Label::Body_9; + +void Label::initSysFont() +{ + Head_24 = Label::sysFont(24, true); + Head_20 = Label::sysFont(20, true); + Head_18 = Label::sysFont(18, true); + Head_16 = Label::sysFont(16, true); + Head_15 = Label::sysFont(15, true); + Head_14 = Label::sysFont(14, true); + Head_13 = Label::sysFont(13, true); + Head_12 = Label::sysFont(12, true); + Head_10 = Label::sysFont(10, true); + + Body_16 = Label::sysFont(16, false); + Body_15 = Label::sysFont(15, false); + Body_14 = Label::sysFont(14, false); + Body_13 = Label::sysFont(13, false); + Body_12 = Label::sysFont(12, false); + Body_11 = Label::sysFont(11, false); + Body_10 = Label::sysFont(10, false); + Body_9 = Label::sysFont(9, false); +} + +wxSize Label::split_lines(wxDC &dc, int width, const wxString &text, wxString &multiline_text) +{ + multiline_text = text; + if (width > 0 && dc.GetTextExtent(text).x > width) { + size_t start = 0; + while (true) { + size_t idx = size_t(-1); + for (size_t i = start; i < multiline_text.Len(); i++) { + if (multiline_text[i] == ' ') { + if (dc.GetTextExtent(multiline_text.SubString(start, i)).x < width) + idx = i; + else { + if (idx == size_t(-1)) idx = i; + break; + } + } + } + if (idx == size_t(-1)) break; + multiline_text[idx] = '\n'; + start = idx + 1; + if (dc.GetTextExtent(multiline_text.Mid(start)).x < width) break; + } + } + return dc.GetMultiLineTextExtent(multiline_text); +} + +Label::Label(wxWindow *parent, wxString const &text, long style) : Label(parent, Body_14, text, style) {} + +Label::Label(wxWindow *parent, wxFont const &font, wxString const &text, long style) + : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, style) +{ + this->font = font; + SetFont(font); + SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent)); + Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { + if (GetWindowStyle() & LB_HYPERLINK) { + SetFont(this->font.Underlined()); + Refresh(); + } + }); + Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { + SetFont(this->font); + Refresh(); + }); +} + +void Label::SetWindowStyleFlag(long style) +{ + if (style == GetWindowStyle()) + return; + wxStaticText::SetWindowStyleFlag(style); + if (style & LB_HYPERLINK) { + this->color = GetForegroundColour(); + static wxColor clr_url("#00AE42"); + SetForegroundColour(clr_url); + } else { + SetForegroundColour(this->color); + SetFont(this->font); + } + Refresh(); +} diff --git a/src/slic3r/GUI/Widgets/Label.hpp b/src/slic3r/GUI/Widgets/Label.hpp new file mode 100644 index 0000000000..1d3d387fb7 --- /dev/null +++ b/src/slic3r/GUI/Widgets/Label.hpp @@ -0,0 +1,49 @@ +#ifndef slic3r_GUI_Label_hpp_ +#define slic3r_GUI_Label_hpp_ + +#include + +#define LB_HYPERLINK 0x0001 + + +class Label : public wxStaticText +{ +public: + Label(wxWindow *parent, wxString const &text = {}, long style = 0); + + Label(wxWindow *parent, wxFont const &font, wxString const &text = {}, long style = 0); + + void SetWindowStyleFlag(long style) override; + +private: + wxFont font; + wxColour color; + +public: + static wxFont Head_24; + static wxFont Head_20; + static wxFont Head_18; + static wxFont Head_16; + static wxFont Head_15; + static wxFont Head_14; + static wxFont Head_13; + static wxFont Head_12; + static wxFont Head_10; + + static wxFont Body_16; + static wxFont Body_15; + static wxFont Body_14; + static wxFont Body_13; + static wxFont Body_12; + static wxFont Body_10; + static wxFont Body_11; + static wxFont Body_9; + + static void initSysFont(); + + static wxFont sysFont(int size, bool bold = false); + + static wxSize split_lines(wxDC &dc, int width, const wxString &text, wxString &multiline_text); +}; + +#endif // !slic3r_GUI_Label_hpp_ diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp new file mode 100644 index 0000000000..9bea97dcdc --- /dev/null +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -0,0 +1,323 @@ +#include "SpinInput.hpp" +#include "Label.hpp" +#include "Button.hpp" + +#include + +BEGIN_EVENT_TABLE(SpinInput, wxPanel) + +EVT_KEY_DOWN(SpinInput::keyPressed) +EVT_MOUSEWHEEL(SpinInput::mouseWheelMoved) + +EVT_PAINT(SpinInput::paintEvent) + +END_EVENT_TABLE() + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +SpinInput::SpinInput() + : label_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x6B6B6B, (int) StateColor::Normal)) + , text_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x262E30, (int) StateColor::Normal)) +{ + radius = 0; + border_width = 1; + border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x00AE42, (int) StateColor::Hovered), + std::make_pair(0xDBDBDB, (int) StateColor::Normal)); + background_color = StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal)); +} + + +SpinInput::SpinInput(wxWindow *parent, + wxString text, + wxString label, + const wxPoint &pos, + const wxSize & size, + long style, + int min, int max, int initial) + : SpinInput() +{ + Create(parent, text, label, pos, size, style, min, max, initial); +} + +void SpinInput::Create(wxWindow *parent, + wxString text, + wxString label, + const wxPoint &pos, + const wxSize & size, + long style, + int min, int max, int initial) +{ + StaticBox::Create(parent, wxID_ANY, pos, size); + SetFont(Label::Body_12); + wxWindow::SetLabel(label); + state_handler.attach({&label_color, &text_color}); + state_handler.update_binds(); + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS)); + text_ctrl->SetFont(Label::Body_14); + text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + state_handler.attach_child(text_ctrl); + text_ctrl->Bind(wxEVT_KILL_FOCUS, &SpinInput::onTextLostFocus, this); + text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInput::onTextEnter, this); + text_ctrl->Bind(wxEVT_KEY_DOWN, &SpinInput::keyPressed, this); + text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu + button_inc = createButton(true); + button_dec = createButton(false); + delta = 0; + timer.Bind(wxEVT_TIMER, &SpinInput::onTimer, this); + + long initialFromText; + if (text.ToLong(&initialFromText)) initial = initialFromText; + SetRange(min, max); + SetValue(initial); + messureSize(); +} + +void SpinInput::SetCornerRadius(double radius) +{ + this->radius = radius; + Refresh(); +} + +void SpinInput::SetLabel(const wxString &label) +{ + wxWindow::SetLabel(label); + messureSize(); + Refresh(); +} + +void SpinInput::SetLabelColor(StateColor const &color) +{ + label_color = color; + state_handler.update_binds(); +} + +void SpinInput::SetTextColor(StateColor const &color) +{ + text_color = color; + state_handler.update_binds(); +} + +void SpinInput::SetSize(wxSize const &size) +{ + wxWindow::SetSize(size); + Rescale(); +} + +void SpinInput::SetValue(const wxString &text) +{ + long value; + if ( text.ToLong(&value) ) + SetValue(value); +} + +void SpinInput::SetValue(int value) +{ + if (value < min) value = min; + else if (value > max) value = max; + this->val = value; + text_ctrl->SetValue(wxString::FromDouble(value)); +} + +int SpinInput::GetValue()const +{ + return val; +} + +void SpinInput::SetRange(int min, int max) +{ + this->min = min; + this->max = max; +} + +void SpinInput::DoSetToolTipText(wxString const &tip) +{ + wxWindow::DoSetToolTipText(tip); + text_ctrl->SetToolTip(tip); +} + +void SpinInput::Rescale() +{ + button_inc->Rescale(); + button_dec->Rescale(); + messureSize(); +} + +bool SpinInput::Enable(bool enable) +{ + bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); + if (result) { + wxCommandEvent e(EVT_ENABLE_CHANGED); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + button_inc->Enable(enable); + button_dec->Enable(enable); + } + return result; +} + +void SpinInput::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void SpinInput::render(wxDC& dc) +{ + StaticBox::render(dc); + int states = state_handler.states(); + wxSize size = GetSize(); + // draw seperator of buttons + wxPoint pt = button_inc->GetPosition(); + pt.y = size.y / 2; + dc.SetPen(wxPen(border_color.defaultColor())); + dc.DrawLine(pt, pt + wxSize{button_inc->GetSize().x - 2, 0}); + // draw label + auto label = GetLabel(); + if (!label.IsEmpty()) { + pt.x = size.x - labelSize.x - 5; + pt.y = (size.y - labelSize.y) / 2; + dc.SetFont(GetFont()); + dc.SetTextForeground(label_color.colorForStates(states)); + dc.DrawText(label, pt); + } +} + +void SpinInput::messureSize() +{ + wxSize size = GetSize(); + wxSize textSize = text_ctrl->GetSize(); + int h = textSize.y + 8; + if (size.y < h) { + size.y = h; + SetSize(size); + SetMinSize(size); + } else { + textSize.y = size.y * 14 / 24; + } + wxSize btnSize = {14, (size.y - 4) / 2}; + btnSize.x = btnSize.x * btnSize.y / 10; + wxClientDC dc(this); + labelSize = dc.GetMultiLineTextExtent(GetLabel()); + textSize.x = size.x - labelSize.x - btnSize.x - 16; + text_ctrl->SetSize(textSize); + text_ctrl->SetPosition({6 + btnSize.x, (size.y - textSize.y) / 2}); + button_inc->SetSize(btnSize); + button_dec->SetSize(btnSize); + button_inc->SetPosition({3, size.y / 2 - btnSize.y - 1}); + button_dec->SetPosition({3, size.y / 2 + 1}); +} + +Button *SpinInput::createButton(bool inc) +{ + auto btn = new Button(this, "", inc ? "spin_inc" : "spin_dec", wxBORDER_NONE, 6); + btn->SetCornerRadius(0); + btn->DisableFocusFromKeyboard(); + btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) { + delta = inc ? 1 : -1; + SetValue(val + delta); + text_ctrl->SetFocus(); + btn->CaptureMouse(); + delta *= 8; + timer.Start(100); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_DCLICK, [=](auto &e) { + delta = inc ? 1 : -1; + btn->CaptureMouse(); + SetValue(val + delta); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_UP, [=](auto &e) { + btn->ReleaseMouse(); + timer.Stop(); + text_ctrl->SelectAll(); + delta = 0; + }); + return btn; +} + +void SpinInput::onTimer(wxTimerEvent &evnet) { + if (delta < -1 || delta > 1) { + delta /= 2; + return; + } + SetValue(val + delta); + sendSpinEvent(); +} + +void SpinInput::onTextLostFocus(wxEvent &event) +{ + timer.Stop(); + for (auto * child : GetChildren()) + if (auto btn = dynamic_cast(child)) + if (btn->HasCapture()) + btn->ReleaseMouse(); + wxCommandEvent e; + onTextEnter(e); + // pass to outer + event.SetId(GetId()); + ProcessEventLocally(event); + e.Skip(); +} + +void SpinInput::onTextEnter(wxCommandEvent &event) +{ + long value; + if (!text_ctrl->GetValue().ToLong(&value)) { value = val; } + if (value != val) { + SetValue(value); + sendSpinEvent(); + } + event.SetId(GetId()); + ProcessEventLocally(event); +} + +void SpinInput::mouseWheelMoved(wxMouseEvent &event) +{ + auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? 1 : -1; + SetValue(val + delta); + sendSpinEvent(); + text_ctrl->SetFocus(); +} + +void SpinInput::keyPressed(wxKeyEvent &event) +{ + switch (event.GetKeyCode()) { + case WXK_UP: + case WXK_DOWN: + long value; + if (!text_ctrl->GetValue().ToLong(&value)) { value = val; } + if (event.GetKeyCode() == WXK_DOWN && value > min) { + --value; + } else if (event.GetKeyCode() == WXK_UP && value + 1 < max) { + ++value; + } + if (value != val) { + SetValue(value); + sendSpinEvent(); + } + break; + default: event.Skip(); break; + } +} + +void SpinInput::sendSpinEvent() +{ + wxCommandEvent event(wxEVT_SPINCTRL, GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} diff --git a/src/slic3r/GUI/Widgets/SpinInput.hpp b/src/slic3r/GUI/Widgets/SpinInput.hpp new file mode 100644 index 0000000000..5b0868880c --- /dev/null +++ b/src/slic3r/GUI/Widgets/SpinInput.hpp @@ -0,0 +1,96 @@ +#ifndef slic3r_GUI_SpinInput_hpp_ +#define slic3r_GUI_SpinInput_hpp_ + +#include +#include "StaticBox.hpp" + +class Button; + +class SpinInput : public wxNavigationEnabled +{ + wxSize labelSize; + StateColor label_color; + StateColor text_color; + wxTextCtrl * text_ctrl; + Button * button_inc; + Button * button_dec; + wxTimer timer; + + int val; + int min; + int max; + int delta; + + static const int SpinInputWidth = 200; + static const int SpinInputHeight = 50; + +public: + SpinInput(); + + SpinInput(wxWindow * parent, + wxString text, + wxString label = "", + const wxPoint &pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = 0, + int min = 0, int max = 100, int initial = 0); + + void Create(wxWindow * parent, + wxString text, + wxString label = "", + const wxPoint &pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = 0, + int min = 0, + int max = 100, + int initial = 0); + + void SetCornerRadius(double radius); + + void SetLabel(const wxString &label) wxOVERRIDE; + + void SetLabelColor(StateColor const &color); + + void SetTextColor(StateColor const &color); + + void SetSize(wxSize const &size); + + void Rescale(); + + virtual bool Enable(bool enable = true) wxOVERRIDE; + + wxTextCtrl * GetTextCtrl() { return text_ctrl; } + + void SetValue(const wxString &text); + + void SetValue (int value); + + int GetValue () const; + + void SetRange(int min, int max); + +protected: + void DoSetToolTipText(wxString const &tip) override; + +private: + void paintEvent(wxPaintEvent& evt); + + void render(wxDC& dc); + + void messureSize(); + + Button *createButton(bool inc); + + // some useful events + void mouseWheelMoved(wxMouseEvent& event); + void keyPressed(wxKeyEvent& event); + void onTimer(wxTimerEvent &evnet); + void onTextLostFocus(wxEvent &event); + void onTextEnter(wxCommandEvent &event); + + void sendSpinEvent(); + + DECLARE_EVENT_TABLE() +}; + +#endif // !slic3r_GUI_SpinInput_hpp_ diff --git a/src/slic3r/GUI/Widgets/StateColor.cpp b/src/slic3r/GUI/Widgets/StateColor.cpp new file mode 100644 index 0000000000..a3419b08d3 --- /dev/null +++ b/src/slic3r/GUI/Widgets/StateColor.cpp @@ -0,0 +1,93 @@ +#include "StateColor.hpp" + +StateColor::StateColor(wxColour const &color) { append(color, 0); } + +StateColor::StateColor(wxString const &color) { append(color, 0); } + +StateColor::StateColor(unsigned long color) { append(color, 0); } + +void StateColor::append(wxColour const & color, int states) +{ + statesList_.push_back(states); + colors_.push_back(color); +} + +void StateColor::append(wxString const & color, int states) +{ + wxColour c1(color); + append(c1, states); +} + +void StateColor::append(unsigned long color, int states) +{ + if ((color & 0xff000000) == 0) + color |= 0xff000000; + wxColour cl; cl.SetRGBA(color & 0xff00ff00 | ((color & 0xff) << 16) | ((color >> 16) & 0xff)); + append(cl, states); +} + +void StateColor::clear() +{ + statesList_.clear(); + colors_.clear(); +} + +int StateColor::states() const +{ + int states = 0; + for (auto s : statesList_) states |= s; + states = (states & 0xffff) | (states >> 16); + if (takeFocusedAsHovered_ && (states & Hovered)) + states |= Focused; + return states; +} + +wxColour StateColor::defaultColor() { + return colorForStates(0); +} + +wxColour StateColor::colorForStates(int states) +{ + bool focused = takeFocusedAsHovered_ && (states & Focused); + for (int i = 0; i < statesList_.size(); ++i) { + int s = statesList_[i]; + int on = s & 0xffff; + int off = s >> 16; + if ((on & states) == on && (off & ~states) == off) { + return colors_[i]; + } + if (focused && (on & Hovered)) { + on |= Focused; + on &= ~Hovered; + if ((on & states) == on && (off & ~states) == off) { + return colors_[i]; + } + } + } + return wxColour(0, 0, 0, 0); +} + +int StateColor::colorIndexForStates(int states) +{ + for (int i = 0; i < statesList_.size(); ++i) { + int s = statesList_[i]; + int on = s & 0xffff; + int off = s >> 16; + if ((on & states) == on && (off & ~states) == off) { return i; } + } + return -1; +} + +bool StateColor::setColorForStates(wxColour const &color, int states) +{ + for (int i = 0; i < statesList_.size(); ++i) { + if (statesList_[i] == states) { + colors_[i] = color; + return true; + } + } + return false; +} + +void StateColor::setTakeFocusedAsHovered(bool set) { takeFocusedAsHovered_ = set; } + diff --git a/src/slic3r/GUI/Widgets/StateColor.hpp b/src/slic3r/GUI/Widgets/StateColor.hpp new file mode 100644 index 0000000000..0855e64db4 --- /dev/null +++ b/src/slic3r/GUI/Widgets/StateColor.hpp @@ -0,0 +1,84 @@ +#ifndef slic3r_GUI_StateColor_hpp_ +#define slic3r_GUI_StateColor_hpp_ + +#include + +class StateColor +{ +public: + enum State { + Normal = 0, + Enabled = 1, + Checked = 2, + Focused = 4, + Hovered = 8, + Pressed = 16, + Disabled = 1 << 16, + NotChecked = 2 << 16, + NotFocused = 4 << 16, + NotHovered = 8 << 16, + NotPressed = 16 << 16, + }; + +public: + template + StateColor(std::pair... colors) { + fill(colors...); + } + + // single color + StateColor(wxColour const & color); + + // single color + StateColor(wxString const &color); + + // single color + StateColor(unsigned long color); + +public: + void append(wxColour const & color, int states); + + void append(wxString const &color, int states); + + void append(unsigned long color, int states); + + void clear(); + +public: + int count() const { return statesList_.size(); } + + int states() const; + +public: + wxColour defaultColor(); + + wxColour colorForStates(int states); + + int colorIndexForStates(int states); + + bool setColorForStates(wxColour const & color, int states); + + void setTakeFocusedAsHovered(bool set); + +private: + template + void fill(std::pair color, std::pair... colors) { + fillOne(color); + fill(colors...); + } + + template + void fillOne(std::pair color) { + append(color.first, color.second); + } + + void fill() { + } + +private: + std::vector statesList_; + std::vector colors_; + bool takeFocusedAsHovered_ = true; +}; + +#endif // !slic3r_GUI_StateColor_hpp_ diff --git a/src/slic3r/GUI/Widgets/StateHandler.cpp b/src/slic3r/GUI/Widgets/StateHandler.cpp new file mode 100644 index 0000000000..72616ed8fd --- /dev/null +++ b/src/slic3r/GUI/Widgets/StateHandler.cpp @@ -0,0 +1,122 @@ +#include "StateHandler.hpp" + +wxDEFINE_EVENT(EVT_ENABLE_CHANGED, wxCommandEvent); + +StateHandler::StateHandler(wxWindow * owner) + : owner_(owner) +{ + owner_->PushEventHandler(this); + if (owner->IsEnabled()) + states_ |= Enabled; + if (owner->HasFocus()) + states_ |= Focused; +} + +StateHandler::~StateHandler() { owner_->RemoveEventHandler(this); } + +void StateHandler::attach(StateColor const &color) +{ + colors_.push_back(&color); +} + +void StateHandler::attach(std::vector const & colors) +{ + colors_.insert(colors_.end(), colors.begin(), colors.end()); +} + +void StateHandler::attach_child(wxWindow *child) +{ + auto ch = new StateHandler(this, child); + children_.emplace_back(ch); + ch->update_binds(); + states2_ |= ch->states(); +} + +void StateHandler::remove_child(wxWindow *child) +{ + children_.erase(std::remove_if(children_.begin(), children_.end(), + [child](auto &c) { return c->owner_ == child; }), children_.end()); + states2_ = 0; + for (auto & c : children_) states2_ |= c->states(); +} + +void StateHandler::update_binds() +{ + int bind_states = parent_ ? (parent_->bind_states_ & ~Enabled) : 0; + for (auto c : colors_) { + bind_states |= c->states(); + } + bind_states = bind_states | (bind_states >> 16); + int diff = bind_states ^ bind_states_; + State states[] = {Enabled, Checked, Focused, Hovered, Pressed}; + wxEventType events[] = {EVT_ENABLE_CHANGED, wxEVT_CHECKBOX, wxEVT_SET_FOCUS, wxEVT_ENTER_WINDOW, wxEVT_LEFT_DOWN}; + wxEventType events2[] = {{0}, {0}, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP}; + for (int i = 0; i < 5; ++i) { + int s = states[i]; + if (diff & s) { + if (bind_states & s) { + Bind(events[i], &StateHandler::changed, this); + if (events2[i]) + Bind(events2[i], &StateHandler::changed, this); + } else { + Unbind(events[i], &StateHandler::changed, this); + if (events2[i]) + owner_->Unbind(events2[i], &StateHandler::changed, this); + } + } + } + bind_states_ = bind_states; + for (auto &c : children_) c->update_binds(); +} + +StateHandler::StateHandler(StateHandler *parent, wxWindow *owner) + : StateHandler(owner) +{ + states_ &= ~Enabled; + parent_ = parent; +} + +void StateHandler::changed(wxEvent &event) +{ + event.Skip(); + wxEventType events[] = {EVT_ENABLE_CHANGED, wxEVT_CHECKBOX, wxEVT_SET_FOCUS, wxEVT_ENTER_WINDOW, wxEVT_LEFT_DOWN}; + wxEventType events2[] = {{0}, {0}, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP}; + int old = states_; + // some events are from another window (ex: text_ctrl of TextInput), save state in states2_ to avoid conflicts + for (int i = 0; i < 5; ++i) { + if (events2[i]) { + if (event.GetEventType() == events[i]) { + states_ |= 1 << i; + break; + } else if (event.GetEventType() == events2[i]) { + states_ &= ~(1 << i); + break; + } + } + else { + if (event.GetEventType() == events[i]) { + states_ ^= (1 << i); + break; + } + } + } + if (old != states_ && (old | states2_) != (states_ | states2_)) { + if (parent_) + parent_->changed(states_ | states2_); + else + owner_->Refresh(); + } +} + +void StateHandler::changed(int) +{ + int old = states2_; + states2_ = 0; + for (auto &c : children_) states2_ |= c->states(); + if (old != states2_ && (old | states_) != (states_ | states2_)) { + if (parent_) + parent_->changed(states_ | states2_); + else + owner_->Refresh(); + } +} diff --git a/src/slic3r/GUI/Widgets/StateHandler.hpp b/src/slic3r/GUI/Widgets/StateHandler.hpp new file mode 100644 index 0000000000..9ef155c7db --- /dev/null +++ b/src/slic3r/GUI/Widgets/StateHandler.hpp @@ -0,0 +1,61 @@ +#ifndef slic3r_GUI_StateHandler_hpp_ +#define slic3r_GUI_StateHandler_hpp_ + +#include + +#include "StateColor.hpp" + +wxDECLARE_EVENT(EVT_ENABLE_CHANGED, wxCommandEvent); + +class StateHandler : public wxEvtHandler +{ +public: + enum State { + Enabled = 1, + Checked = 2, + Focused = 4, + Hovered = 8, + Pressed = 16, + Disabled = 1 << 16, + NotChecked = 2 << 16, + NotFocused = 4 << 16, + NotHovered = 8 << 16, + NotPressed = 16 << 16, + }; + +public: + StateHandler(wxWindow * owner); + + ~StateHandler(); + +public: + void attach(StateColor const & color); + + void attach(std::vector const & colors); + + void attach_child(wxWindow *child); + + void remove_child(wxWindow *child); + + void update_binds(); + + int states() const { return states_ | states2_; } + +private: + StateHandler(StateHandler * parent, wxWindow *owner); + + void changed(wxEvent &event); + + void changed(int state2); + +private: + wxWindow * owner_; + std::vector colors_; + int bind_states_ = 0; + int states_ = 0; + int states2_ = 0; // from children + std::vector> children_; + StateHandler * parent_ = nullptr; +}; + +#endif // !slic3r_GUI_StateHandler_hpp_ diff --git a/src/slic3r/GUI/Widgets/StaticBox.cpp b/src/slic3r/GUI/Widgets/StaticBox.cpp new file mode 100644 index 0000000000..1a806e0007 --- /dev/null +++ b/src/slic3r/GUI/Widgets/StaticBox.cpp @@ -0,0 +1,214 @@ +#include "StaticBox.hpp" +#include "../GUI.hpp" +#include + +BEGIN_EVENT_TABLE(StaticBox, wxWindow) + +// catch paint events +//EVT_ERASE_BACKGROUND(StaticBox::eraseEvent) +EVT_PAINT(StaticBox::paintEvent) + +END_EVENT_TABLE() + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +StaticBox::StaticBox() + : state_handler(this) + , radius(8) +{ + border_color = StateColor( + std::make_pair(*wxLIGHT_GREY, (int) StateColor::Disabled), + std::make_pair(0x303A3C, (int) StateColor::Normal)); +} + +StaticBox::StaticBox(wxWindow* parent, + wxWindowID id, + const wxPoint & pos, + const wxSize & size, long style) + : StaticBox() +{ + Create(parent, id, pos, size, style); +} + +bool StaticBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) +{ + if (style & wxBORDER_NONE) + border_width = 0; + wxWindow::Create(parent, id, pos, size, style); + state_handler.attach({&border_color, &background_color, &background_color2}); + state_handler.update_binds(); + SetBackgroundColour(GetParentBackgroundColor(parent)); + return true; +} + +void StaticBox::SetCornerRadius(double radius) +{ + this->radius = radius; + Refresh(); +} + +void StaticBox::SetBorderWidth(int width) +{ + border_width = width; + Refresh(); +} + +void StaticBox::SetBorderColor(StateColor const &color) +{ + border_color = color; + state_handler.update_binds(); + Refresh(); +} + +void StaticBox::SetBorderColorNormal(wxColor const &color) +{ + border_color.setColorForStates(color, 0); + Refresh(); +} + +void StaticBox::SetBackgroundColor(StateColor const &color) +{ + background_color = color; + state_handler.update_binds(); + Refresh(); +} + +void StaticBox::SetBackgroundColorNormal(wxColor const &color) +{ + background_color.setColorForStates(color, 0); + Refresh(); +} + +void StaticBox::SetBackgroundColor2(StateColor const &color) +{ + background_color2 = color; + state_handler.update_binds(); + Refresh(); +} + +wxColor StaticBox::GetParentBackgroundColor(wxWindow* parent) +{ + if (auto box = dynamic_cast(parent)) { + if (box->background_color.count() > 0) { + if (box->background_color2.count() == 0) + return box->background_color.defaultColor(); + auto s = box->background_color.defaultColor(); + auto e = box->background_color2.defaultColor(); + int r = (s.Red() + e.Red()) / 2; + int g = (s.Green() + e.Green()) / 2; + int b = (s.Blue() + e.Blue()) / 2; + return wxColor(r, g, b); + } + } + if (parent) + return parent->GetBackgroundColour(); + return *wxWHITE; +} + +void StaticBox::eraseEvent(wxEraseEvent& evt) +{ + // for transparent background, but not work +#ifdef __WXMSW__ + wxDC *dc = evt.GetDC(); + wxSize size = GetSize(); + wxClientDC dc2(GetParent()); + dc->Blit({0, 0}, size, &dc2, GetPosition()); +#endif +} + +void StaticBox::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void StaticBox::render(wxDC& dc) +{ +#ifdef __WXMSW__ + if (radius == 0) { + doRender(dc); + return; + } + + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + //memdc.Blit({0, 0}, size, &dc, {0, 0}); + memdc.SetBackground(wxBrush(GetBackgroundColour())); + memdc.Clear(); + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void StaticBox::doRender(wxDC& dc) +{ + wxSize size = GetSize(); + int states = state_handler.states(); + if (background_color2.count() == 0) { + if ((border_width && border_color.count() > 0) || background_color.count() > 0) { + wxRect rc(0, 0, size.x, size.y); + if (border_width && border_color.count() > 0) { + if (dc.GetContentScaleFactor() == 1.0) { + int d = floor(border_width / 2.0); + int d2 = floor(border_width - 1); + rc.x += d; + rc.width -= d2; + rc.y += d; + rc.height -= d2; + } else { + int d = 1; + rc.x += d; + rc.width -= d; + rc.y += d; + rc.height -= d; + } + dc.SetPen(wxPen(border_color.colorForStates(states), border_width)); + } else { + dc.SetPen(wxPen(background_color.colorForStates(states))); + } + if (background_color.count() > 0) + dc.SetBrush(wxBrush(background_color.colorForStates(states))); + else + dc.SetBrush(wxBrush(GetBackgroundColour())); + if (radius == 0) { + dc.DrawRectangle(rc); + } + else { + dc.DrawRoundedRectangle(rc, radius - border_width); + } + } + } + else { + wxColor start = background_color.colorForStates(states); + wxColor stop = background_color2.colorForStates(states); + int r = start.Red(), g = start.Green(), b = start.Blue(); + int dr = (int) stop.Red() - r, dg = (int) stop.Green() - g, db = (int) stop.Blue() - b; + int lr = 0, lg = 0, lb = 0; + for (int y = 0; y < size.y; ++y) { + dc.SetPen(wxPen(wxColor(r, g, b))); + dc.DrawLine(0, y, size.x, y); + lr += dr; while (lr >= size.y) { ++r, lr -= size.y; } while (lr <= -size.y) { --r, lr += size.y; } + lg += dg; while (lg >= size.y) { ++g, lg -= size.y; } while (lg <= -size.y) { --g, lg += size.y; } + lb += db; while (lb >= size.y) { ++b, lb -= size.y; } while (lb <= -size.y) { --b, lb += size.y; } + } + } +} diff --git a/src/slic3r/GUI/Widgets/StaticBox.hpp b/src/slic3r/GUI/Widgets/StaticBox.hpp new file mode 100644 index 0000000000..871c5651d9 --- /dev/null +++ b/src/slic3r/GUI/Widgets/StaticBox.hpp @@ -0,0 +1,62 @@ +#ifndef slic3r_GUI_StaticBox_hpp_ +#define slic3r_GUI_StaticBox_hpp_ + +#include "../wxExtensions.hpp" +#include "StateHandler.hpp" + +#include + +class StaticBox : public wxWindow +{ +public: + StaticBox(); + + StaticBox(wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint & pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = 0); + + bool Create(wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint & pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = 0); + + void SetCornerRadius(double radius); + + void SetBorderWidth(int width); + + void SetBorderColor(StateColor const & color); + + void SetBorderColorNormal(wxColor const &color); + + void SetBackgroundColor(StateColor const &color); + + void SetBackgroundColorNormal(wxColor const &color); + + void SetBackgroundColor2(StateColor const &color); + + static wxColor GetParentBackgroundColor(wxWindow * parent); + +protected: + void eraseEvent(wxEraseEvent& evt); + + void paintEvent(wxPaintEvent& evt); + + void render(wxDC& dc); + + virtual void doRender(wxDC& dc); + +protected: + double radius; + int border_width = 1; + StateHandler state_handler; + StateColor border_color; + StateColor background_color; + StateColor background_color2; + + DECLARE_EVENT_TABLE() +}; + +#endif // !slic3r_GUI_StaticBox_hpp_ diff --git a/src/slic3r/GUI/Widgets/SwitchButton.cpp b/src/slic3r/GUI/Widgets/SwitchButton.cpp new file mode 100644 index 0000000000..8ae1165dcb --- /dev/null +++ b/src/slic3r/GUI/Widgets/SwitchButton.cpp @@ -0,0 +1,134 @@ +#include "SwitchButton.hpp" +#include "Label.hpp" +#include "StaticBox.hpp" + +#include "../wxExtensions.hpp" +#include "../Utils/MacDarkMode.hpp" + +#include + +SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id) + : wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT) + , m_on(this, "toggle_on", 16) + , m_off(this, "toggle_off", 16) + , text_color(std::pair{*wxWHITE, (int) StateColor::Checked}, std::pair{0x6B6B6B, (int) StateColor::Normal}) + , track_color(0xD9D9D9) + , thumb_color(std::pair{0x00AE42, (int) StateColor::Checked}, std::pair{0xD9D9D9, (int) StateColor::Normal}) +{ + SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent)); + Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); + SetFont(Label::Body_12); + Rescale(); +} + +void SwitchButton::SetLabels(wxString const& lbl_on, wxString const& lbl_off) +{ + labels[0] = lbl_on; + labels[1] = lbl_off; + Rescale(); +} + +void SwitchButton::SetTextColor(StateColor const& color) +{ + text_color = color; +} + +void SwitchButton::SetTrackColor(StateColor const& color) +{ + track_color = color; +} + +void SwitchButton::SetThumbColor(StateColor const& color) +{ + thumb_color = color; +} + +void SwitchButton::SetValue(bool value) +{ + if (value != GetValue()) + wxBitmapToggleButton::SetValue(value); + update(); +} + +void SwitchButton::Rescale() +{ + if (labels[0].IsEmpty()) { + m_on.msw_rescale(); + m_off.msw_rescale(); + } + else { +#ifdef __WXOSX__ + auto scale = Slic3r::GUI::mac_max_scaling_factor(); + int BS = (int) scale; +#else + constexpr int BS = 1; +#endif + wxSize thumbSize; + wxSize trackSize; + wxClientDC dc(this); +#ifdef __WXOSX__ + dc.SetFont(dc.GetFont().Scaled(scale)); +#endif + wxSize textSize[2]; + { + textSize[0] = dc.GetTextExtent(labels[0]); + textSize[1] = dc.GetTextExtent(labels[1]); + } + { + thumbSize = textSize[0]; + auto size = textSize[1]; + if (size.x > thumbSize.x) thumbSize.x = size.x; + else size.x = thumbSize.x; + thumbSize.x += BS * 12; + thumbSize.y += BS * 6; + trackSize.x = thumbSize.x + size.x + BS * 10; + trackSize.y = thumbSize.y + BS * 2; + auto maxWidth = GetMaxWidth(); +#ifdef __WXOSX__ + maxWidth *= scale; +#endif + if (trackSize.x > maxWidth) { + thumbSize.x -= (trackSize.x - maxWidth) / 2; + trackSize.x = maxWidth; + } + } + for (int i = 0; i < 2; ++i) { + wxMemoryDC memdc(&dc); + wxBitmap bmp(trackSize.x, trackSize.y); + memdc.SelectObject(bmp); + memdc.SetBackground(wxBrush(GetBackgroundColour())); + memdc.Clear(); + memdc.SetFont(dc.GetFont()); + auto state = i == 0 ? StateColor::Enabled : (StateColor::Checked | StateColor::Enabled); + { +#ifdef __WXMSW__ + wxGCDC dc2(memdc); +#else + wxDC &dc2(memdc); +#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.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); + } + memdc.SetTextForeground(text_color.colorForStates(state ^ StateColor::Checked)); + memdc.DrawText(labels[0], {BS + (thumbSize.x - textSize[0].x) / 2, BS + (thumbSize.y - textSize[0].y) / 2}); + memdc.SetTextForeground(text_color.colorForStates(state)); + memdc.DrawText(labels[1], {trackSize.x - thumbSize.x - BS + (thumbSize.x - textSize[1].x) / 2, BS + (thumbSize.y - textSize[1].y) / 2}); + memdc.SelectObject(wxNullBitmap); +#ifdef __WXOSX__ + bmp = wxBitmap(bmp.ConvertToImage(), -1, scale); +#endif + (i == 0 ? m_off : m_on).bmp() = bmp; + } + } + SetSize(m_on.GetBmpSize()); + update(); +} + +void SwitchButton::update() +{ + SetBitmap((GetValue() ? m_on : m_off).bmp()); +} diff --git a/src/slic3r/GUI/Widgets/SwitchButton.hpp b/src/slic3r/GUI/Widgets/SwitchButton.hpp new file mode 100644 index 0000000000..25581f3762 --- /dev/null +++ b/src/slic3r/GUI/Widgets/SwitchButton.hpp @@ -0,0 +1,40 @@ +#ifndef slic3r_GUI_SwitchButton_hpp_ +#define slic3r_GUI_SwitchButton_hpp_ + +#include "../wxExtensions.hpp" +#include "StateColor.hpp" + +#include + +class SwitchButton : public wxBitmapToggleButton +{ +public: + SwitchButton(wxWindow * parent = NULL, wxWindowID id = wxID_ANY); + +public: + void SetLabels(wxString const & lbl_on, wxString const & lbl_off); + + void SetTextColor(StateColor const &color); + + void SetTrackColor(StateColor const &color); + + void SetThumbColor(StateColor const &color); + + void SetValue(bool value) override; + + void Rescale(); + +private: + void update(); + +private: + ScalableBitmap m_on; + ScalableBitmap m_off; + + wxString labels[2]; + StateColor text_color; + StateColor track_color; + StateColor thumb_color; +}; + +#endif // !slic3r_GUI_SwitchButton_hpp_ diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp new file mode 100644 index 0000000000..823dd5512d --- /dev/null +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -0,0 +1,230 @@ +#include "TextInput.hpp" +#include "Label.hpp" + +#include + +BEGIN_EVENT_TABLE(TextInput, wxPanel) + +EVT_PAINT(TextInput::paintEvent) + +END_EVENT_TABLE() + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +TextInput::TextInput() + : label_color(std::make_pair(0x909090, (int) StateColor::Disabled), + std::make_pair(0x6B6B6B, (int) StateColor::Normal)) + , text_color(std::make_pair(0x909090, (int) StateColor::Disabled), + std::make_pair(0x262E30, (int) StateColor::Normal)) +{ + radius = 0; + border_width = 1; + border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x00AE42, (int) StateColor::Hovered), + std::make_pair(0xDBDBDB, (int) StateColor::Normal)); + background_color = StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal)); + SetFont(Label::Body_12); +} + +TextInput::TextInput(wxWindow * parent, + wxString text, + wxString label, + wxString icon, + const wxPoint &pos, + const wxSize & size, + long style) + : TextInput() +{ + Create(parent, text, label, icon, pos, size, style); +} + +void TextInput::Create(wxWindow * parent, + wxString text, + wxString label, + wxString icon, + const wxPoint &pos, + const wxSize & size, + long style) +{ + text_ctrl = nullptr; + StaticBox::Create(parent, wxID_ANY, pos, size, style); + wxWindow::SetLabel(label); + style &= ~wxRIGHT; + state_handler.attach({&label_color, & text_color}); + state_handler.update_binds(); + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER); + text_ctrl->SetFont(Label::Body_14); + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + state_handler.attach_child(text_ctrl); + text_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) { + OnEdit(); + e.SetId(GetId()); + ProcessEventLocally(e); + e.Skip(); + }); + text_ctrl->Bind(wxEVT_TEXT_ENTER, [this](auto &e) { + OnEdit(); + e.SetId(GetId()); + ProcessEventLocally(e); + }); + text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu + if (!icon.IsEmpty()) { + this->icon = ScalableBitmap(this, icon.ToStdString(), 16); + } + messureSize(); +} + +void TextInput::SetCornerRadius(double radius) +{ + this->radius = radius; + Refresh(); +} + +void TextInput::SetLabel(const wxString& label) +{ + wxWindow::SetLabel(label); + messureSize(); + Refresh(); +} + +void TextInput::SetIcon(const wxBitmap &icon) +{ + this->icon.bmp() = icon; + Rescale(); +} + +void TextInput::SetLabelColor(StateColor const &color) +{ + label_color = color; + state_handler.update_binds(); +} + +void TextInput::SetTextColor(StateColor const& color) +{ + text_color= color; + state_handler.update_binds(); +} + +void TextInput::Rescale() +{ + if (!this->icon.name().empty()) + this->icon.msw_rescale(); + messureSize(); + Refresh(); +} + +bool TextInput::Enable(bool enable) +{ + bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); + if (result) { + wxCommandEvent e(EVT_ENABLE_CHANGED); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + } + return result; +} + +void TextInput::SetMinSize(const wxSize& size) +{ + wxSize size2 = size; + if (size2.y < 0) { +#ifdef __WXMAC__ + if (GetPeer()) // peer is not ready in Create on mac +#endif + size2.y = GetSize().y; + } + wxWindow::SetMinSize(size2); +} + +void TextInput::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + wxWindow::DoSetSize(x, y, width, height, sizeFlags); + if (sizeFlags & wxSIZE_USE_EXISTING) return; + wxSize size = GetSize(); + wxPoint textPos = {5, 0}; + if (this->icon.bmp().IsOk()) { + wxSize szIcon = this->icon.GetBmpSize(); + textPos.x += szIcon.x; + } + bool align_right = GetWindowStyle() & wxRIGHT; + if (align_right) + textPos.x += labelSize.x; + if (text_ctrl) { + wxSize textSize = text_ctrl->GetSize(); + textSize.x = size.x - textPos.x - labelSize.x - 10; + text_ctrl->SetSize(textSize); + text_ctrl->SetPosition({textPos.x, (size.y - textSize.y) / 2}); + } +} + +void TextInput::DoSetToolTipText(wxString const &tip) +{ + wxWindow::DoSetToolTipText(tip); + text_ctrl->SetToolTip(tip); +} + +void TextInput::paintEvent(wxPaintEvent &evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void TextInput::render(wxDC& dc) +{ + StaticBox::render(dc); + int states = state_handler.states(); + wxSize size = GetSize(); + bool align_right = GetWindowStyle() & wxRIGHT; + // start draw + wxPoint pt = {5, 0}; + if (icon.bmp().IsOk()) { + wxSize szIcon = icon.GetBmpSize(); + pt.y = (size.y - szIcon.y) / 2; + dc.DrawBitmap(icon.bmp(), pt); + pt.x += szIcon.x + 0; + } + auto text = wxWindow::GetLabel(); + if (!text.IsEmpty()) { + wxSize textSize = text_ctrl->GetSize(); + if (align_right) { + if (pt.x + labelSize.x > size.x) + text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x); + pt.y = (size.y - labelSize.y) / 2; + } else { + pt.x += textSize.x; + pt.y = (size.y + textSize.y) / 2 - labelSize.y; + } + dc.SetTextForeground(label_color.colorForStates(states)); + dc.SetFont(GetFont()); + dc.DrawText(text, pt); + } +} + +void TextInput::messureSize() +{ + wxSize size = GetSize(); + wxClientDC dc(this); + labelSize = dc.GetTextExtent(wxWindow::GetLabel()); + wxSize textSize = text_ctrl->GetSize(); + int h = textSize.y + 8; + if (size.y < h) { + size.y = h; + } + wxSize minSize = size; + minSize.x = GetMinWidth(); + SetMinSize(minSize); + SetSize(size); +} diff --git a/src/slic3r/GUI/Widgets/TextInput.hpp b/src/slic3r/GUI/Widgets/TextInput.hpp new file mode 100644 index 0000000000..152fb88f3d --- /dev/null +++ b/src/slic3r/GUI/Widgets/TextInput.hpp @@ -0,0 +1,77 @@ +#ifndef slic3r_GUI_TextInput_hpp_ +#define slic3r_GUI_TextInput_hpp_ + +#include +#include "StaticBox.hpp" + +class TextInput : public wxNavigationEnabled +{ + + wxSize labelSize; + ScalableBitmap icon; + StateColor label_color; + StateColor text_color; + wxTextCtrl * text_ctrl; + + static const int TextInputWidth = 200; + static const int TextInputHeight = 50; + +public: + TextInput(); + + TextInput(wxWindow * parent, + wxString text, + wxString label = "", + wxString icon = "", + const wxPoint &pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = 0); + +public: + void Create(wxWindow * parent, + wxString text, + wxString label = "", + wxString icon = "", + const wxPoint &pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = 0); + + void SetCornerRadius(double radius); + + void SetLabel(const wxString& label); + + void SetIcon(const wxBitmap & icon); + + void SetLabelColor(StateColor const &color); + + void SetTextColor(StateColor const &color); + + virtual void Rescale(); + + virtual bool Enable(bool enable = true) override; + + virtual void SetMinSize(const wxSize& size) override; + + wxTextCtrl *GetTextCtrl() { return text_ctrl; } + + wxTextCtrl const *GetTextCtrl() const { return text_ctrl; } + +protected: + virtual void OnEdit() {} + + virtual void DoSetSize( + int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); + + void DoSetToolTipText(wxString const &tip) override; + +private: + void paintEvent(wxPaintEvent& evt); + + void render(wxDC& dc); + + void messureSize(); + + DECLARE_EVENT_TABLE() +}; + +#endif // !slic3r_GUI_TextInput_hpp_ From c0aef5ff0a4ff2e47acebeae358c2d7b063cfe82 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 19 Jul 2023 15:41:14 +0200 Subject: [PATCH 02/11] Skinned UI: WIP * Non-MSW specific: Next improvements for BG of the controls + Create wrap class BitmapToggleButton to correct create under all platforms + TabFilament: Fixes crash on recreating of the app * Next improvements for background under nonMSW systems + Fixed Field::SpinCtrl::propagate_value * DropDown: Implemented transparent background for rounded corners. + Tab: use TextInput and SwitchButton for substitutions + nonMSW specific: Don't set BackgroundColors for panels * ObjectManipulation: Use TextInput instead wxTextCtrl * Process rectangle/rounded controls + Preferences: Added "Suppress round corners" parameter * Skinned UI: SwitchButton. Use it for CheckBox Field * Skinned UI: SpinInput + ScalableBitmap/ScalableButton respects to different width and height of bitmap. * Skinned UI: ComboBox * Skinned UI: CheckBox --- resources/icons/check_off.svg | 3 + resources/icons/check_off_disabled.svg | 3 + resources/icons/check_off_focused.svg | 3 + resources/icons/check_on.svg | 4 + resources/icons/check_on_disabled.svg | 4 + resources/icons/check_on_focused.svg | 4 + resources/icons/checked.svg | 4 + resources/icons/drop_down.svg | 3 + resources/icons/spin_dec.svg | 3 + resources/icons/spin_dec_act.svg | 3 + resources/icons/spin_inc.svg | 3 + resources/icons/spin_inc_act.svg | 3 + resources/icons/toggle_off.svg | 5 + resources/icons/toggle_on.svg | 4 + src/libslic3r/AppConfig.cpp | 3 + src/slic3r/CMakeLists.txt | 23 ++ src/slic3r/GUI/BitmapCache.cpp | 2 + src/slic3r/GUI/BitmapComboBox.cpp | 8 +- src/slic3r/GUI/BitmapComboBox.hpp | 8 +- src/slic3r/GUI/ButtonsDescription.cpp | 2 +- src/slic3r/GUI/ExtruderSequenceDialog.cpp | 5 +- src/slic3r/GUI/ExtruderSequenceDialog.hpp | 6 +- src/slic3r/GUI/Field.cpp | 245 +++++++++++------- src/slic3r/GUI/Field.hpp | 57 ++-- src/slic3r/GUI/GUI_App.cpp | 5 + src/slic3r/GUI/GUI_App.hpp | 1 + src/slic3r/GUI/GUI_ObjectManipulation.cpp | 36 ++- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 16 +- src/slic3r/GUI/MainFrame.cpp | 7 +- src/slic3r/GUI/MsgDialog.cpp | 4 +- src/slic3r/GUI/MsgDialog.hpp | 4 +- src/slic3r/GUI/OG_CustomCtrl.cpp | 3 +- src/slic3r/GUI/OptionsGroup.cpp | 1 + src/slic3r/GUI/Plater.cpp | 6 +- src/slic3r/GUI/Preferences.cpp | 13 +- src/slic3r/GUI/PresetComboBoxes.cpp | 3 + src/slic3r/GUI/Search.cpp | 4 +- src/slic3r/GUI/Search.hpp | 7 +- src/slic3r/GUI/Tab.cpp | 118 +++++---- src/slic3r/GUI/Tab.hpp | 6 +- src/slic3r/GUI/Widgets/BitmapToggleButton.cpp | 47 ++++ src/slic3r/GUI/Widgets/BitmapToggleButton.hpp | 17 ++ src/slic3r/GUI/Widgets/Button.cpp | 29 +-- src/slic3r/GUI/Widgets/Button.hpp | 4 +- src/slic3r/GUI/Widgets/CheckBox.cpp | 70 +++-- src/slic3r/GUI/Widgets/CheckBox.hpp | 34 +-- src/slic3r/GUI/Widgets/ComboBox.cpp | 113 +++++--- src/slic3r/GUI/Widgets/ComboBox.hpp | 18 +- src/slic3r/GUI/Widgets/DropDown.cpp | 100 +++++-- src/slic3r/GUI/Widgets/DropDown.hpp | 22 +- src/slic3r/GUI/Widgets/Label.cpp | 2 + src/slic3r/GUI/Widgets/Label.hpp | 1 + src/slic3r/GUI/Widgets/SpinInput.cpp | 131 ++++++++-- src/slic3r/GUI/Widgets/SpinInput.hpp | 20 +- src/slic3r/GUI/Widgets/StateHandler.cpp | 2 + src/slic3r/GUI/Widgets/StateHandler.hpp | 1 + src/slic3r/GUI/Widgets/StaticBox.cpp | 112 ++++---- src/slic3r/GUI/Widgets/StaticBox.hpp | 5 +- src/slic3r/GUI/Widgets/SwitchButton.cpp | 36 +-- src/slic3r/GUI/Widgets/SwitchButton.hpp | 10 +- src/slic3r/GUI/Widgets/TextInput.cpp | 164 +++++++++--- src/slic3r/GUI/Widgets/TextInput.hpp | 26 +- src/slic3r/GUI/Widgets/UIColors.hpp | 18 ++ src/slic3r/GUI/wxExtensions.cpp | 51 ++-- src/slic3r/GUI/wxExtensions.hpp | 43 ++- 65 files changed, 1181 insertions(+), 537 deletions(-) create mode 100644 resources/icons/check_off.svg create mode 100644 resources/icons/check_off_disabled.svg create mode 100644 resources/icons/check_off_focused.svg create mode 100644 resources/icons/check_on.svg create mode 100644 resources/icons/check_on_disabled.svg create mode 100644 resources/icons/check_on_focused.svg create mode 100644 resources/icons/checked.svg create mode 100644 resources/icons/drop_down.svg create mode 100644 resources/icons/spin_dec.svg create mode 100644 resources/icons/spin_dec_act.svg create mode 100644 resources/icons/spin_inc.svg create mode 100644 resources/icons/spin_inc_act.svg create mode 100644 resources/icons/toggle_off.svg create mode 100644 resources/icons/toggle_on.svg create mode 100644 src/slic3r/GUI/Widgets/BitmapToggleButton.cpp create mode 100644 src/slic3r/GUI/Widgets/BitmapToggleButton.hpp create mode 100644 src/slic3r/GUI/Widgets/UIColors.hpp diff --git a/resources/icons/check_off.svg b/resources/icons/check_off.svg new file mode 100644 index 0000000000..f28cba5ea4 --- /dev/null +++ b/resources/icons/check_off.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/check_off_disabled.svg b/resources/icons/check_off_disabled.svg new file mode 100644 index 0000000000..492a88ea83 --- /dev/null +++ b/resources/icons/check_off_disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/check_off_focused.svg b/resources/icons/check_off_focused.svg new file mode 100644 index 0000000000..3fb1ab9bc2 --- /dev/null +++ b/resources/icons/check_off_focused.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/check_on.svg b/resources/icons/check_on.svg new file mode 100644 index 0000000000..62c23441a9 --- /dev/null +++ b/resources/icons/check_on.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/check_on_disabled.svg b/resources/icons/check_on_disabled.svg new file mode 100644 index 0000000000..2c00ecfa59 --- /dev/null +++ b/resources/icons/check_on_disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/check_on_focused.svg b/resources/icons/check_on_focused.svg new file mode 100644 index 0000000000..6b4e7935e1 --- /dev/null +++ b/resources/icons/check_on_focused.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/checked.svg b/resources/icons/checked.svg new file mode 100644 index 0000000000..88747cb95d --- /dev/null +++ b/resources/icons/checked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/drop_down.svg b/resources/icons/drop_down.svg new file mode 100644 index 0000000000..3354ddc295 --- /dev/null +++ b/resources/icons/drop_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/spin_dec.svg b/resources/icons/spin_dec.svg new file mode 100644 index 0000000000..889ad9ce23 --- /dev/null +++ b/resources/icons/spin_dec.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/spin_dec_act.svg b/resources/icons/spin_dec_act.svg new file mode 100644 index 0000000000..a9924d8235 --- /dev/null +++ b/resources/icons/spin_dec_act.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/spin_inc.svg b/resources/icons/spin_inc.svg new file mode 100644 index 0000000000..cf6b3a6998 --- /dev/null +++ b/resources/icons/spin_inc.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/spin_inc_act.svg b/resources/icons/spin_inc_act.svg new file mode 100644 index 0000000000..e052bb7644 --- /dev/null +++ b/resources/icons/spin_inc_act.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/toggle_off.svg b/resources/icons/toggle_off.svg new file mode 100644 index 0000000000..4a7925a155 --- /dev/null +++ b/resources/icons/toggle_off.svg @@ -0,0 +1,5 @@ + + + rect x="1" y="1.00293" width="22" height="12" rx="6" fill="#BBG"/--> + + diff --git a/resources/icons/toggle_on.svg b/resources/icons/toggle_on.svg new file mode 100644 index 0000000000..caae9478be --- /dev/null +++ b/resources/icons/toggle_on.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 426cc53309..4bf4b4a2cd 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -104,6 +104,9 @@ void AppConfig::set_defaults() if (get("tabs_as_menu").empty()) set("tabs_as_menu", "0"); + + if (get("suppress_round_corners").empty()) + set("suppress_round_corners", "1"); #endif // _WIN32 // remove old 'use_legacy_opengl' parameter from this config, if present diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 8f9900bbf2..5eee8dd7e4 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -256,6 +256,29 @@ set(SLIC3R_GUI_SOURCES GUI/DesktopIntegrationDialog.hpp GUI/HintNotification.cpp GUI/HintNotification.hpp + GUI/Widgets/BitmapToggleButton.cpp + GUI/Widgets/BitmapToggleButton.hpp + GUI/Widgets/Button.cpp + GUI/Widgets/Button.hpp + GUI/Widgets/CheckBox.cpp + GUI/Widgets/CheckBox.hpp + GUI/Widgets/ComboBox.cpp + GUI/Widgets/ComboBox.hpp + GUI/Widgets/DropDown.cpp + GUI/Widgets/DropDown.hpp + GUI/Widgets/StateColor.cpp + GUI/Widgets/StateColor.hpp + GUI/Widgets/StateHandler.cpp + GUI/Widgets/StateHandler.hpp + GUI/Widgets/StaticBox.cpp + GUI/Widgets/StaticBox.hpp + GUI/Widgets/SpinInput.cpp + GUI/Widgets/SpinInput.hpp + GUI/Widgets/SwitchButton.cpp + GUI/Widgets/SwitchButton.hpp + GUI/Widgets/TextInput.cpp + GUI/Widgets/TextInput.hpp + GUI/Widgets/UIColors.hpp GUI/FileArchiveDialog.cpp GUI/FileArchiveDialog.hpp GUI/Downloader.cpp diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 10f7277309..98b2889aa1 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -414,6 +414,8 @@ wxBitmapBundle* BitmapCache::from_svg(const std::string& bitmap_name, unsigned t if (!new_color.empty()) replaces["\"#ED6B21\""] = "\"" + new_color + "\""; + replaces["\"#ButtonBG\""] = dark_mode ? "\"#4E4E4E\"" : "\"#828282\""; + std::string str; nsvgGetDataFromFileWithReplace(Slic3r::var(bitmap_name + ".svg").c_str(), str, replaces); if (str.empty()) diff --git a/src/slic3r/GUI/BitmapComboBox.cpp b/src/slic3r/GUI/BitmapComboBox.cpp index 465eb4822b..2c50ab8cf7 100644 --- a/src/slic3r/GUI/BitmapComboBox.cpp +++ b/src/slic3r/GUI/BitmapComboBox.cpp @@ -66,10 +66,11 @@ BitmapComboBox::BitmapComboBox(wxWindow* parent, int n/* = 0*/, const wxString choices[]/* = NULL*/, long style/* = 0*/) : - wxBitmapComboBox(parent, id, value, pos, size, n, choices, style) +// wxBitmapComboBox(parent, id, value, pos, size, n, choices, style) + ::ComboBox(parent, id, value, pos, size, n, choices, style | DD_NO_CHECK_ICON) { SetFont(Slic3r::GUI::wxGetApp().normal_font()); -#ifdef _WIN32 +#if 0 //#ifdef _WIN32 // Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that // the index of the item inside CBN_EDITCHANGE may no more be valid. EnableTextChangedEvents(false); @@ -79,11 +80,12 @@ BitmapComboBox::BitmapComboBox(wxWindow* parent, #endif /* _WIN32 */ } +#if 0 BitmapComboBox::~BitmapComboBox() { } -#ifdef _WIN32 +//#ifdef _WIN32 int BitmapComboBox::Append(const wxString& item) { diff --git a/src/slic3r/GUI/BitmapComboBox.hpp b/src/slic3r/GUI/BitmapComboBox.hpp index 07031f6bf2..e1398ec041 100644 --- a/src/slic3r/GUI/BitmapComboBox.hpp +++ b/src/slic3r/GUI/BitmapComboBox.hpp @@ -8,6 +8,8 @@ #include #include +#include "Widgets/ComboBox.hpp" + #include "GUI_Utils.hpp" // --------------------------------- @@ -17,7 +19,8 @@ namespace Slic3r { namespace GUI { // BitmapComboBox used to presets list on Sidebar and Tabs -class BitmapComboBox : public wxBitmapComboBox +//class BitmapComboBox : public wxBitmapComboBox +class BitmapComboBox : public ::ComboBox { public: BitmapComboBox(wxWindow* parent, @@ -28,6 +31,7 @@ BitmapComboBox(wxWindow* parent, int n = 0, const wxString choices[] = NULL, long style = 0); +#if 0 ~BitmapComboBox(); #ifdef _WIN32 @@ -40,7 +44,7 @@ BitmapComboBox(wxWindow* parent, protected: -#ifdef _WIN32 +//#ifdef _WIN32 bool MSWOnDraw(WXDRAWITEMSTRUCT* item) override; void DrawBackground_(wxDC& dc, const wxRect& rect, int WXUNUSED(item), int flags) const; public: diff --git a/src/slic3r/GUI/ButtonsDescription.cpp b/src/slic3r/GUI/ButtonsDescription.cpp index 105dbe777d..08d1cb76c8 100644 --- a/src/slic3r/GUI/ButtonsDescription.cpp +++ b/src/slic3r/GUI/ButtonsDescription.cpp @@ -78,7 +78,7 @@ wxBitmapBundle * ModePaletteComboBox::get_bmp(const std::vector &pa // Create the bitmap with color bars. std::vector bmps; for (const auto& color : palette) { - bmps.emplace_back(get_bmp_bundle("mode", icon_height, color)); + bmps.emplace_back(get_bmp_bundle("mode", icon_height, icon_height, color)); bmps.emplace_back(get_empty_bmp_bundle(wxOSX ? 5 : 6, icon_height)); } bmp_bndl = bitmap_cache().insert_bndl(bitmap_key, bmps); diff --git a/src/slic3r/GUI/ExtruderSequenceDialog.cpp b/src/slic3r/GUI/ExtruderSequenceDialog.cpp index ca2fee15e6..1268b3595f 100644 --- a/src/slic3r/GUI/ExtruderSequenceDialog.cpp +++ b/src/slic3r/GUI/ExtruderSequenceDialog.cpp @@ -22,6 +22,7 @@ #include "MainFrame.hpp" #include "BitmapComboBox.hpp" +#include "Widgets/CheckBox.hpp" namespace Slic3r { namespace GUI { @@ -165,7 +166,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ intervals_box_sizer->Add(m_intervals_grid_sizer, 0, wxLEFT, em); option_sizer->Add(intervals_box_sizer, 0, wxEXPAND); - m_random_sequence = new wxCheckBox(this, wxID_ANY, _L("Random sequence")); + m_random_sequence = new ::CheckBox(this, _L("Random sequence")); m_random_sequence->SetValue(m_sequence.random_sequence); m_random_sequence->SetToolTip(_L("If enabled, random sequence of the selected extruders will be used.")); m_random_sequence->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) { @@ -173,7 +174,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ m_color_repetition->Enable(m_sequence.random_sequence); }); - m_color_repetition = new wxCheckBox(this, wxID_ANY, _L("Allow next color repetition")); + m_color_repetition = new ::CheckBox(this, _L("Allow next color repetition")); m_color_repetition->SetValue(m_sequence.color_repetition); m_color_repetition->SetToolTip(_L("If enabled, a repetition of the next random color will be allowed.")); m_color_repetition->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {m_sequence.color_repetition = e.IsChecked(); }); diff --git a/src/slic3r/GUI/ExtruderSequenceDialog.hpp b/src/slic3r/GUI/ExtruderSequenceDialog.hpp index 1c986682c9..61cd057425 100644 --- a/src/slic3r/GUI/ExtruderSequenceDialog.hpp +++ b/src/slic3r/GUI/ExtruderSequenceDialog.hpp @@ -10,7 +10,7 @@ class wxTextCtrl; class wxFlexGridSizer; -class wxCheckBox; +class CheckBox; namespace Slic3r { namespace GUI { @@ -27,8 +27,8 @@ class ExtruderSequenceDialog: public DPIDialog wxTextCtrl* m_interval_by_layers {nullptr}; wxTextCtrl* m_interval_by_mm {nullptr}; - wxCheckBox* m_random_sequence {nullptr}; - wxCheckBox* m_color_repetition{nullptr}; + CheckBox* m_random_sequence {nullptr}; + CheckBox* m_color_repetition{nullptr}; wxFlexGridSizer* m_intervals_grid_sizer {nullptr}; wxFlexGridSizer* m_extruders_grid_sizer {nullptr}; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index c93a831927..9a8c0287c3 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -28,6 +28,8 @@ #include "MsgDialog.hpp" #include "BitmapComboBox.hpp" +#include "Widgets/ComboBox.hpp" + #ifdef __WXOSX__ #define wxOSX true #else @@ -102,8 +104,6 @@ Field::~Field() void Field::PostInitialize() { - auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - switch (m_opt.type) { case coPercents: @@ -488,10 +488,7 @@ void TextCtrl::BUILD() { } long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER; -#ifdef _WIN32 - style |= wxBORDER_SIMPLE; -#endif - auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style); + auto temp = new text_ctrl(m_parent, text_value, "", "", wxDefaultPosition, size, style); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double)temp->GetSize().GetHeight()/m_em_unit; temp->SetFont(m_opt.is_code ? @@ -503,9 +500,6 @@ void TextCtrl::BUILD() { // Only disable background refresh for single line input fields, as they are completely painted over by the edit control. // This does not apply to the multi-line edit field, where the last line and a narrow frame around the text is not cleared. temp->SetBackgroundStyle(wxBG_STYLE_PAINT); -#ifdef __WXOSX__ - temp->OSXDisableAllSmartSubstitutions(); -#endif // __WXOSX__ temp->SetToolTip(get_tooltip_text(text_value)); @@ -562,7 +556,7 @@ bool TextCtrl::value_was_changed() return true; boost::any val = m_value; - wxString ret_str = static_cast(window)->GetValue(); + wxString ret_str = static_cast(window)->GetValue(); // update m_value! // ret_str might be changed inside get_value_by_opt_type get_value_by_opt_type(ret_str); @@ -593,11 +587,11 @@ bool TextCtrl::value_was_changed() void TextCtrl::propagate_value() { - wxString val = dynamic_cast(window)->GetValue(); + wxString val = dynamic_cast(window)->GetValue(); if (m_opt.nullable && val != na_value()) m_last_meaningful_value = val; - if (!is_defined_input_value(window, m_opt.type) ) + if (!is_defined_input_value(window, m_opt.type) ) // on_kill_focus() cause a call of OptionsGroup::reload_config(), // Thus, do it only when it's really needed (when undefined value was input) on_kill_focus(); @@ -611,14 +605,14 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) const bool m_is_na_val = boost::any_cast(value) == na_value(); if (!m_is_na_val) m_last_meaningful_value = value; - dynamic_cast(window)->SetValue(m_is_na_val ? na_value() : boost::any_cast(value)); + dynamic_cast(window)->SetValue(m_is_na_val ? na_value() : boost::any_cast(value)); } else - dynamic_cast(window)->SetValue(boost::any_cast(value)); + dynamic_cast(window)->SetValue(boost::any_cast(value)); m_disable_change_event = false; if (!change_event) { - wxString ret_str = static_cast(window)->GetValue(); + wxString ret_str = static_cast(window)->GetValue(); /* Update m_value to correct work of next value_was_changed(). * But after checking of entered value, don't fix the "incorrect" value and don't show a warning message, * just clear m_value in this case. @@ -629,19 +623,19 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) void TextCtrl::set_last_meaningful_value() { - dynamic_cast(window)->SetValue(boost::any_cast(m_last_meaningful_value)); + dynamic_cast(window)->SetValue(boost::any_cast(m_last_meaningful_value)); propagate_value(); } void TextCtrl::set_na_value() { - dynamic_cast(window)->SetValue(na_value()); + dynamic_cast(window)->SetValue(na_value()); propagate_value(); } boost::any& TextCtrl::get_value() { - wxString ret_str = static_cast(window)->GetValue(); + wxString ret_str = static_cast(window)->GetValue(); // update m_value get_value_by_opt_type(ret_str); @@ -659,8 +653,11 @@ void TextCtrl::msw_rescale() size.SetHeight(lround(opt_height*m_em_unit)); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); - if (size != wxDefaultSize) - { + if (size != wxDefaultSize) { + if (::TextInput* text_input = dynamic_cast<::TextInput*>(window)) { + text_input->SetCtrlSize(size); + return; + } wxTextCtrl* field = dynamic_cast(window); if (parent_is_custom_ctrl) field->SetSize(size); @@ -670,8 +667,8 @@ void TextCtrl::msw_rescale() } -void TextCtrl::enable() { dynamic_cast(window)->Enable(); dynamic_cast(window)->SetEditable(true); } -void TextCtrl::disable() { dynamic_cast(window)->Disable(); dynamic_cast(window)->SetEditable(false); } +void TextCtrl::enable() { dynamic_cast(window)->Enable(); } +void TextCtrl::disable() { dynamic_cast(window)->Disable();} #ifdef __WXGTK__ void TextCtrl::change_field_value(wxEvent& event) @@ -682,10 +679,71 @@ void TextCtrl::change_field_value(wxEvent& event) }; #endif //__WXGTK__ + +wxWindow* CheckBox::GetNewWin(wxWindow* parent, const wxString& label /*= wxEmptyString*/) +{ + if (wxGetApp().suppress_round_corners()) + return new ::CheckBox(parent, label); + + return new ::SwitchButton(parent, label); +} + +void CheckBox::SetValue(wxWindow* win, bool value) +{ + if (wxGetApp().suppress_round_corners()) { + if (::CheckBox* ch_b = dynamic_cast<::CheckBox*>(win)) + ch_b->SetValue(value); + } + else { + if (::SwitchButton* ch_b = dynamic_cast<::SwitchButton*>(win)) + ch_b->SetValue(value); + } +} + +bool CheckBox::GetValue(wxWindow* win) +{ + if (wxGetApp().suppress_round_corners()) + return dynamic_cast<::CheckBox*>(win)->GetValue(); + + return dynamic_cast<::SwitchButton*>(win)->GetValue(); +} + +void CheckBox::Rescale(wxWindow* win) +{ + if (wxGetApp().suppress_round_corners()) + dynamic_cast<::CheckBox*>(win)->Rescale(); + else + dynamic_cast<::SwitchButton*>(win)->Rescale(); +} + +void CheckBox::SysColorChanged(wxWindow* win) +{ + if (!wxGetApp().suppress_round_corners()) + dynamic_cast<::SwitchButton*>(win)->SysColorChange(); +} + +void CheckBox::SetValue(bool value) +{ + if (wxGetApp().suppress_round_corners()) + dynamic_cast<::CheckBox*>(window)->SetValue(value); + else + dynamic_cast<::SwitchButton*>(window)->SetValue(value); +} + +bool CheckBox::GetValue() +{ + if (wxGetApp().suppress_round_corners()) + return dynamic_cast<::CheckBox*>(window)->GetValue(); + + return dynamic_cast<::SwitchButton*>(window)->GetValue(); +} + void CheckBox::BUILD() { auto size = wxSize(wxDefaultSize); - if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); - if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); + if (m_opt.height >= 0) + size.SetHeight(m_opt.height*m_em_unit); + if (m_opt.width >= 0) + size.SetWidth(m_opt.width*m_em_unit); bool check_value = m_opt.type == coBool ? m_opt.default_value->getBool() : m_opt.type == coBools ? @@ -695,21 +753,29 @@ void CheckBox::BUILD() { m_last_meaningful_value = static_cast(check_value); // Set Label as a string of at least one space simbol to correct system scaling of a CheckBox - auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size); - temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); - temp->SetValue(check_value); - if (m_opt.readonly) temp->Disable(); + window = GetNewWin(m_parent); + wxGetApp().UpdateDarkUI(window); + window->SetFont(wxGetApp().normal_font()); + if (!wxOSX) + window->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (m_opt.readonly) + window->Disable(); - temp->Bind(wxEVT_CHECKBOX, ([this](wxCommandEvent e) { + SetValue(check_value); + + window->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent e) { m_is_na_val = false; on_change_field(); - }), temp->GetId()); + }); - temp->SetToolTip(get_tooltip_text(check_value ? "true" : "false")); + window->SetToolTip(get_tooltip_text(check_value ? "true" : "false")); +} - // recast as a wxWindow to fit the calling convention - window = dynamic_cast(temp); +void CheckBox::set_value(const bool value, bool change_event/* = false*/) +{ + m_disable_change_event = !change_event; + SetValue(value); + m_disable_change_event = false; } void CheckBox::set_value(const boost::any& value, bool change_event) @@ -719,10 +785,10 @@ void CheckBox::set_value(const boost::any& value, bool change_event) m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::nil_value(); if (!m_is_na_val) m_last_meaningful_value = value; - dynamic_cast(window)->SetValue(m_is_na_val ? false : boost::any_cast(value) != 0); + SetValue(m_is_na_val ? false : boost::any_cast(value) != 0); } else - dynamic_cast(window)->SetValue(boost::any_cast(value)); + SetValue(boost::any_cast(value)); m_disable_change_event = false; } @@ -730,7 +796,7 @@ void CheckBox::set_last_meaningful_value() { if (m_opt.nullable) { m_is_na_val = false; - dynamic_cast(window)->SetValue(boost::any_cast(m_last_meaningful_value) != 0); + SetValue(boost::any_cast(m_last_meaningful_value) != 0); on_change_field(); } } @@ -739,15 +805,13 @@ void CheckBox::set_na_value() { if (m_opt.nullable) { m_is_na_val = true; - dynamic_cast(window)->SetValue(false); on_change_field(); } } boost::any& CheckBox::get_value() { -// boost::any m_value; - bool value = dynamic_cast(window)->GetValue(); + bool value = GetValue(); if (m_opt.type == coBool) m_value = static_cast(value); else @@ -761,6 +825,23 @@ void CheckBox::msw_rescale() window->SetInitialSize(window->GetBestSize()); } +void CheckBox::sys_color_changed() +{ + Field::sys_color_changed(); + if (auto switch_btn = dynamic_cast<::SwitchButton*>(window)) + switch_btn->SysColorChange(); +} + +void CheckBox::enable() +{ + window->Enable(); +} + +void CheckBox::disable() +{ + window->Disable(); +} + void SpinCtrl::BUILD() { auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); @@ -804,11 +885,9 @@ void SpinCtrl::BUILD() { ? (int)0 : (int)m_opt.min; const int max_val = m_opt.max < FLT_MAX ? (int)m_opt.max : INT_MAX; - auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, + auto temp = new ::SpinInput(m_parent, text_value, "", wxDefaultPosition, size, wxTE_PROCESS_ENTER | wxSP_ARROW_KEYS -#ifdef _WIN32 - | wxBORDER_SIMPLE -#endif + , min_val, max_val, default_value); #ifdef __WXGTK3__ @@ -823,14 +902,7 @@ void SpinCtrl::BUILD() { if (m_opt.height < 0 && parent_is_custom_ctrl) opt_height = (double)temp->GetSize().GetHeight() / m_em_unit; -// XXX: On OS X the wxSpinCtrl widget is made up of two subwidgets, unfortunatelly -// the kill focus event is not propagated to the encompassing widget, -// so we need to bind it on the inner text widget instead. (Ugh.) -#ifdef __WXOSX__ - temp->GetText()->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) -#else temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) -#endif { e.Skip(); if (bEnterPressed) { @@ -849,29 +921,16 @@ void SpinCtrl::BUILD() { propagate_value(); bEnterPressed = true; }), temp->GetId()); + temp->SetToolTip(get_tooltip_text(text_value)); - temp->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent e) - { -// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value -// # when it was changed from the text control, so the on_change callback -// # gets the old one, and on_kill_focus resets the control to the old value. -// # As a workaround, we get the new value from $event->GetString and store -// # here temporarily so that we can return it from get_value() - - long value; - const bool parsed = e.GetString().ToLong(&value); - if (!parsed || value < INT_MIN || value > INT_MAX) + temp->Bind(wxEVT_TEXT, [this, temp](wxCommandEvent e) { + long value; + if (!e.GetString().ToLong(&value)) + return; + if (value < INT_MIN || value > INT_MAX) tmp_value = UNDEF_VALUE; else { tmp_value = std::min(std::max((int)value, temp->GetMin()), temp->GetMax()); -#ifdef __WXOSX__ - // Forcibly set the input value for SpinControl, since the value - // inserted from the keyboard or clipboard is not updated under OSX - temp->SetValue(tmp_value); - // But in SetValue() is executed m_text_ctrl->SelectAll(), so - // discard this selection and set insertion point to the end of string - temp->GetText()->SetInsertionPointEnd(); -#else // update value for the control only if it was changed in respect to the Min/max values if (tmp_value != (int)value) { temp->SetValue(tmp_value); @@ -880,11 +939,8 @@ void SpinCtrl::BUILD() { int pos = std::to_string(tmp_value).length(); temp->SetSelection(pos, pos); } -#endif } - }), temp->GetId()); - - temp->SetToolTip(get_tooltip_text(text_value)); + }, temp->GetId()); // recast as a wxWindow to fit the calling convention window = dynamic_cast(temp); @@ -898,35 +954,35 @@ void SpinCtrl::set_value(const boost::any& value, bool change_event/* = false*/) if (m_opt.nullable) { const bool m_is_na_val = tmp_value == ConfigOptionIntsNullable::nil_value(); if (m_is_na_val) - dynamic_cast(window)->SetValue(na_value(true)); + dynamic_cast<::SpinInput*>(window)->SetValue(na_value(true)); else { m_last_meaningful_value = value; - dynamic_cast(window)->SetValue(tmp_value); + dynamic_cast<::SpinInput*>(window)->SetValue(tmp_value); } } else - dynamic_cast(window)->SetValue(tmp_value); + dynamic_cast<::SpinInput*>(window)->SetValue(tmp_value); m_disable_change_event = false; } void SpinCtrl::set_last_meaningful_value() { const int val = boost::any_cast(m_last_meaningful_value); - dynamic_cast(window)->SetValue(val); + dynamic_cast<::SpinInput*>(window)->SetValue(val); tmp_value = val; propagate_value(); } void SpinCtrl::set_na_value() { - dynamic_cast(window)->SetValue(na_value(true)); + dynamic_cast<::SpinInput*>(window)->SetValue(na_value(true)); m_value = ConfigOptionIntsNullable::nil_value(); propagate_value(); } boost::any& SpinCtrl::get_value() { - wxSpinCtrl* spin = static_cast(window); + ::SpinInput* spin = static_cast<::SpinInput*>(window); if (spin->GetTextValue() == na_value(true)) return m_value; @@ -949,7 +1005,7 @@ void SpinCtrl::propagate_value() #ifdef __WXOSX__ // check input value for minimum if (m_opt.min > 0 && tmp_value < m_opt.min) { - wxSpinCtrl* spin = static_cast(window); + ::SpinInput* spin = static_cast<::SpinInput*>(window); spin->SetValue(m_opt.min); spin->GetText()->SetInsertionPointEnd(); } @@ -962,13 +1018,16 @@ void SpinCtrl::msw_rescale() { Field::msw_rescale(); - wxSpinCtrl* field = dynamic_cast(window); + auto field = dynamic_cast<::SpinInput*>(window); if (parent_is_custom_ctrl) field->SetSize(wxSize(def_width() * m_em_unit, lround(opt_height * m_em_unit))); else field->SetMinSize(wxSize(def_width() * m_em_unit, int(1.9f*field->GetFont().GetPixelSize().y))); } +#if 1 +using choice_ctrl = ::ComboBox; +#else #ifdef __WXOSX__ static_assert(wxMAJOR_VERSION >= 3, "Use of wxBitmapComboBox on Settings Tabs requires wxWidgets 3.0 and newer"); using choice_ctrl = wxBitmapComboBox; @@ -979,6 +1038,7 @@ using choice_ctrl = BitmapComboBox; using choice_ctrl = wxComboBox; #endif #endif // __WXOSX__ +#endif void Choice::BUILD() { wxSize size(def_width_wider() * m_em_unit, wxDefaultCoord); @@ -989,10 +1049,10 @@ void Choice::BUILD() { if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_close) { m_is_editable = true; - temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxTE_PROCESS_ENTER); + temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxTE_PROCESS_ENTER | DD_NO_CHECK_ICON); } else { -#ifdef __WXOSX__ +#if 0 //#ifdef __WXOSX__ /* wxBitmapComboBox with wxCB_READONLY style return NULL for GetTextCtrl(), * so ToolTip doesn't shown. * Next workaround helps to solve this problem @@ -1001,7 +1061,7 @@ void Choice::BUILD() { temp->SetTextCtrlStyle(wxTE_READONLY); temp->Create(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr); #else - temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY); + temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY | DD_NO_CHECK_ICON); #endif //__WXOSX__ } @@ -1458,18 +1518,15 @@ void PointCtrl::BUILD() wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); long style = wxTE_PROCESS_ENTER; -#ifdef _WIN32 - style |= wxBORDER_SIMPLE; -#endif - x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, style); - y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, style); + x_textctrl = new text_ctrl(m_parent, X, "", "", wxDefaultPosition, field_size, style); + y_textctrl = new text_ctrl(m_parent, Y, "", "", wxDefaultPosition, field_size, style); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double)x_textctrl->GetSize().GetHeight() / m_em_unit; x_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - x_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) x_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); y_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - y_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) y_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); auto static_text_x = new wxStaticText(m_parent, wxID_ANY, "x : "); auto static_text_y = new wxStaticText(m_parent, wxID_ANY, " y : "); @@ -1527,7 +1584,7 @@ void PointCtrl::sys_color_changed() #endif } -bool PointCtrl::value_was_changed(wxTextCtrl* win) +bool PointCtrl::value_was_changed(text_ctrl* win) { if (m_value.empty()) return true; @@ -1539,7 +1596,7 @@ bool PointCtrl::value_was_changed(wxTextCtrl* win) return boost::any_cast(m_value) != boost::any_cast(val); } -void PointCtrl::propagate_value(wxTextCtrl* win) +void PointCtrl::propagate_value(text_ctrl* win) { if (win->GetValue().empty()) on_kill_focus(); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index bdc8199136..2d9625e499 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -25,6 +25,10 @@ #include "GUI.hpp" #include "wxExtensions.hpp" +#include "Widgets/CheckBox.hpp" +#include "Widgets/SwitchButton.hpp" +#include "Widgets/SpinInput.hpp" +#include "Widgets/TextInput.hpp" #ifdef __WXMSW__ #define wxMSW true @@ -294,6 +298,8 @@ inline bool is_window_field(const t_field& obj) { return !is_bad_field(obj) && o /// Covenience function to determine whether this field is a valid sizer field. inline bool is_sizer_field(const t_field& obj) { return !is_bad_field(obj) && obj->getSizer() != nullptr; } +using text_ctrl = ::TextInput; //wxTextCtrl + class TextCtrl : public Field { using Field::Field; #ifdef __WXGTK__ @@ -314,7 +320,7 @@ public: void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; - dynamic_cast(window)->SetValue(wxString(value)); + dynamic_cast(window)->SetValue(wxString(value)); m_disable_change_event = false; } void set_value(const boost::any& value, bool change_event = false) override; @@ -338,24 +344,31 @@ public: CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} ~CheckBox() {} + static wxWindow* GetNewWin(wxWindow* parent, const wxString& label = wxEmptyString); + static void SetValue(wxWindow* win, bool value); + static bool GetValue(wxWindow* win); + static void Rescale(wxWindow* win); + static void SysColorChanged(wxWindow* win); + wxWindow* window{ nullptr }; void BUILD() override; - void set_value(const bool value, bool change_event = false) { - m_disable_change_event = !change_event; - dynamic_cast(window)->SetValue(value); - m_disable_change_event = false; - } + void set_value(const bool value, bool change_event = false); void set_value(const boost::any& value, bool change_event = false) override; void set_last_meaningful_value() override; void set_na_value() override; boost::any& get_value() override; void msw_rescale() override; + void sys_color_changed() override; - void enable() override { dynamic_cast(window)->Enable(); } - void disable() override { dynamic_cast(window)->Disable(); } + void enable() override; + void disable() override; wxWindow* getWindow() override { return window; } + +private: + void SetValue(bool value); + bool GetValue(); }; class SpinCtrl : public Field { @@ -377,20 +390,32 @@ public: /* void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; - dynamic_cast(window)->SetValue(value); + dynamic_cast<::SpinInput*>(window)->SetValue(value); m_disable_change_event = false; } + void set_value(const boost::any& value, bool change_event = false) override { + m_disable_change_event = !change_event; + tmp_value = boost::any_cast(value); + m_value = value; + dynamic_cast<::SpinInput*>(window)->SetValue(tmp_value); + m_disable_change_event = false; + } */ void set_value(const boost::any& value, bool change_event = false) override; void set_last_meaningful_value() override; void set_na_value() override; boost::any& get_value() override; - +/* + boost::any& get_value() override { + int value = static_cast<::SpinInput*>(window)->GetValue(); + return m_value = value; + } +*/ void msw_rescale() override; - void enable() override { dynamic_cast(window)->Enable(); } - void disable() override { dynamic_cast(window)->Disable(); } + void enable() override { dynamic_cast<::SpinInput*>(window)->Enable(); } + void disable() override { dynamic_cast<::SpinInput*>(window)->Disable(); } wxWindow* getWindow() override { return window; } }; @@ -466,13 +491,13 @@ public: ~PointCtrl(); wxSizer* sizer{ nullptr }; - wxTextCtrl* x_textctrl{ nullptr }; - wxTextCtrl* y_textctrl{ nullptr }; + text_ctrl* x_textctrl{ nullptr }; + text_ctrl* y_textctrl{ nullptr }; void BUILD() override; - bool value_was_changed(wxTextCtrl* win); + bool value_was_changed(text_ctrl* win); // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER - void propagate_value(wxTextCtrl* win); + void propagate_value(text_ctrl* win); void set_value(const Vec2d& value, bool change_event = false); void set_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 41745e843c..04c2c5c506 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1756,6 +1756,11 @@ bool GUI_App::tabs_as_menu() const return app_config->get_bool("tabs_as_menu"); // || dark_mode(); } +bool GUI_App::suppress_round_corners() const +{ + return app_config->get("suppress_round_corners") == "1"; +} + wxSize GUI_App::get_min_size() const { return wxSize(76*m_em_unit, 49 * m_em_unit); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 039818e012..fb4e1d87ab 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -248,6 +248,7 @@ public: const wxFont& link_font() { return m_link_font; } int em_unit() const { return m_em_unit; } bool tabs_as_menu() const; + bool suppress_round_corners() const; wxSize get_min_size() const; float toolbar_icon_scale(const bool is_limited = false) const; void set_auto_toolbar_icon_scale(float scale) const; diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 0b7534b1d6..19b8b3e108 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -25,6 +25,8 @@ #include #include "slic3r/Utils/FixModelByWin10.hpp" +#include "Widgets/CheckBox.hpp" + // For special mirroring in manipulation gizmo #include "Gizmos/GLGizmosManager.hpp" #include "Gizmos/GLGizmoEmboss.hpp" @@ -77,7 +79,7 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent) wxSize size(15 * wxGetApp().em_unit(), -1); choice_ctrl* temp = nullptr; -#ifdef __WXOSX__ +#if 0//def __WXOSX__ /* wxBitmapComboBox with wxCB_READONLY style return NULL for GetTextCtrl(), * so ToolTip doesn't shown. * Next workaround helps to solve this problem @@ -86,7 +88,7 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent) temp->SetTextCtrlStyle(wxTE_READONLY); temp->Create(parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr); #else - temp = new choice_ctrl(parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY | wxBORDER_SIMPLE); + temp = new choice_ctrl(parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY/* | wxBORDER_SIMPLE*/); #endif //__WXOSX__ temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); @@ -137,7 +139,7 @@ void msw_rescale_word_local_combo(choice_ctrl* combo) static void set_font_and_background_style(wxWindow* win, const wxFont& font) { win->SetFont(font); - win->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (!wxOSX) win->SetBackgroundStyle(wxBG_STYLE_PAINT); } static const wxString axes_color_text[] = { "#990000", "#009900", "#000099" }; @@ -495,16 +497,16 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : }); m_main_grid_sizer->Add(m_reset_skew_button); - m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches")); + m_check_inch = CheckBox::GetNewWin(parent, _L("Inches")); m_check_inch->SetFont(wxGetApp().normal_font()); - m_check_inch->SetValue(m_imperial_units); + CheckBox::SetValue(m_check_inch, m_imperial_units); m_check_inch->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { - wxGetApp().app_config->set("use_inches", m_check_inch->GetValue() ? "1" : "0"); + wxGetApp().app_config->set("use_inches", CheckBox::GetValue(m_check_inch) ? "1" : "0"); wxGetApp().sidebar().update_ui_from_settings(); }); - m_main_grid_sizer->Add(m_check_inch, 1, wxEXPAND); + m_main_grid_sizer->Add(m_check_inch); m_og->activate(); m_og->sizer->Clear(true); @@ -533,7 +535,7 @@ void ObjectManipulation::Show(const bool show) const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()); if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) { -#ifdef __linux__ +#if 0//def __linux__ m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), 2); #else m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), wxNullBitmap, 2); @@ -615,7 +617,7 @@ void ObjectManipulation::update_ui_from_settings() update(3/*meSize*/, m_new_size); } } - m_check_inch->SetValue(m_imperial_units); + CheckBox::SetValue(m_check_inch, m_imperial_units); if (m_use_colors != wxGetApp().app_config->get_bool("color_mapinulation_panel")) { m_use_colors = wxGetApp().app_config->get_bool("color_mapinulation_panel"); @@ -1199,6 +1201,8 @@ void ObjectManipulation::sys_color_changed() wxGetApp().UpdateDarkUI(m_word_local_combo); wxGetApp().UpdateDarkUI(m_check_inch); #endif + + CheckBox::SysColorChanged(m_check_inch); for (ManipulationEditor* editor : m_editors) editor->sys_color_changed(this); @@ -1227,19 +1231,12 @@ static const char axes[] = { 'x', 'y', 'z' }; ManipulationEditor::ManipulationEditor(ObjectManipulation* parent, const std::string& opt_key, int axis) : - wxTextCtrl(parent->parent(), wxID_ANY, wxEmptyString, wxDefaultPosition, - wxSize((wxOSX ? 5 : 6)*int(wxGetApp().em_unit()), wxDefaultCoord), wxTE_PROCESS_ENTER -#ifdef _WIN32 - | wxBORDER_SIMPLE -#endif - ), + ::TextInput(parent->parent(), "", "", "", wxDefaultPosition, + wxSize(int(5.8 * wxGetApp().em_unit()), wxDefaultCoord), wxTE_PROCESS_ENTER), m_opt_key(opt_key), m_axis(axis) { set_font_and_background_style(this, wxGetApp().normal_font()); -#ifdef __WXOSX__ - this->OSXDisableAllSmartSubstitutions(); -#endif // __WXOSX__ if (parent->use_colors()) { this->SetBackgroundColour(wxColour(axes_color_back[axis])); this->SetForegroundColour(*wxBLACK); @@ -1295,8 +1292,7 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent, void ManipulationEditor::msw_rescale() { - const int em = wxGetApp().em_unit(); - SetMinSize(wxSize(5 * em, wxDefaultCoord)); + SetCtrlSize(wxSize(int(5.8 * wxGetApp().em_unit()), wxDefaultCoord)); } void ManipulationEditor::sys_color_changed(ObjectManipulation* parent) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 8952f7248d..96e006a6ba 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -13,6 +13,9 @@ #include "libslic3r/Point.hpp" #include +#include "Widgets/ComboBox.hpp" +#include "Widgets/TextInput.hpp" + #ifdef __WXOSX__ class wxBitmapComboBox; #else @@ -21,15 +24,17 @@ class wxComboBox; class wxStaticText; class LockButton; class wxStaticBitmap; -class wxCheckBox; namespace Slic3r { -namespace GUI { + namespace GUI { #ifdef _WIN32 -class BitmapComboBox; + class BitmapComboBox; #endif +#if 1 + using choice_ctrl = ::ComboBox; +#else #ifdef __WXOSX__ static_assert(wxMAJOR_VERSION >= 3, "Use of wxBitmapComboBox on Manipulation panel requires wxWidgets 3.0 and newer"); using choice_ctrl = wxBitmapComboBox; @@ -40,11 +45,12 @@ class BitmapComboBox; using choice_ctrl = wxComboBox; #endif #endif // __WXOSX__ +#endif class Selection; class ObjectManipulation; -class ManipulationEditor : public wxTextCtrl +class ManipulationEditor : public ::TextInput { std::string m_opt_key; int m_axis; @@ -128,7 +134,7 @@ private: ScalableButton* m_reset_skew_button{ nullptr }; ScalableButton* m_drop_to_bed_button{ nullptr }; - wxCheckBox* m_check_inch {nullptr}; + wxWindow* m_check_inch {nullptr}; std::array m_mirror_buttons; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 1ee12c1fb5..c6bb44851c 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -732,7 +732,7 @@ void MainFrame::init_tabpanel() #ifdef _MSW_DARK_MODE if (wxGetApp().tabs_as_menu()) { m_tabpanel = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); - wxGetApp().UpdateDarkUI(m_tabpanel); +// wxGetApp().UpdateDarkUI(m_tabpanel); } else m_tabpanel = new Notebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME, true); @@ -740,6 +740,8 @@ void MainFrame::init_tabpanel() m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); #endif + wxGetApp().UpdateDarkUI(m_tabpanel); + #ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font()); #endif @@ -1107,7 +1109,6 @@ void MainFrame::on_sys_color_changed() wxGetApp().update_ui_colours_from_appconfig(); #ifdef __WXMSW__ wxGetApp().UpdateDarkUI(m_tabpanel); - // m_statusbar->update_dark_ui(); #ifdef _MSW_DARK_MODE // update common mode sizer if (!wxGetApp().tabs_as_menu()) @@ -2311,7 +2312,7 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe) this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); #else this->SetFont(wxGetApp().normal_font()); - this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +// this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif // __WXMSW__ // Load the icon either from the exe, or from the ico file. diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index bf919a6f8f..b8c4151ad0 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -27,6 +27,8 @@ #include "slic3r/GUI/MainFrame.hpp" #include "GUI_App.hpp" +#include "Widgets/CheckBox.hpp" + namespace Slic3r { namespace GUI { @@ -268,7 +270,7 @@ RichMessageDialog::RichMessageDialog(wxWindow* parent, { add_msg_content(this, content_sizer, get_wraped_wxString(message)); - m_checkBox = new wxCheckBox(this, wxID_ANY, m_checkBoxText); + m_checkBox = new ::CheckBox(this, m_checkBoxText); wxGetApp().UpdateDarkUI(m_checkBox); m_checkBox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { m_checkBoxValue = m_checkBox->GetValue(); }); diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index cde5928425..96c7703755 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -17,7 +17,7 @@ #include class wxBoxSizer; -class wxCheckBox; +class CheckBox; class wxStaticBitmap; namespace Slic3r { @@ -132,7 +132,7 @@ public: // Generic rich message dialog, used intead of wxRichMessageDialog class RichMessageDialog : public MsgDialog { - wxCheckBox* m_checkBox{ nullptr }; + CheckBox* m_checkBox{ nullptr }; wxString m_checkBoxText; bool m_checkBoxValue{ false }; diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index ad38d68435..fb1cfc2138 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -686,7 +686,8 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos) return ctrl->m_h_gap; ConfigOptionMode mode = og_line.get_options()[0].opt.mode; - wxBitmapBundle* bmp = get_bmp_bundle("mode", wxOSX ? 10 : 12, wxGetApp().get_mode_btn_color(mode)); + int pix_cnt = wxOSX ? 10 : 12; + wxBitmapBundle* bmp = get_bmp_bundle("mode", pix_cnt, pix_cnt, wxGetApp().get_mode_btn_color(mode)); wxCoord y_draw = v_pos + lround((height - get_bitmap_size(bmp, ctrl).GetHeight()) / 2); if (og_line.get_options().front().opt.gui_type != ConfigOptionDef::GUIType::legend) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 0fa39cd106..bf6c8571a3 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -288,6 +288,7 @@ void OptionsGroup::activate_line(Line& line) if (!custom_ctrl && m_use_custom_ctrl) { custom_ctrl = new OG_CustomCtrl(is_legend_line || !staticbox ? this->parent() : static_cast(this->stb), this); + wxGetApp().UpdateDarkUI(custom_ctrl); if (is_legend_line) sizer->Add(custom_ctrl, 0, wxEXPAND | wxLEFT, wxOSX ? 0 : 10); else diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0bd5f21312..ddbe95a156 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -141,6 +141,8 @@ #include "libslic3r/CustomGCode.hpp" #include "libslic3r/Platform.hpp" +#include "Widgets/CheckBox.hpp" + using boost::optional; namespace fs = boost::filesystem; using Slic3r::_3DScene; @@ -800,7 +802,7 @@ Sidebar::Sidebar(Plater *parent) wxGetApp().UpdateDarkUI(this); wxGetApp().UpdateDarkUI(p->scrolled); #else - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +// SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif #endif @@ -6112,7 +6114,7 @@ ProjectDropDialog::ProjectDropDialog(const std::string& filename) main_sizer->Add(stb_sizer, 1, wxEXPAND | wxRIGHT | wxLEFT, 10); wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL); - wxCheckBox* check = new wxCheckBox(this, wxID_ANY, _L("Don't show again")); + ::CheckBox* check = new ::CheckBox(this, _L("Don't show again")); check->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& evt) { wxGetApp().app_config->set("show_drop_project_dialog", evt.IsChecked() ? "0" : "1"); }); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 6fb2f23258..1e884e3fc0 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -212,7 +212,7 @@ void PreferencesDialog::build() #ifdef _WIN32 wxGetApp().UpdateDarkUI(this); #else - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + //SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif const wxFont& font = wxGetApp().normal_font(); SetFont(font); @@ -223,7 +223,7 @@ void PreferencesDialog::build() tabs = new Notebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME | wxNB_DEFAULT); #else tabs = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL |wxNB_NOPAGETHEME | wxNB_DEFAULT ); - tabs->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +// tabs->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif // Add "General" tab @@ -527,6 +527,13 @@ void PreferencesDialog::build() m_optgroup_gui->append_separator(); + append_bool_option(m_optgroup_gui, "suppress_round_corners", + L("Suppress round corners for controls (experimental)"), + L("If enabled, Settings Tabs will be placed as menu items. If disabled, old UI will be used."), + app_config->get("suppress_round_corners") == "1"); + + m_optgroup_gui->append_separator(); + append_bool_option(m_optgroup_gui, "show_hints", L("Show \"Tip of the day\" notification after start"), L("If enabled, useful hints are displayed at startup."), @@ -706,7 +713,7 @@ void PreferencesDialog::accept(wxEvent&) #endif // __linux__ } - std::vector options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled", "font_size" }; + std::vector options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled", "font_size", "suppress_round_corners" }; for (const std::string& option : options_to_recreate_GUI) { if (m_values.find(option) != m_values.end()) { diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index e31e47647b..224752bdff 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -45,6 +45,8 @@ #include "PhysicalPrinterDialog.hpp" #include "MsgDialog.hpp" +#include "Widgets/ComboBox.hpp" + // A workaround for a set of issues related to text fitting into gtk widgets: // See e.g.: https://github.com/prusa3d/PrusaSlicer/issues/4584 #if defined(__WXGTK20__) || defined(__WXGTK3__) @@ -437,6 +439,7 @@ void PresetComboBox::update_from_bundle() void PresetComboBox::msw_rescale() { m_em_unit = em_unit(this); + ::ComboBox::Rescale(); } void PresetComboBox::sys_color_changed() diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 951e01b691..79b7ed70d4 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -525,9 +525,9 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher) wxBoxSizer* check_sizer = new wxBoxSizer(wxHORIZONTAL); - check_category = new wxCheckBox(this, wxID_ANY, _L("Category")); + check_category = new ::CheckBox(this, _L("Category")); if (GUI::wxGetApp().is_localized()) - check_english = new wxCheckBox(this, wxID_ANY, _L("Search in English")); + check_english = new ::CheckBox(this, _L("Search in English")); wxStdDialogButtonSizer* cancel_btn = this->CreateStdDialogButtonSizer(wxCANCEL); GUI::wxGetApp().UpdateDarkUI(static_cast(this->FindWindowById(wxID_CANCEL, this))); diff --git a/src/slic3r/GUI/Search.hpp b/src/slic3r/GUI/Search.hpp index 99c3b319e7..571448d492 100644 --- a/src/slic3r/GUI/Search.hpp +++ b/src/slic3r/GUI/Search.hpp @@ -24,6 +24,9 @@ #include "OptionsGroup.hpp" #include "libslic3r/Preset.hpp" +#include "Widgets/CheckBox.hpp" + +class CheckBox; namespace Slic3r { @@ -162,8 +165,8 @@ class SearchDialog : public GUI::DPIDialog wxTextCtrl* search_line { nullptr }; wxDataViewCtrl* search_list { nullptr }; SearchListModel* search_list_model { nullptr }; - wxCheckBox* check_category { nullptr }; - wxCheckBox* check_english { nullptr }; + CheckBox* check_category { nullptr }; + CheckBox* check_english { nullptr }; OptionsSearcher* searcher { nullptr }; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 4d279ebbeb..5199e45220 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -69,6 +69,8 @@ #include "MsgDialog.hpp" #include "Notebook.hpp" +#include "Widgets/CheckBox.hpp" + #ifdef WIN32 #include #endif // WIN32 @@ -82,7 +84,11 @@ Tab::Tab(wxBookCtrlBase* parent, const wxString& title, Preset::Type type) : Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL/*, name*/); this->SetFont(Slic3r::GUI::wxGetApp().normal_font()); +#ifdef __WXMSW__ wxGetApp().UpdateDarkUI(this); +#else + SetBackgroundColour(parent->GetBackgroundColour()); +#endif m_compatible_printers.type = Preset::TYPE_PRINTER; m_compatible_printers.key_list = "compatible_printers"; @@ -167,8 +173,6 @@ void Tab::create_preset_tab() } }); - auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - //buttons m_scaled_buttons.reserve(6); m_scaled_buttons.reserve(2); @@ -422,10 +426,6 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str } // Initialize the page. PageShp page(new Page(m_page_view, title, icon_idx)); -// page->SetBackgroundStyle(wxBG_STYLE_SYSTEM); -#ifdef __WINDOWS__ -// page->SetDoubleBuffered(true); -#endif //__WINDOWS__ if (!is_extruder_pages) m_pages.push_back(page); @@ -961,6 +961,11 @@ void Tab::msw_rescale() m_presets_choice->msw_rescale(); m_treectrl->SetMinSize(wxSize(20 * m_em_unit, -1)); + if (m_compatible_printers.checkbox) + CheckBox::Rescale(m_compatible_printers.checkbox); + if (m_compatible_prints.checkbox) + CheckBox::Rescale(m_compatible_prints.checkbox); + // rescale options_groups if (m_active_page) m_active_page->msw_rescale(); @@ -1939,21 +1944,23 @@ void TabFilament::create_line_with_near_label_widget(ConfigOptionsGroupShp optgr else line = optgroup->create_single_option_line(optgroup->get_option(opt_key)); - line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(optgroup), opt_key, opt_index](wxWindow* parent) { - wxCheckBox* check_box = new wxCheckBox(parent, wxID_ANY, ""); - check_box->Bind(wxEVT_CHECKBOX, [optgroup_wk, opt_key, opt_index](wxCommandEvent& evt) { - const bool is_checked = evt.IsChecked(); - if (auto optgroup_sh = optgroup_wk.lock(); optgroup_sh) { - if (Field *field = optgroup_sh->get_fieldc(opt_key, opt_index); field != nullptr) { - field->toggle(is_checked); - if (is_checked) - field->set_last_meaningful_value(); - else - field->set_na_value(); + line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(optgroup), opt_key, opt_index](wxWindow* parent) { + wxWindow* check_box = CheckBox::GetNewWin(parent); + wxGetApp().UpdateDarkUI(check_box); + + check_box->Bind(wxEVT_CHECKBOX, [optgroup_wk, opt_key, opt_index](wxCommandEvent& evt) { + const bool is_checked = evt.IsChecked(); + if (auto optgroup_sh = optgroup_wk.lock(); optgroup_sh) { + if (Field *field = optgroup_sh->get_fieldc(opt_key, opt_index); field != nullptr) { + field->toggle(is_checked); + if (is_checked) + field->set_last_meaningful_value(); + else + field->set_na_value(); + } } - } - }, check_box->GetId()); + }); m_overrides_options[opt_key] = check_box; return check_box; @@ -1969,7 +1976,7 @@ void TabFilament::update_line_with_near_label_widget(ConfigOptionsGroupShp optgr m_overrides_options[opt_key]->Enable(is_checked); is_checked &= !m_config->option(opt_key)->is_nil(); - m_overrides_options[opt_key]->SetValue(is_checked); + CheckBox::SetValue(m_overrides_options[opt_key], is_checked); Field* field = optgroup->get_fieldc(opt_key, opt_index); if (field != nullptr) @@ -2038,6 +2045,16 @@ void TabFilament::update_filament_overrides_page() { bool is_checked = opt_key=="filament_retract_length" ? true : have_retract_length; update_line_with_near_label_widget(optgroup, opt_key, extruder_idx, is_checked); +/* + m_overrides_options[opt_key]->Enable(is_checked); + + is_checked &= !m_config->option(opt_key)->is_nil(); + CheckBox::SetValue(m_overrides_options[opt_key], is_checked); + + Field* field = optgroup->get_fieldc(opt_key, extruder_idx); + if (field != nullptr) + field->toggle(is_checked); +*/ } og_it = std::find_if(page->m_optgroups.begin(), page->m_optgroups.end(), [](const ConfigOptionsGroupShp og) { return og->title == "Retraction when tool is disabled"; }); @@ -2399,6 +2416,9 @@ void TabFilament::clear_pages() m_volumetric_speed_description_line = nullptr; m_cooling_description_line = nullptr; + + for (auto& over_opt : m_overrides_options) + over_opt.second = nullptr; } void TabFilament::msw_rescale() @@ -2406,7 +2426,6 @@ void TabFilament::msw_rescale() for (const auto& over_opt : m_overrides_options) if (wxWindow* win = over_opt.second) win->SetInitialSize(win->GetBestSize()); - Tab::msw_rescale(); } @@ -2416,8 +2435,16 @@ void TabFilament::sys_color_changed() update_extruder_combobox(); Tab::sys_color_changed(); + + for (const auto& over_opt : m_overrides_options) + if (wxWindow* check_box = over_opt.second) { + wxGetApp().UpdateDarkUI(check_box); + CheckBox::SysColorChanged(check_box); + } } + + void TabFilament::load_current_preset() { const std::string& selected_filament_name = m_presets->get_selected_preset_name(); @@ -4463,9 +4490,9 @@ void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::strin // Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer. wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &deps) { - deps.checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All"))); + deps.checkbox = CheckBox::GetNewWin(parent, _L("All")); deps.checkbox->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - wxGetApp().UpdateDarkUI(deps.checkbox, false, true); + wxGetApp().UpdateDarkUI(deps.checkbox); deps.btn = new ScalableButton(parent, wxID_ANY, "printer", format_wxstr(" %s %s", _L("Set"), dots), wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT); deps.btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); @@ -4477,11 +4504,12 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep deps.checkbox->Bind(wxEVT_CHECKBOX, ([this, &deps](wxCommandEvent e) { - deps.btn->Enable(! deps.checkbox->GetValue()); + const bool is_checked = CheckBox::GetValue(deps.checkbox); + deps.btn->Enable(!is_checked); // All printers have been made compatible with this preset. - if (deps.checkbox->GetValue()) + if (is_checked) this->load_key_value(deps.key_list, std::vector {}); - this->get_field(deps.key_condition)->toggle(deps.checkbox->GetValue()); + this->get_field(deps.key_condition)->toggle(is_checked); this->update_changed_ui(); }) ); @@ -4524,7 +4552,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep for (auto idx : selections) value.push_back(presets[idx].ToUTF8().data()); if (value.empty()) { - deps.checkbox->SetValue(1); + CheckBox::SetValue(deps.checkbox, true); deps.btn->Disable(); } // All depending_presets have been made compatible with this preset. @@ -4646,11 +4674,7 @@ void SubstitutionManager::add_substitution( int substitution_id, auto top_sizer = new wxBoxSizer(wxHORIZONTAL); auto add_text_editor = [substitution_id, top_sizer, this](const wxString& value, int opt_pos, int proportion) { - auto editor = new wxTextCtrl(m_parent, wxID_ANY, value, wxDefaultPosition, wxSize(15 * m_em, wxDefaultCoord), wxTE_PROCESS_ENTER -#ifdef _WIN32 - | wxBORDER_SIMPLE -#endif - ); + auto editor = new ::TextInput(m_parent, value, "", "", wxDefaultPosition, wxSize(15 * m_em, wxDefaultCoord), wxTE_PROCESS_ENTER); editor->SetFont(wxGetApp().normal_font()); wxGetApp().UpdateDarkUI(editor); @@ -4679,39 +4703,39 @@ void SubstitutionManager::add_substitution( int substitution_id, bool whole_word = strchr(params.c_str(), 'w') != nullptr || strchr(params.c_str(), 'W') != nullptr; bool match_single_line = strchr(params.c_str(), 's') != nullptr || strchr(params.c_str(), 'S') != nullptr; - auto chb_regexp = new wxCheckBox(m_parent, wxID_ANY, _L("Regular expression")); - chb_regexp->SetValue(regexp); + auto chb_regexp = CheckBox::GetNewWin(m_parent, _L("Regular expression")); + CheckBox::SetValue(chb_regexp, regexp); params_sizer->Add(chb_regexp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, m_em); - auto chb_case_insensitive = new wxCheckBox(m_parent, wxID_ANY, _L("Case insensitive")); - chb_case_insensitive->SetValue(case_insensitive); + auto chb_case_insensitive = CheckBox::GetNewWin(m_parent, _L("Case insensitive")); + CheckBox::SetValue(chb_case_insensitive, case_insensitive); params_sizer->Add(chb_case_insensitive, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxLEFT, m_em); - auto chb_whole_word = new wxCheckBox(m_parent, wxID_ANY, _L("Whole word")); - chb_whole_word->SetValue(whole_word); + auto chb_whole_word = CheckBox::GetNewWin(m_parent, _L("Whole word")); + CheckBox::SetValue(chb_whole_word, whole_word); params_sizer->Add(chb_whole_word, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxLEFT, m_em); - auto chb_match_single_line = new wxCheckBox(m_parent, wxID_ANY, _L("Match single line")); - chb_match_single_line->SetValue(match_single_line); + auto chb_match_single_line = CheckBox::GetNewWin(m_parent, _L("Match single line")); + CheckBox::SetValue(chb_match_single_line, match_single_line); chb_match_single_line->Show(regexp); m_chb_match_single_lines.emplace_back(chb_match_single_line); params_sizer->Add(chb_match_single_line, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxLEFT, m_em); - for (wxCheckBox* chb : std::initializer_list{ chb_regexp, chb_case_insensitive, chb_whole_word, chb_match_single_line }) { + for (wxWindow* chb : std::initializer_list{ chb_regexp, chb_case_insensitive, chb_whole_word, chb_match_single_line }) { chb->SetFont(wxGetApp().normal_font()); chb->Bind(wxEVT_CHECKBOX, [this, substitution_id, chb_regexp, chb_case_insensitive, chb_whole_word, chb_match_single_line](wxCommandEvent e) { std::string value = std::string(); - if (chb_regexp->GetValue()) + if (CheckBox::GetValue(chb_regexp)) value += "r"; - if (chb_case_insensitive->GetValue()) + if (CheckBox::GetValue(chb_case_insensitive)) value += "i"; - if (chb_whole_word->GetValue()) + if (CheckBox::GetValue(chb_whole_word)) value += "w"; - if (chb_match_single_line->GetValue()) + if (CheckBox::GetValue(chb_match_single_line)) value += "s"; - chb_match_single_line->Show(chb_regexp->GetValue()); + chb_match_single_line->Show(CheckBox::GetValue(chb_regexp)); m_grid_sizer->Layout(); edit_substitution(substitution_id, 2, value); @@ -4978,7 +5002,7 @@ void Tab::compatible_widget_reload(PresetDependencies &deps) bool has_any = ! m_config->option(deps.key_list)->values.empty(); has_any ? deps.btn->Enable() : deps.btn->Disable(); - deps.checkbox->SetValue(! has_any); + CheckBox::SetValue(deps.checkbox, !has_any); field->toggle(! has_any); } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 1b8dc99bc5..69ac11f95c 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -51,6 +51,8 @@ #include "OptionsGroup.hpp" #include "libslic3r/Preset.hpp" +class CheckBox; + namespace Slic3r { namespace GUI { @@ -202,7 +204,7 @@ protected: struct PresetDependencies { Preset::Type type = Preset::TYPE_INVALID; - wxCheckBox *checkbox = nullptr; + wxWindow *checkbox = nullptr; ScalableButton *btn = nullptr; std::string key_list; // "compatible_printers" std::string key_condition; @@ -473,7 +475,7 @@ class TabFilament : public Tab void create_extruder_combobox(); void update_volumetric_flow_preset_hints(); - std::map m_overrides_options; + std::map m_overrides_options; public: TabFilament(wxBookCtrlBase* parent) : Tab(parent, _(L("Filament Settings")), Slic3r::Preset::TYPE_FILAMENT) {} diff --git a/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp b/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp new file mode 100644 index 0000000000..4531446665 --- /dev/null +++ b/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp @@ -0,0 +1,47 @@ +#include "BitmapToggleButton.hpp" + +#include + +BitmapToggleButton::BitmapToggleButton(wxWindow* parent, const wxString& label, wxWindowID id) +{ +#ifdef __linux__ + long style = wxBORDER_NONE | wxBU_EXACTFIT; + if (label.IsEmpty()) + style = style | wxBU_NOTEXT; + // Call Create() from wxToggleButton instead of wxBitmapToggleButton to allow add Label text under Linux + wxToggleButton::Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style); +#else + wxBitmapToggleButton::Create(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT); + if (!label.IsEmpty()) + SetLabel(label); +#endif + +#ifdef __WXMSW__ + if (parent) { + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); + } +#elif __linux__ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#endif + + Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { + update(); + + wxCommandEvent evt(wxEVT_CHECKBOX); + evt.SetInt(int(GetValue())); + wxPostEvent(this, evt); + + e.Skip(); + }); +} + +void BitmapToggleButton::update_size() +{ +#ifdef __linux__ + if (GetLabel().IsEmpty()) + SetSize(GetBitmap().GetSize()); + else +#endif + SetSize(GetBestSize()); +} diff --git a/src/slic3r/GUI/Widgets/BitmapToggleButton.hpp b/src/slic3r/GUI/Widgets/BitmapToggleButton.hpp new file mode 100644 index 0000000000..db653e03fb --- /dev/null +++ b/src/slic3r/GUI/Widgets/BitmapToggleButton.hpp @@ -0,0 +1,17 @@ +#ifndef slic3r_GUI_BitmapToggleButton_hpp_ +#define slic3r_GUI_BitmapToggleButton_hpp_ + +#include + +class BitmapToggleButton : public wxBitmapToggleButton +{ + virtual void update() = 0; + +public: + BitmapToggleButton(wxWindow * parent = NULL, const wxString& label = wxEmptyString, wxWindowID id = wxID_ANY); + +protected: + void update_size(); +}; + +#endif // !slic3r_GUI_BitmapToggleButton_hpp_ diff --git a/src/slic3r/GUI/Widgets/Button.cpp b/src/slic3r/GUI/Widgets/Button.cpp index fa1dc15ee2..10e2819b05 100644 --- a/src/slic3r/GUI/Widgets/Button.cpp +++ b/src/slic3r/GUI/Widgets/Button.cpp @@ -1,7 +1,8 @@ #include "Button.hpp" -#include "Label.hpp" #include +#include +#include BEGIN_EVENT_TABLE(Button, StaticBox) @@ -36,23 +37,20 @@ Button::Button() std::make_pair(*wxBLACK, (int) StateColor::Normal)); } -Button::Button(wxWindow* parent, wxString text, wxString icon, long style, int iconSize) +Button::Button(wxWindow* parent, wxString text, wxString icon, long style, wxSize iconSize/* = wxSize(16, 16)*/) : Button() { Create(parent, text, icon, style, iconSize); } -bool Button::Create(wxWindow* parent, wxString text, wxString icon, long style, int iconSize) +bool Button::Create(wxWindow* parent, wxString text, wxString icon, long style, wxSize iconSize/* = wxSize(16, 16)*/) { StaticBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style); state_handler.attach({&text_color}); state_handler.update_binds(); - //BBS set default font - SetFont(Label::Body_14); wxWindow::SetLabel(text); if (!icon.IsEmpty()) { - //BBS set button icon default size to 20 - this->active_icon = ScalableBitmap(this, icon.ToStdString(), iconSize > 0 ? iconSize : 20); + this->active_icon = ScalableBitmap(this, icon.ToStdString(), iconSize); } messureSize(); return true; @@ -68,8 +66,7 @@ void Button::SetLabel(const wxString& label) void Button::SetIcon(const wxString& icon) { if (!icon.IsEmpty()) { - //BBS set button icon default size to 20 - this->active_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt()); + this->active_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_size()); } else { @@ -81,8 +78,7 @@ void Button::SetIcon(const wxString& icon) void Button::SetInactiveIcon(const wxString &icon) { if (!icon.IsEmpty()) { - // BBS set button icon default size to 20 - this->inactive_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt()); + this->inactive_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_size()); } else { this->inactive_icon = ScalableBitmap(); } @@ -129,12 +125,12 @@ void Button::SetCanFocus(bool canFocus) { this->canFocus = canFocus; } void Button::Rescale() { - if (this->active_icon.bmp().IsOk()) +/* if (this->active_icon.bmp().IsOk()) this->active_icon.msw_rescale(); if (this->inactive_icon.bmp().IsOk()) this->inactive_icon.msw_rescale(); - +*/ messureSize(); } @@ -162,6 +158,7 @@ void Button::render(wxDC& dc) ScalableBitmap icon; if (m_selected || ((states & (int)StateColor::State::Hovered) != 0)) +// if (m_selected || (states & (int)StateColor::State::Hovered)) icon = active_icon; else icon = inactive_icon; @@ -171,7 +168,7 @@ void Button::render(wxDC& dc) //BBS norrow size between text and icon szContent.x += padding; } - szIcon = icon.GetBmpSize(); + szIcon = icon.GetSize(); szContent.x += szIcon.x; if (szIcon.y > szContent.y) szContent.y = szIcon.y; @@ -190,7 +187,7 @@ void Button::render(wxDC& dc) wxPoint pt = rcContent.GetLeftTop(); if (icon.bmp().IsOk()) { pt.y += (rcContent.height - szIcon.y) / 2; - dc.DrawBitmap(icon.bmp(), pt); + dc.DrawBitmap(icon.get_bitmap(), pt); //BBS norrow size between text and icon pt.x += szIcon.x + padding; pt.y = rcContent.y; @@ -220,7 +217,7 @@ void Button::messureSize() //BBS norrow size between text and icon szContent.x += 5; } - wxSize szIcon = this->active_icon.GetBmpSize(); + wxSize szIcon = this->active_icon.GetSize(); szContent.x += szIcon.x; if (szIcon.y > szContent.y) szContent.y = szIcon.y; diff --git a/src/slic3r/GUI/Widgets/Button.hpp b/src/slic3r/GUI/Widgets/Button.hpp index 43aac6b9fb..249989ddff 100644 --- a/src/slic3r/GUI/Widgets/Button.hpp +++ b/src/slic3r/GUI/Widgets/Button.hpp @@ -24,9 +24,9 @@ class Button : public StaticBox public: Button(); - Button(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0); + Button(wxWindow* parent, wxString text, wxString icon = "", long style = 0, wxSize iconSize = wxSize(16, 16)); - bool Create(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0); + bool Create(wxWindow* parent, wxString text, wxString icon = "", long style = 0, wxSize iconSize = wxSize(16, 16)); void SetLabel(const wxString& label) override; diff --git a/src/slic3r/GUI/Widgets/CheckBox.cpp b/src/slic3r/GUI/Widgets/CheckBox.cpp index 4ca1ca5ba0..627f1d0971 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.cpp +++ b/src/slic3r/GUI/Widgets/CheckBox.cpp @@ -1,31 +1,25 @@ #include "CheckBox.hpp" -#include "../wxExtensions.hpp" +//#include "../wxExtensions.hpp" -CheckBox::CheckBox(wxWindow* parent) - : wxBitmapToggleButton(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE) - , m_on(this, "check_on", 18) - , m_half(this, "check_half", 18) - , m_off(this, "check_off", 18) - , m_on_disabled(this, "check_on_disabled", 18) - , m_half_disabled(this, "check_half_disabled", 18) - , m_off_disabled(this, "check_off_disabled", 18) - , m_on_focused(this, "check_on_focused", 18) - , m_half_focused(this, "check_half_focused", 18) - , m_off_focused(this, "check_off_focused", 18) +const int px_cnt = 16; + +CheckBox::CheckBox(wxWindow* parent, const wxString& name) + : BitmapToggleButton(parent, name, wxID_ANY) + , m_on(this, "check_on", px_cnt) + , m_off(this, "check_off", px_cnt) + , m_on_disabled(this, "check_on_disabled", px_cnt) + , m_off_disabled(this, "check_off_disabled", px_cnt) + , m_on_focused(this, "check_on_focused", px_cnt) + , m_off_focused(this, "check_off_focused", px_cnt) { - //SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); - if (parent) - SetBackgroundColour(parent->GetBackgroundColour()); - Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { m_half_checked = false; update(); e.Skip(); }); #ifdef __WXOSX__ // State not fully implement on MacOS Bind(wxEVT_SET_FOCUS, &CheckBox::updateBitmap, this); Bind(wxEVT_KILL_FOCUS, &CheckBox::updateBitmap, this); Bind(wxEVT_ENTER_WINDOW, &CheckBox::updateBitmap, this); Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this); #endif - SetSize(m_on.GetBmpSize()); - SetMinSize(m_on.GetBmpSize()); + update(); } @@ -35,61 +29,59 @@ void CheckBox::SetValue(bool value) update(); } -void CheckBox::SetHalfChecked(bool value) +void CheckBox::Update() { - m_half_checked = value; - update(); + update(); } void CheckBox::Rescale() { - m_on.msw_rescale(); - m_half.msw_rescale(); - m_off.msw_rescale(); - m_on_disabled.msw_rescale(); - m_half_disabled.msw_rescale(); - m_off_disabled.msw_rescale(); - m_on_focused.msw_rescale(); - m_half_focused.msw_rescale(); - m_off_focused.msw_rescale(); - SetSize(m_on.GetBmpSize()); update(); } void CheckBox::update() { - SetBitmapLabel((m_half_checked ? m_half : GetValue() ? m_on : m_off).bmp()); - SetBitmapDisabled((m_half_checked ? m_half_disabled : GetValue() ? m_on_disabled : m_off_disabled).bmp()); + const bool val = GetValue(); + const wxBitmapBundle& bmp = (val ? m_on : m_off).bmp(); + SetBitmap(bmp); + SetBitmapCurrent(bmp); + SetBitmapDisabled((val ? m_on_disabled : m_off_disabled).bmp()); #ifdef __WXMSW__ - SetBitmapFocus((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp()); + SetBitmapFocus((val ? m_on_focused : m_off_focused).bmp()); #endif - SetBitmapCurrent((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp()); #ifdef __WXOSX__ wxCommandEvent e(wxEVT_UPDATE_UI); updateBitmap(e); #endif + + update_size(); } #ifdef __WXMSW__ -CheckBox::State CheckBox::GetNormalState() const { return State_Normal; } +CheckBox::State CheckBox::GetNormalState() const +{ + return State_Normal; +} #endif - -#ifdef __WXOSX__ - bool CheckBox::Enable(bool enable) { bool result = wxBitmapToggleButton::Enable(enable); + +#ifdef __WXOSX__ if (result) { m_disable = !enable; wxCommandEvent e(wxEVT_ACTIVATE); updateBitmap(e); } +#endif return result; } +#ifdef __WXOSX__ + wxBitmap CheckBox::DoGetBitmap(State which) const { if (m_disable) { diff --git a/src/slic3r/GUI/Widgets/CheckBox.hpp b/src/slic3r/GUI/Widgets/CheckBox.hpp index 53c41b6470..727bbce9b5 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.hpp +++ b/src/slic3r/GUI/Widgets/CheckBox.hpp @@ -2,25 +2,20 @@ #define slic3r_GUI_CheckBox_hpp_ #include "../wxExtensions.hpp" +#include "BitmapToggleButton.hpp" -#include - -class CheckBox : public wxBitmapToggleButton +class CheckBox : public BitmapToggleButton { public: - CheckBox(wxWindow * parent = NULL); + CheckBox(wxWindow* parent = NULL, const wxString& name = wxEmptyString); public: void SetValue(bool value) override; - - void SetHalfChecked(bool value = true); + void Update() override; + bool Enable(bool enable = true) override; void Rescale(); -#ifdef __WXOSX__ - virtual bool Enable(bool enable = true) wxOVERRIDE; -#endif - protected: #ifdef __WXMSW__ virtual State GetNormalState() const wxOVERRIDE; @@ -37,19 +32,14 @@ protected: #endif private: - void update(); + void update() override; -private: - ScalableBitmap m_on; - ScalableBitmap m_half; - ScalableBitmap m_off; - ScalableBitmap m_on_disabled; - ScalableBitmap m_half_disabled; - ScalableBitmap m_off_disabled; - ScalableBitmap m_on_focused; - ScalableBitmap m_half_focused; - ScalableBitmap m_off_focused; - bool m_half_checked = false; + ScalableBitmap m_on; + ScalableBitmap m_off; + ScalableBitmap m_on_disabled; + ScalableBitmap m_off_disabled; + ScalableBitmap m_on_focused; + ScalableBitmap m_off_focused; }; #endif // !slic3r_GUI_CheckBox_hpp_ diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp index 01d7d9614c..68fc6ee8c5 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.cpp +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -1,11 +1,13 @@ #include "ComboBox.hpp" -#include "Label.hpp" +#include "UIColors.hpp" #include +#include "../GUI_App.hpp" + BEGIN_EVENT_TABLE(ComboBox, TextInput) -EVT_LEFT_DOWN(ComboBox::mouseDown) + EVT_LEFT_DOWN(ComboBox::mouseDown) //EVT_MOUSEWHEEL(ComboBox::mouseWheelMoved) EVT_KEY_DOWN(ComboBox::keyDown) @@ -28,27 +30,23 @@ ComboBox::ComboBox(wxWindow * parent, long style) : drop(texts, icons) { - if (style & wxCB_READONLY) - style |= wxRIGHT; text_off = style & CB_NO_TEXT; TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size, style | wxTE_PROCESS_ENTER); - drop.Create(this, style & DD_STYLE_MASK); + drop.Create(this, style); - if (style & wxCB_READONLY) { + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + if (style & wxCB_READONLY) GetTextCtrl()->Hide(); - TextInput::SetFont(Label::Body_14); - TextInput::SetBorderColor(StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), - std::make_pair(0x00AE42, (int) StateColor::Hovered), - std::make_pair(0xDBDBDB, (int) StateColor::Normal))); - TextInput::SetBackgroundColor(StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), - std::make_pair(0xEDFAF2, (int) StateColor::Focused), - std::make_pair(*wxWHITE, (int) StateColor::Normal))); - TextInput::SetLabelColor(StateColor(std::make_pair(0x909090, (int) StateColor::Disabled), - std::make_pair(0x262E30, (int) StateColor::Normal))); - } else { + else GetTextCtrl()->Bind(wxEVT_KEY_DOWN, &ComboBox::keyDown, this); + + SetBorderColor(TextInput::GetBorderColor()); + if (parent) { + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); } + drop.Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { SetSelection(e.GetInt()); e.SetEventObject(this); @@ -75,6 +73,8 @@ void ComboBox::SetSelection(int n) void ComboBox::Rescale() { + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + TextInput::Rescale(); drop.Rescale(); } @@ -120,27 +120,74 @@ wxString ComboBox::GetTextLabel() const bool ComboBox::SetFont(wxFont const& font) { + const bool set_drop_font = drop.SetFont(font); if (GetTextCtrl() && GetTextCtrl()->IsShown()) - return GetTextCtrl()->SetFont(font); - else - return TextInput::SetFont(font); + return GetTextCtrl()->SetFont(font) && set_drop_font; + return TextInput::SetFont(font) && set_drop_font; } -int ComboBox::Append(const wxString &item, const wxBitmap &bitmap) +bool ComboBox::SetBackgroundColour(const wxColour& colour) +{ + TextInput::SetBackgroundColour(colour); + + drop.SetBackgroundColour(colour); + drop.SetSelectorBackgroundColor(background_color); + + return true; +} + +bool ComboBox::SetForegroundColour(const wxColour& colour) +{ + TextInput::SetForegroundColour(colour); + + drop.SetTextColor(TextInput::GetTextColor()); + + return true; +} + +void ComboBox::SetBorderColor(StateColor const& color) +{ + TextInput::SetBorderColor(color); + drop.SetBorderColor(color); + drop.SetSelectorBorderColor(color); +} + +int ComboBox::Append(const wxString &item, const wxBitmapBundle &bitmap) { return Append(item, bitmap, nullptr); } -int ComboBox::Append(const wxString &item, - const wxBitmap &bitmap, - void * clientData) +int ComboBox::Append(const wxString &item, + const wxBitmapBundle &bitmap, + void * clientData) { texts.push_back(item); icons.push_back(bitmap); datas.push_back(clientData); types.push_back(wxClientData_None); drop.Invalidate(); - return texts.size() - 1; + return int(texts.size()) - 1; +} + +int ComboBox::Insert(const wxString& item, + const wxBitmapBundle& bitmap, + unsigned int pos) +{ + return Insert(item, bitmap, pos, nullptr); +} + +int ComboBox::Insert(const wxString& item, const wxBitmapBundle& bitmap, + unsigned int pos, void* clientData) +{ + const int n = wxItemContainer::Insert(item, pos); + if (n != wxNOT_FOUND) { + texts.insert(texts.begin() + n, item); + icons.insert(icons.begin() + n, bitmap); + datas.insert(datas.begin() + n, clientData); + types.insert(types.begin() + n, wxClientData_None); + drop.Invalidate(); + } + return n; } void ComboBox::DoClear() @@ -174,10 +221,13 @@ void ComboBox::SetString(unsigned int n, wxString const &value) if (n >= texts.size()) return; texts[n] = value; drop.Invalidate(); - if (n == drop.GetSelection()) SetLabel(value); + if (int(n) == drop.GetSelection()) SetLabel(value); } -wxBitmap ComboBox::GetItemBitmap(unsigned int n) { return icons[n]; } +wxBitmap ComboBox::GetItemBitmap(unsigned int n) +{ + return icons[n].GetBitmapFor(m_parent); +} int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, unsigned int pos, @@ -185,7 +235,7 @@ int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, wxClientDataType type) { if (pos > texts.size()) return -1; - for (int i = 0; i < items.GetCount(); ++i) { + for (size_t i = 0; i < items.GetCount(); ++i) { texts.insert(texts.begin() + pos, items[i]); icons.insert(icons.begin() + pos, wxNullBitmap); datas.insert(datas.begin() + pos, clientData ? clientData[i] : NULL); @@ -193,7 +243,7 @@ int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, ++pos; } drop.Invalidate(true); - return pos - 1; + return int(pos) - 1; } void *ComboBox::DoGetItemClientData(unsigned int n) const { return n < texts.size() ? datas[n] : NULL; } @@ -232,8 +282,11 @@ void ComboBox::mouseWheelMoved(wxMouseEvent &event) void ComboBox::keyDown(wxKeyEvent& event) { - switch (event.GetKeyCode()) { + int key_code = event.GetKeyCode(); + switch (key_code) { +#ifndef __WXOSX__ case WXK_RETURN: +#endif case WXK_SPACE: if (drop_down) { drop.DismissAndNotify(); @@ -251,7 +304,7 @@ void ComboBox::keyDown(wxKeyEvent& event) case WXK_RIGHT: if ((event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_LEFT) && GetSelection() > 0) { SetSelection(GetSelection() - 1); - } else if ((event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_RIGHT) && GetSelection() + 1 < texts.size()) { + } else if ((event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_RIGHT) && GetSelection() + 1 < int(texts.size())) { SetSelection(GetSelection() + 1); } else { break; diff --git a/src/slic3r/GUI/Widgets/ComboBox.hpp b/src/slic3r/GUI/Widgets/ComboBox.hpp index 0a8e018dce..7ba9911228 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.hpp +++ b/src/slic3r/GUI/Widgets/ComboBox.hpp @@ -4,13 +4,13 @@ #include "TextInput.hpp" #include "DropDown.hpp" -#define CB_NO_DROP_ICON DD_NO_CHECK_ICON +#define CB_NO_DROP_ICON DD_NO_DROP_ICON #define CB_NO_TEXT DD_NO_TEXT class ComboBox : public wxWindowWithItems { std::vector texts; - std::vector icons; + std::vector icons; std::vector datas; std::vector types; @@ -32,10 +32,18 @@ public: virtual bool SetFont(wxFont const & font) override; -public: - int Append(const wxString &item, const wxBitmap &bitmap = wxNullBitmap); + bool SetBackgroundColour(const wxColour& colour) override; + bool SetForegroundColour(const wxColour& colour) override; - int Append(const wxString &item, const wxBitmap &bitmap, void *clientData); + void SetBorderColor(StateColor const& color); + + int Append(const wxString &item, const wxBitmapBundle &bitmap = wxNullBitmap); + + int Append(const wxString &item, const wxBitmapBundle &bitmap, void *clientData); + + int Insert(const wxString& item, const wxBitmapBundle& bitmap, unsigned int pos); + int Insert(const wxString& item, const wxBitmapBundle& bitmap, + unsigned int pos, void* clientData); unsigned int GetCount() const override; diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index c0074b531d..873a734e80 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -1,7 +1,15 @@ #include "DropDown.hpp" -#include "Label.hpp" +#include "../GUI_App.hpp" +#include "../OptionsGroup.hpp" #include +#include +#include +#include +#include +#include + +#include wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent); @@ -25,12 +33,13 @@ END_EVENT_TABLE() */ DropDown::DropDown(std::vector &texts, - std::vector &icons) + std::vector &icons) : texts(texts) , icons(icons) + , radius(Slic3r::GUI::wxGetApp().suppress_round_corners() ? 0 : 5) , state_handler(this) - , border_color(0xDBDBDB) , text_color(0x363636) + , border_color(0xDBDBDB) , selector_border_color(std::make_pair(0x00AE42, (int) StateColor::Hovered), std::make_pair(*wxWHITE, (int) StateColor::Normal)) , selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked), @@ -40,7 +49,7 @@ DropDown::DropDown(std::vector &texts, DropDown::DropDown(wxWindow * parent, std::vector &texts, - std::vector &icons, + std::vector &icons, long style) : DropDown(texts, icons) { @@ -51,16 +60,14 @@ void DropDown::Create(wxWindow * parent, long style) { wxPopupTransientWindow::Create(parent); - SetBackgroundStyle(wxBG_STYLE_PAINT); - SetBackgroundColour(*wxWHITE); + if (!wxOSX) SetBackgroundStyle(wxBG_STYLE_PAINT); state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color}); state_handler.update_binds(); - if ((style & DD_NO_CHECK_ICON) == 0) + if (!(style & DD_NO_CHECK_ICON)) check_bitmap = ScalableBitmap(this, "checked", 16); text_off = style & DD_NO_TEXT; - // BBS set default font - SetFont(Label::Body_14); + SetFont(parent->GetFont()); #ifdef __WXOSX__ // wxPopupTransientWindow releases mouse on idle, which may cause various problems, // such as losting mouse move, and dismissing soon on first LEFT_DOWN event. @@ -99,9 +106,9 @@ void DropDown::SetValue(const wxString &value) selection = i == texts.end() ? -1 : std::distance(texts.begin(), i); } -void DropDown::SetCornerRadius(double radius) +void DropDown::SetCornerRadius(double radius_in) { - this->radius = radius; + radius = radius_in; paintNow(); } @@ -179,6 +186,28 @@ void DropDown::paintNow() Refresh(); } +void DropDown::SetTransparentBG(wxDC& dc, wxWindow* win) +{ + const wxSize size = win->GetSize(); + const wxPoint screen_pos = win->GetScreenPosition(); + wxScreenDC screen_dc; + +#ifdef __WXMSW__ + // Draw screen_dc to dc for transparent background + dc.Blit(0, 0, size.x, size.y, &screen_dc, screen_pos.x, screen_pos.y); +#else + // See https://forums.wxwidgets.org/viewtopic.php?f=1&t=49318 + wxClientDC client_dc(win); + client_dc.Blit(0, 0, size.x, size.y, &screen_dc, screen_pos.x, screen_pos.y); + + wxBitmap bmp(size.x, size.y); + wxMemoryDC mem_dc(bmp); + mem_dc.Blit(0, 0, size.x, size.y, &client_dc, 0, 0); + mem_dc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#endif //__WXMSW__ +} + /* * Here we do the actual rendering. I put it in a separate * method so that it can work no matter what type of DC @@ -188,17 +217,26 @@ void DropDown::render(wxDC &dc) { if (texts.size() == 0) return; int states = state_handler.states(); + + const wxSize size = GetSize(); + if (radius > 0. && !wxOSX) + SetTransparentBG(dc, this); + dc.SetPen(wxPen(border_color.colorForStates(states))); dc.SetBrush(wxBrush(GetBackgroundColour())); // if (GetWindowStyle() & wxBORDER_NONE) // dc.SetPen(wxNullPen); + wxRect rc(0, 0, size.x, size.y); + if (wxOSX && dc.GetContentScaleFactor() > 1.0) + // On Retina displays all controls are cut on 1px + rc.x = rc.y = 1; + // draw background - wxSize size = GetSize(); - if (radius == 0) - dc.DrawRectangle(0, 0, size.x, size.y); + if (radius == 0.0 || wxOSX) + dc.DrawRectangle(rc); else - dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius); + dc.DrawRoundedRectangle(rc, radius); // draw hover rectangle wxRect rcContent = {{0, offset.y}, rowSize}; @@ -233,8 +271,9 @@ void DropDown::render(wxDC &dc) } // draw position bar - if (rowSize.y * texts.size() > size.y) { - int height = rowSize.y * texts.size(); + const int text_size = int(texts.size()); + if (rowSize.y * text_size > size.y) { + int height = rowSize.y * text_size; wxRect rect = {size.x - 6, -offset.y * size.y / height, 4, size.y * size.y / height}; dc.SetPen(wxPen(border_color.defaultColor())); @@ -247,13 +286,13 @@ void DropDown::render(wxDC &dc) rcContent.x += 5; rcContent.width -= 5; if (check_bitmap.bmp().IsOk()) { - auto szBmp = check_bitmap.GetBmpSize(); + auto szBmp = check_bitmap.GetSize(); if (selection >= 0) { wxPoint pt = rcContent.GetLeftTop(); pt.y += (rcContent.height - szBmp.y) / 2; pt.y += rowSize.y * selection; if (pt.y + szBmp.y > 0 && pt.y < size.y) - dc.DrawBitmap(check_bitmap.bmp(), pt); + dc.DrawBitmap(check_bitmap.get_bitmap(), pt); } rcContent.x += szBmp.x + 5; rcContent.width -= szBmp.x + 5; @@ -268,17 +307,26 @@ void DropDown::render(wxDC &dc) if (rcContent.y > size.y) break; wxPoint pt = rcContent.GetLeftTop(); auto & icon = icons[i]; + const wxSize pref_icon_sz = get_preferred_size(icon, m_parent); if (iconSize.x > 0) { if (icon.IsOk()) { - pt.y += (rcContent.height - icon.GetSize().y) / 2; - dc.DrawBitmap(icon, pt); + pt.y += (rcContent.height - pref_icon_sz.y) / 2; +#ifdef __WXGTK3__ + dc.DrawBitmap(icon.GetBitmap(pref_icon_sz), pt); +#else + dc.DrawBitmap(icon.GetBitmapFor(m_parent), pt); +#endif } pt.x += iconSize.x + 5; pt.y = rcContent.y; } else if (icon.IsOk()) { - pt.y += (rcContent.height - icon.GetSize().y) / 2; - dc.DrawBitmap(icon, pt); - pt.x += icon.GetWidth() + 5; + pt.y += (rcContent.height - pref_icon_sz.y) / 2; +#ifdef __WXGTK3__ + dc.DrawBitmap(icon.GetBitmap(pref_icon_sz), pt); +#else + dc.DrawBitmap(icon.GetBitmapFor(m_parent), pt); +#endif + pt.x += pref_icon_sz.GetWidth() + 5; pt.y = rcContent.y; } auto text = texts[i]; @@ -305,7 +353,7 @@ void DropDown::messureSize() for (size_t i = 0; i < texts.size(); ++i) { wxSize size1 = text_off ? wxSize() : dc.GetMultiLineTextExtent(texts[i]); if (icons[i].IsOk()) { - wxSize size2 = icons[i].GetSize(); + wxSize size2 = get_preferred_size(icons[i], m_parent); if (size2.x > iconSize.x) iconSize = size2; if (!align_icon) { size1.x += size2.x + (text_off ? 0 : 5); @@ -317,7 +365,7 @@ void DropDown::messureSize() wxSize szContent = textSize; szContent.x += 10; if (check_bitmap.bmp().IsOk()) { - auto szBmp = check_bitmap.bmp().GetSize(); + auto szBmp = check_bitmap.GetSize(); szContent.x += szBmp.x + 5; } if (iconSize.x > 0) szContent.x += iconSize.x + (text_off ? 0 : 5); diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index b2b7eaa73e..87eccd0238 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -2,24 +2,29 @@ #define slic3r_GUI_DropDown_hpp_ #include +#include + +#include + #include "../wxExtensions.hpp" #include "StateHandler.hpp" #define DD_NO_CHECK_ICON 0x0001 -#define DD_NO_TEXT 0x0002 -#define DD_STYLE_MASK 0x0003 +#define DD_NO_DROP_ICON 0x0002 +#define DD_NO_TEXT 0x0004 +#define DD_STYLE_MASK 0x0008 wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent); class DropDown : public wxPopupTransientWindow { std::vector & texts; - std::vector & icons; + std::vector & icons; bool need_sync = false; int selection = -1; int hover_item = -1; - double radius = 0; + double radius; bool use_content_width = false; bool align_icon = false; bool text_off = false; @@ -42,17 +47,16 @@ class DropDown : public wxPopupTransientWindow public: DropDown(std::vector &texts, - std::vector &icons); + std::vector &icons); DropDown(wxWindow * parent, std::vector &texts, - std::vector &icons, + std::vector &icons, long style = 0); void Create(wxWindow * parent, long style = 0); -public: void Invalidate(bool clear = false); int GetSelection() const { return selection; } @@ -62,7 +66,6 @@ public: wxString GetValue() const; void SetValue(const wxString &value); -public: void SetCornerRadius(double radius); void SetBorderColor(StateColor const & color); @@ -77,10 +80,11 @@ public: void SetAlignIcon(bool align); -public: void Rescale(); bool HasDismissLongTime(); + + static void SetTransparentBG(wxDC& dc, wxWindow* win); protected: void OnDismiss() override; diff --git a/src/slic3r/GUI/Widgets/Label.cpp b/src/slic3r/GUI/Widgets/Label.cpp index 4a541f3478..c0bc2278fc 100644 --- a/src/slic3r/GUI/Widgets/Label.cpp +++ b/src/slic3r/GUI/Widgets/Label.cpp @@ -1,6 +1,8 @@ #include "Label.hpp" #include "StaticBox.hpp" +#include + wxFont Label::sysFont(int size, bool bold) { //#ifdef __linux__ diff --git a/src/slic3r/GUI/Widgets/Label.hpp b/src/slic3r/GUI/Widgets/Label.hpp index 1d3d387fb7..90ce81a338 100644 --- a/src/slic3r/GUI/Widgets/Label.hpp +++ b/src/slic3r/GUI/Widgets/Label.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_Label_hpp_ #include +#include #define LB_HYPERLINK 0x0001 diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index 9bea97dcdc..1dce77bb8a 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -1,8 +1,14 @@ #include "SpinInput.hpp" -#include "Label.hpp" #include "Button.hpp" +#include "UIColors.hpp" + +#include "../GUI_App.hpp" + #include +#include +#include +#include BEGIN_EVENT_TABLE(SpinInput, wxPanel) @@ -23,11 +29,9 @@ SpinInput::SpinInput() : label_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x6B6B6B, (int) StateColor::Normal)) , text_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x262E30, (int) StateColor::Normal)) { - radius = 0; + if (Slic3r::GUI::wxGetApp().suppress_round_corners()) + radius = 0; border_width = 1; - border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x00AE42, (int) StateColor::Hovered), - std::make_pair(0xDBDBDB, (int) StateColor::Normal)); - background_color = StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal)); } @@ -52,17 +56,20 @@ void SpinInput::Create(wxWindow *parent, int min, int max, int initial) { StaticBox::Create(parent, wxID_ANY, pos, size); - SetFont(Label::Body_12); wxWindow::SetLabel(label); + state_handler.attach({&label_color, &text_color}); state_handler.update_binds(); + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS)); - text_ctrl->SetFont(Label::Body_14); - text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); - text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); +#ifdef __WXOSX__ + text_ctrl->OSXDisableAllSmartSubstitutions(); +#endif // __WXOSX__ text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); state_handler.attach_child(text_ctrl); + text_ctrl->Bind(wxEVT_KILL_FOCUS, &SpinInput::onTextLostFocus, this); + text_ctrl->Bind(wxEVT_TEXT, &SpinInput::onText, this); text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInput::onTextEnter, this); text_ctrl->Bind(wxEVT_KEY_DOWN, &SpinInput::keyPressed, this); text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu @@ -71,6 +78,12 @@ void SpinInput::Create(wxWindow *parent, delta = 0; timer.Bind(wxEVT_TIMER, &SpinInput::onTimer, this); + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + if (parent) { + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); + } + long initialFromText; if (text.ToLong(&initialFromText)) initial = initialFromText; SetRange(min, max); @@ -114,6 +127,8 @@ void SpinInput::SetValue(const wxString &text) long value; if ( text.ToLong(&value) ) SetValue(value); + else + text_ctrl->SetValue(text); } void SpinInput::SetValue(int value) @@ -129,12 +144,76 @@ int SpinInput::GetValue()const return val; } +wxString SpinInput::GetTextValue() const +{ + return text_ctrl->GetValue(); +} + void SpinInput::SetRange(int min, int max) { this->min = min; this->max = max; } +void SpinInput::SetSelection(long from, long to) +{ + if (text_ctrl) + text_ctrl->SetSelection(from, to); +} + +bool SpinInput::SetFont(wxFont const& font) +{ + if (text_ctrl) + return text_ctrl->SetFont(font); + return StaticBox::SetFont(font); +} + +bool SpinInput::SetBackgroundColour(const wxColour& colour) +{ + const int clr_background_disabled = Slic3r::GUI::wxGetApp().dark_mode() ? clr_background_disabled_dark : clr_background_disabled_light; + StateColor clr_state(std::make_pair(clr_background_disabled, (int)StateColor::Disabled), + std::make_pair(clr_background_focused, (int)StateColor::Checked), + std::make_pair(colour, (int)StateColor::Focused), + std::make_pair(colour, (int)StateColor::Normal)); + + StaticBox::SetBackgroundColor(clr_state); + if (text_ctrl) + text_ctrl->SetBackgroundColour(colour); + if (button_inc) + button_inc->SetBackgroundColor(clr_state); + if (button_dec) + button_dec->SetBackgroundColor(clr_state); + + return true; +} + +bool SpinInput::SetForegroundColour(const wxColour& colour) +{ + StateColor clr_state(std::make_pair(clr_foreground_disabled, (int)StateColor::Disabled), + std::make_pair(colour, (int)StateColor::Normal)); + + SetLabelColor(clr_state); + SetTextColor(clr_state); + + if (text_ctrl) + text_ctrl->SetForegroundColour(colour); + if (button_inc) + button_inc->SetTextColor(clr_state); + if (button_dec) + button_dec->SetTextColor(clr_state); + + return true; +} + +void SpinInput::SetBorderColor(StateColor const &color) +{ + StaticBox::SetBorderColor(color); + if (button_inc) + button_inc->SetBorderColor(color); + if (button_dec) + button_dec->SetBorderColor(color); +} + void SpinInput::DoSetToolTipText(wxString const &tip) { wxWindow::DoSetToolTipText(tip); @@ -143,6 +222,9 @@ void SpinInput::DoSetToolTipText(wxString const &tip) void SpinInput::Rescale() { + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + button_inc->Rescale(); button_dec->Rescale(); messureSize(); @@ -183,8 +265,11 @@ void SpinInput::render(wxDC& dc) // draw seperator of buttons wxPoint pt = button_inc->GetPosition(); pt.y = size.y / 2; + pt.x += 1; dc.SetPen(wxPen(border_color.defaultColor())); - dc.DrawLine(pt, pt + wxSize{button_inc->GetSize().x - 2, 0}); + + const double scale = dc.GetContentScaleFactor(); + dc.DrawLine(pt, pt + wxSize{button_inc->GetSize().x - int(3. * scale), 0}); // draw label auto label = GetLabel(); if (!label.IsEmpty()) { @@ -201,31 +286,36 @@ void SpinInput::messureSize() wxSize size = GetSize(); wxSize textSize = text_ctrl->GetSize(); int h = textSize.y + 8; - if (size.y < h) { + if (size.y != h) { size.y = h; SetSize(size); SetMinSize(size); - } else { - textSize.y = size.y * 14 / 24; } + wxSize btnSize = {14, (size.y - 4) / 2}; btnSize.x = btnSize.x * btnSize.y / 10; + + const double scale = this->GetContentScaleFactor(); + wxClientDC dc(this); labelSize = dc.GetMultiLineTextExtent(GetLabel()); textSize.x = size.x - labelSize.x - btnSize.x - 16; text_ctrl->SetSize(textSize); - text_ctrl->SetPosition({6 + btnSize.x, (size.y - textSize.y) / 2}); + text_ctrl->SetPosition({int(3. * scale), (size.y - textSize.y) / 2}); button_inc->SetSize(btnSize); button_dec->SetSize(btnSize); - button_inc->SetPosition({3, size.y / 2 - btnSize.y - 1}); - button_dec->SetPosition({3, size.y / 2 + 1}); + button_inc->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 - btnSize.y/* - 1*/}); + button_dec->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 + 1}); } Button *SpinInput::createButton(bool inc) { - auto btn = new Button(this, "", inc ? "spin_inc" : "spin_dec", wxBORDER_NONE, 6); + auto btn = new Button(this, "", inc ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); btn->SetCornerRadius(0); + btn->SetInactiveIcon(inc ? "spin_inc" : "spin_dec"); btn->DisableFocusFromKeyboard(); + btn->SetSelected(false); + btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) { delta = inc ? 1 : -1; SetValue(val + delta); @@ -286,6 +376,13 @@ void SpinInput::onTextEnter(wxCommandEvent &event) ProcessEventLocally(event); } +void SpinInput::onText(wxCommandEvent &event) +{ + sendSpinEvent(); + event.SetId(GetId()); + ProcessEventLocally(event); +} + void SpinInput::mouseWheelMoved(wxMouseEvent &event) { auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? 1 : -1; diff --git a/src/slic3r/GUI/Widgets/SpinInput.hpp b/src/slic3r/GUI/Widgets/SpinInput.hpp index 5b0868880c..932958e138 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.hpp +++ b/src/slic3r/GUI/Widgets/SpinInput.hpp @@ -11,9 +11,9 @@ class SpinInput : public wxNavigationEnabled wxSize labelSize; StateColor label_color; StateColor text_color; - wxTextCtrl * text_ctrl; - Button * button_inc; - Button * button_dec; + wxTextCtrl * text_ctrl{nullptr}; + Button * button_inc {nullptr}; + Button * button_dec {nullptr}; wxTimer timer; int val; @@ -59,16 +59,27 @@ public: virtual bool Enable(bool enable = true) wxOVERRIDE; - wxTextCtrl * GetTextCtrl() { return text_ctrl; } + wxTextCtrl * GetText() { return text_ctrl; } void SetValue(const wxString &text); void SetValue (int value); int GetValue () const; + wxString GetTextValue() const; void SetRange(int min, int max); + bool SetFont(wxFont const& font) override; + + bool SetBackgroundColour(const wxColour& colour) override; + bool SetForegroundColour(const wxColour& colour) override; + void SetBorderColor(StateColor const& color); + + int GetMin() const { return this->min; } + int GetMax() const { return this->max; } + void SetSelection(long from, long to); + protected: void DoSetToolTipText(wxString const &tip) override; @@ -86,6 +97,7 @@ private: void keyPressed(wxKeyEvent& event); void onTimer(wxTimerEvent &evnet); void onTextLostFocus(wxEvent &event); + void onText(wxCommandEvent &event); void onTextEnter(wxCommandEvent &event); void sendSpinEvent(); diff --git a/src/slic3r/GUI/Widgets/StateHandler.cpp b/src/slic3r/GUI/Widgets/StateHandler.cpp index 72616ed8fd..87d14674cc 100644 --- a/src/slic3r/GUI/Widgets/StateHandler.cpp +++ b/src/slic3r/GUI/Widgets/StateHandler.cpp @@ -1,5 +1,7 @@ #include "StateHandler.hpp" +#include + wxDEFINE_EVENT(EVT_ENABLE_CHANGED, wxCommandEvent); StateHandler::StateHandler(wxWindow * owner) diff --git a/src/slic3r/GUI/Widgets/StateHandler.hpp b/src/slic3r/GUI/Widgets/StateHandler.hpp index 9ef155c7db..d7d6faeb40 100644 --- a/src/slic3r/GUI/Widgets/StateHandler.hpp +++ b/src/slic3r/GUI/Widgets/StateHandler.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_StateHandler_hpp_ #include +#include #include "StateColor.hpp" diff --git a/src/slic3r/GUI/Widgets/StaticBox.cpp b/src/slic3r/GUI/Widgets/StaticBox.cpp index 1a806e0007..29d5ff69e3 100644 --- a/src/slic3r/GUI/Widgets/StaticBox.cpp +++ b/src/slic3r/GUI/Widgets/StaticBox.cpp @@ -1,11 +1,13 @@ #include "StaticBox.hpp" #include "../GUI.hpp" #include +#include + +#include "DropDown.hpp" +#include "UIColors.hpp" BEGIN_EVENT_TABLE(StaticBox, wxWindow) -// catch paint events -//EVT_ERASE_BACKGROUND(StaticBox::eraseEvent) EVT_PAINT(StaticBox::paintEvent) END_EVENT_TABLE() @@ -20,9 +22,9 @@ StaticBox::StaticBox() : state_handler(this) , radius(8) { - border_color = StateColor( - std::make_pair(*wxLIGHT_GREY, (int) StateColor::Disabled), - std::make_pair(0x303A3C, (int) StateColor::Normal)); + border_color = StateColor(std::make_pair(clr_border_disabled, (int) StateColor::Disabled), + std::make_pair(clr_border_hovered, (int) StateColor::Hovered), + std::make_pair(clr_border_nornal, (int) StateColor::Normal)); } StaticBox::StaticBox(wxWindow* parent, @@ -41,7 +43,8 @@ bool StaticBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons wxWindow::Create(parent, id, pos, size, style); state_handler.attach({&border_color, &background_color, &background_color2}); state_handler.update_binds(); - SetBackgroundColour(GetParentBackgroundColor(parent)); +// SetBackgroundColour(GetParentBackgroundColor(parent)); +// SetForegroundColour(parent->GetParent()->GetForegroundColour()); return true; } @@ -109,21 +112,10 @@ wxColor StaticBox::GetParentBackgroundColor(wxWindow* parent) return *wxWHITE; } -void StaticBox::eraseEvent(wxEraseEvent& evt) -{ - // for transparent background, but not work -#ifdef __WXMSW__ - wxDC *dc = evt.GetDC(); - wxSize size = GetSize(); - wxClientDC dc2(GetParent()); - dc->Blit({0, 0}, size, &dc2, GetPosition()); -#endif -} - void StaticBox::paintEvent(wxPaintEvent& evt) { // depending on your system you may need to look at double-buffered dcs - wxPaintDC dc(this); + wxBufferedPaintDC dc(this);//wxPaintDC dc(this); render(dc); } @@ -134,29 +126,7 @@ void StaticBox::paintEvent(wxPaintEvent& evt) */ void StaticBox::render(wxDC& dc) { -#ifdef __WXMSW__ - if (radius == 0) { - doRender(dc); - return; - } - - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - //memdc.Blit({0, 0}, size, &dc, {0, 0}); - memdc.SetBackground(wxBrush(GetBackgroundColour())); - memdc.Clear(); - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else doRender(dc); -#endif } void StaticBox::doRender(wxDC& dc) @@ -166,35 +136,53 @@ void StaticBox::doRender(wxDC& dc) if (background_color2.count() == 0) { if ((border_width && border_color.count() > 0) || background_color.count() > 0) { wxRect rc(0, 0, size.x, size.y); - if (border_width && border_color.count() > 0) { - if (dc.GetContentScaleFactor() == 1.0) { - int d = floor(border_width / 2.0); - int d2 = floor(border_width - 1); - rc.x += d; - rc.width -= d2; - rc.y += d; - rc.height -= d2; - } else { - int d = 1; - rc.x += d; - rc.width -= d; - rc.y += d; - rc.height -= d; - } - dc.SetPen(wxPen(border_color.colorForStates(states), border_width)); - } else { - dc.SetPen(wxPen(background_color.colorForStates(states))); +#ifdef __WXOSX__ + // On Retina displays all controls are cut on 1px + if (dc.GetContentScaleFactor() > 1.) + rc.Deflate(1, 1); +#endif //__WXOSX__ + + if (radius > 0.) { +#if 0 + DropDown::SetTransparentBG(dc, this); +#else +#ifdef __WXMSW__ + wxColour bg_clr = GetParentBackgroundColor(m_parent); + dc.SetBrush(wxBrush(bg_clr)); + dc.SetPen(wxPen(bg_clr)); + dc.DrawRectangle(rc); +#endif +#endif } + if (background_color.count() > 0) dc.SetBrush(wxBrush(background_color.colorForStates(states))); else dc.SetBrush(wxBrush(GetBackgroundColour())); - if (radius == 0) { + + if (border_width && border_color.count() > 0) { +#ifdef __WXOSX__ + const double bw = (double)border_width; +#else + const double bw = dc.GetContentScaleFactor() * (double)border_width; +#endif //__WXOSX__ + { + int d = floor(bw / 2.0); + int d2 = floor(bw - 1); + rc.x += d; + rc.width -= d2; + rc.y += d; + rc.height -= d2; + } + dc.SetPen(wxPen(border_color.colorForStates(states), bw)); + } else { + dc.SetPen(wxPen(background_color.colorForStates(states))); + } + + if (radius == 0.) dc.DrawRectangle(rc); - } - else { + else dc.DrawRoundedRectangle(rc, radius - border_width); - } } } else { diff --git a/src/slic3r/GUI/Widgets/StaticBox.hpp b/src/slic3r/GUI/Widgets/StaticBox.hpp index 871c5651d9..9cfddaef24 100644 --- a/src/slic3r/GUI/Widgets/StaticBox.hpp +++ b/src/slic3r/GUI/Widgets/StaticBox.hpp @@ -31,7 +31,7 @@ public: void SetBorderColorNormal(wxColor const &color); - void SetBackgroundColor(StateColor const &color); + virtual void SetBackgroundColor(StateColor const &color); void SetBackgroundColorNormal(wxColor const &color); @@ -40,15 +40,12 @@ public: static wxColor GetParentBackgroundColor(wxWindow * parent); protected: - void eraseEvent(wxEraseEvent& evt); - void paintEvent(wxPaintEvent& evt); void render(wxDC& dc); virtual void doRender(wxDC& dc); -protected: double radius; int border_width = 1; StateHandler state_handler; diff --git a/src/slic3r/GUI/Widgets/SwitchButton.cpp b/src/slic3r/GUI/Widgets/SwitchButton.cpp index 8ae1165dcb..c87d302037 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.cpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.cpp @@ -1,23 +1,20 @@ #include "SwitchButton.hpp" -#include "Label.hpp" -#include "StaticBox.hpp" #include "../wxExtensions.hpp" -#include "../Utils/MacDarkMode.hpp" +#include "../../Utils/MacDarkMode.hpp" #include +#include +#include -SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id) - : wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT) - , m_on(this, "toggle_on", 16) - , m_off(this, "toggle_off", 16) +SwitchButton::SwitchButton(wxWindow* parent, const wxString& name, wxWindowID id) + : BitmapToggleButton(parent, name, id) + , m_on(this, "toggle_on", 28, 16) + , m_off(this, "toggle_off", 28, 16) , text_color(std::pair{*wxWHITE, (int) StateColor::Checked}, std::pair{0x6B6B6B, (int) StateColor::Normal}) , track_color(0xD9D9D9) , thumb_color(std::pair{0x00AE42, (int) StateColor::Checked}, std::pair{0xD9D9D9, (int) StateColor::Normal}) { - SetBackgroundColour(StaticBox::GetParentBackgroundColor(parent)); - Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); }); - SetFont(Label::Body_12); Rescale(); } @@ -52,11 +49,7 @@ void SwitchButton::SetValue(bool value) void SwitchButton::Rescale() { - if (labels[0].IsEmpty()) { - m_on.msw_rescale(); - m_off.msw_rescale(); - } - else { + if (!labels[0].IsEmpty()) { #ifdef __WXOSX__ auto scale = Slic3r::GUI::mac_max_scaling_factor(); int BS = (int) scale; @@ -121,14 +114,23 @@ void SwitchButton::Rescale() #ifdef __WXOSX__ bmp = wxBitmap(bmp.ConvertToImage(), -1, scale); #endif - (i == 0 ? m_off : m_on).bmp() = bmp; + (i == 0 ? m_off : m_on).SetBitmap(bmp); } } - SetSize(m_on.GetBmpSize()); + + update(); +} + +void SwitchButton::SysColorChange() +{ + m_on.sys_color_changed(); + m_off.sys_color_changed(); + update(); } void SwitchButton::update() { SetBitmap((GetValue() ? m_on : m_off).bmp()); + update_size(); } diff --git a/src/slic3r/GUI/Widgets/SwitchButton.hpp b/src/slic3r/GUI/Widgets/SwitchButton.hpp index 25581f3762..5c1859e9c2 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.hpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.hpp @@ -4,12 +4,12 @@ #include "../wxExtensions.hpp" #include "StateColor.hpp" -#include +#include "BitmapToggleButton.hpp" -class SwitchButton : public wxBitmapToggleButton +class SwitchButton : public BitmapToggleButton { public: - SwitchButton(wxWindow * parent = NULL, wxWindowID id = wxID_ANY); + SwitchButton(wxWindow * parent = NULL, const wxString& name = wxEmptyString, wxWindowID id = wxID_ANY); public: void SetLabels(wxString const & lbl_on, wxString const & lbl_off); @@ -24,8 +24,10 @@ public: void Rescale(); + void SysColorChange(); + private: - void update(); + void update() override; private: ScalableBitmap m_on; diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp index 823dd5512d..4b7dd44ddc 100644 --- a/src/slic3r/GUI/Widgets/TextInput.cpp +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -1,7 +1,10 @@ #include "TextInput.hpp" -#include "Label.hpp" +#include "UIColors.hpp" #include +#include + +#include "slic3r/GUI/GUI_App.hpp" BEGIN_EVENT_TABLE(TextInput, wxPanel) @@ -21,12 +24,9 @@ TextInput::TextInput() , text_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x262E30, (int) StateColor::Normal)) { - radius = 0; + if (Slic3r::GUI::wxGetApp().suppress_round_corners()) + radius = 0; border_width = 1; - border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x00AE42, (int) StateColor::Hovered), - std::make_pair(0xDBDBDB, (int) StateColor::Normal)); - background_color = StateColor(std::make_pair(0xF0F0F0, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal)); - SetFont(Label::Body_12); } TextInput::TextInput(wxWindow * parent, @@ -52,15 +52,21 @@ void TextInput::Create(wxWindow * parent, text_ctrl = nullptr; StaticBox::Create(parent, wxID_ANY, pos, size, style); wxWindow::SetLabel(label); - style &= ~wxRIGHT; - state_handler.attach({&label_color, & text_color}); + + state_handler.attach({&label_color, &text_color}); state_handler.update_binds(); - text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER); - text_ctrl->SetFont(Label::Body_14); + + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE); +#ifdef __WXOSX__ + text_ctrl->OSXDisableAllSmartSubstitutions(); +#endif // __WXOSX__ text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); - text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); - text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + if (parent) { + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); + } state_handler.attach_child(text_ctrl); + text_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) { OnEdit(); e.SetId(GetId()); @@ -73,8 +79,9 @@ void TextInput::Create(wxWindow * parent, ProcessEventLocally(e); }); text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu + if (!icon.IsEmpty()) { - this->icon = ScalableBitmap(this, icon.ToStdString(), 16); + this->drop_down_icon = ScalableBitmap(this, icon.ToStdString(), 16); } messureSize(); } @@ -92,10 +99,54 @@ void TextInput::SetLabel(const wxString& label) Refresh(); } -void TextInput::SetIcon(const wxBitmap &icon) +bool TextInput::SetBackgroundColour(const wxColour& colour) { - this->icon.bmp() = icon; - Rescale(); + const int clr_background_disabled = Slic3r::GUI::wxGetApp().dark_mode() ? clr_background_disabled_dark : clr_background_disabled_light; + const StateColor clr_state( std::make_pair(clr_background_disabled, (int)StateColor::Disabled), + std::make_pair(clr_background_focused, (int)StateColor::Checked), + std::make_pair(colour, (int)StateColor::Focused), + std::make_pair(colour, (int)StateColor::Normal)); + + SetBackgroundColor(clr_state); + if (text_ctrl) + text_ctrl->SetBackgroundColour(colour); + + return true; +} + +bool TextInput::SetForegroundColour(const wxColour& colour) +{ + const StateColor clr_state( std::make_pair(clr_foreground_disabled, (int)StateColor::Disabled), + std::make_pair(colour, (int)StateColor::Normal)); + + SetLabelColor(clr_state); + SetTextColor (clr_state); + + return true; +} + +void TextInput::SetValue(const wxString& value) +{ + if (text_ctrl) + text_ctrl->SetValue(value); +} + +wxString TextInput::GetValue() +{ + if (text_ctrl) + return text_ctrl->GetValue(); + return wxEmptyString; +} + +void TextInput::SetSelection(long from, long to) +{ + if (text_ctrl) + text_ctrl->SetSelection(from, to); +} + +void TextInput::SetIcon(const wxBitmapBundle& icon_in) +{ + icon = icon_in; } void TextInput::SetLabelColor(StateColor const &color) @@ -106,18 +157,41 @@ void TextInput::SetLabelColor(StateColor const &color) void TextInput::SetTextColor(StateColor const& color) { - text_color= color; + text_color = color; state_handler.update_binds(); + if (text_ctrl) + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); +} + +void TextInput::SetBGColor(StateColor const& color) +{ + background_color = color; + state_handler.update_binds(); +} + +void TextInput::SetCtrlSize(wxSize const& size) +{ + StaticBox::SetInitialSize(size); + Rescale(); } void TextInput::Rescale() { - if (!this->icon.name().empty()) - this->icon.msw_rescale(); + if (text_ctrl) + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + messureSize(); Refresh(); } +bool TextInput::SetFont(const wxFont& font) +{ + bool ret = StaticBox::SetFont(font); + if (text_ctrl) + return ret && text_ctrl->SetFont(font); + return ret; +} + bool TextInput::Enable(bool enable) { bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); @@ -149,16 +223,22 @@ void TextInput::DoSetSize(int x, int y, int width, int height, int sizeFlags) if (sizeFlags & wxSIZE_USE_EXISTING) return; wxSize size = GetSize(); wxPoint textPos = {5, 0}; - if (this->icon.bmp().IsOk()) { - wxSize szIcon = this->icon.GetBmpSize(); + if (this->icon.IsOk()) { + wxSize szIcon = get_preferred_size(icon, m_parent); textPos.x += szIcon.x; } + wxSize dd_icon_size = wxSize(0,0); + if (this->drop_down_icon.bmp().IsOk()) + dd_icon_size = this->drop_down_icon.GetSize(); + bool align_right = GetWindowStyle() & wxRIGHT; if (align_right) textPos.x += labelSize.x; if (text_ctrl) { wxSize textSize = text_ctrl->GetSize(); - textSize.x = size.x - textPos.x - labelSize.x - 10; + wxClientDC dc(this); + const int r_shift = int((dd_icon_size.x == 0 ? 3. : 2.) * dc.GetContentScaleFactor()); + textSize.x = size.x - textPos.x - labelSize.x - dd_icon_size.x - r_shift; text_ctrl->SetSize(textSize); text_ctrl->SetPosition({textPos.x, (size.y - textSize.y) / 2}); } @@ -190,22 +270,36 @@ void TextInput::render(wxDC& dc) bool align_right = GetWindowStyle() & wxRIGHT; // start draw wxPoint pt = {5, 0}; - if (icon.bmp().IsOk()) { - wxSize szIcon = icon.GetBmpSize(); + if (icon.IsOk()) { + wxSize szIcon = get_preferred_size(icon, m_parent); pt.y = (size.y - szIcon.y) / 2; - dc.DrawBitmap(icon.bmp(), pt); - pt.x += szIcon.x + 0; +#ifdef __WXGTK3__ + dc.DrawBitmap(icon.GetBitmap(szIcon), pt); +#else + dc.DrawBitmap(icon.GetBitmapFor(m_parent), pt); +#endif + pt.x += szIcon.x + 5; } + + // drop_down_icon draw + wxPoint pt_r = {size.x, 0}; + if (drop_down_icon.bmp().IsOk()) { + wxSize szIcon = drop_down_icon.GetSize(); + pt_r.x -= szIcon.x + 2; + pt_r.y = (size.y - szIcon.y) / 2; + dc.DrawBitmap(drop_down_icon.get_bitmap(), pt_r); + } + auto text = wxWindow::GetLabel(); if (!text.IsEmpty()) { wxSize textSize = text_ctrl->GetSize(); if (align_right) { - if (pt.x + labelSize.x > size.x) - text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x); - pt.y = (size.y - labelSize.y) / 2; - } else { pt.x += textSize.x; pt.y = (size.y + textSize.y) / 2 - labelSize.y; + } else { + if (pt.x + labelSize.x > pt_r.x) + text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, pt_r.x - pt.x); + pt.y = (size.y - labelSize.y) / 2; } dc.SetTextForeground(label_color.colorForStates(states)); dc.SetFont(GetFont()); @@ -218,11 +312,11 @@ void TextInput::messureSize() wxSize size = GetSize(); wxClientDC dc(this); labelSize = dc.GetTextExtent(wxWindow::GetLabel()); - wxSize textSize = text_ctrl->GetSize(); - int h = textSize.y + 8; - if (size.y < h) { - size.y = h; - } + + const wxSize textSize = text_ctrl->GetSize(); + const wxSize iconSize = drop_down_icon.bmp().IsOk() ? drop_down_icon.GetSize() : wxSize(0, 0); + size.y = ((textSize.y > iconSize.y) ? textSize.y : iconSize.y) + 8; + wxSize minSize = size; minSize.x = GetMinWidth(); SetMinSize(minSize); diff --git a/src/slic3r/GUI/Widgets/TextInput.hpp b/src/slic3r/GUI/Widgets/TextInput.hpp index 152fb88f3d..84bdf7126b 100644 --- a/src/slic3r/GUI/Widgets/TextInput.hpp +++ b/src/slic3r/GUI/Widgets/TextInput.hpp @@ -8,10 +8,11 @@ class TextInput : public wxNavigationEnabled { wxSize labelSize; - ScalableBitmap icon; + wxBitmapBundle icon; + ScalableBitmap drop_down_icon; StateColor label_color; StateColor text_color; - wxTextCtrl * text_ctrl; + wxTextCtrl* text_ctrl{nullptr}; static const int TextInputWidth = 200; static const int TextInputHeight = 50; @@ -40,22 +41,38 @@ public: void SetLabel(const wxString& label); - void SetIcon(const wxBitmap & icon); + void SetIcon(const wxBitmapBundle& icon); void SetLabelColor(StateColor const &color); + void SetBGColor(StateColor const &color); + void SetTextColor(StateColor const &color); + void SetCtrlSize(wxSize const& size); + virtual void Rescale(); + bool SetFont(const wxFont &font) override; + virtual bool Enable(bool enable = true) override; virtual void SetMinSize(const wxSize& size) override; + bool SetBackgroundColour(const wxColour &colour) override; + + bool SetForegroundColour(const wxColour &colour) override; + wxTextCtrl *GetTextCtrl() { return text_ctrl; } wxTextCtrl const *GetTextCtrl() const { return text_ctrl; } + void SetValue(const wxString& value); + + wxString GetValue(); + + void SetSelection(long from, long to); + protected: virtual void OnEdit() {} @@ -64,6 +81,9 @@ protected: void DoSetToolTipText(wxString const &tip) override; + StateColor GetTextColor() const { return text_color; } + StateColor GetBorderColor() const { return border_color; } + private: void paintEvent(wxPaintEvent& evt); diff --git a/src/slic3r/GUI/Widgets/UIColors.hpp b/src/slic3r/GUI/Widgets/UIColors.hpp new file mode 100644 index 0000000000..fefa6efd71 --- /dev/null +++ b/src/slic3r/GUI/Widgets/UIColors.hpp @@ -0,0 +1,18 @@ +#ifndef slic3r_UI_Colors_hpp_ +#define slic3r_UI_Colors_hpp_ + +static const int clr_border_nornal = 0x646464;//0xDBDBDB; +static const int clr_border_hovered = 0xED6B21;//0x00AE42; +static const int clr_border_disabled = 0x646464;//0xDBDBDB; + +static const int clr_background_nornal_light = 0xFFFFFF; +static const int clr_background_nornal_dark = 0x2B2B2B;//0x434343; +static const int clr_background_focused = 0xED6B21;//0xEDFAF2; +static const int clr_background_disabled_dark = 0x404040;//0xF0F0F0; +static const int clr_background_disabled_light = 0xD9D9D9;//0xF0F0F0; + +static const int clr_foreground_nornal = 0x262E30; +static const int clr_foreground_focused = 0x00AE42; +static const int clr_foreground_disabled = 0x909090; + +#endif // !slic3r_UI_Colors_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 87f6a0ac02..0984c82c57 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -422,10 +422,12 @@ static int scale() } #endif // __WXGTK2__ -wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name_in, int px_cnt/* = 16*/, const std::string& new_color/* = std::string()*/) +wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name_in, int width/* = 16*/, int height/* = -1*/, const std::string& new_color/* = std::string()*/) { #ifdef __WXGTK2__ - px_cnt *= scale(); + width *= scale(); + if (height > 0) + height *= scale(); #endif // __WXGTK2__ static Slic3r::GUI::BitmapCache cache; @@ -433,10 +435,13 @@ wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name_in, int px_cnt/* = 16 std::string bmp_name = bmp_name_in; boost::replace_last(bmp_name, ".png", ""); + if (height < 0) + height = width; + // Try loading an SVG first, then PNG if SVG is not found: - wxBitmapBundle* bmp = cache.from_svg(bmp_name, px_cnt, px_cnt, Slic3r::GUI::wxGetApp().dark_mode(), new_color); + wxBitmapBundle* bmp = cache.from_svg(bmp_name, width, height, Slic3r::GUI::wxGetApp().dark_mode(), new_color); if (bmp == nullptr) { - bmp = cache.from_png(bmp_name, px_cnt, px_cnt); + bmp = cache.from_png(bmp_name, width, height); if (!bmp) // Neither SVG nor PNG has been found, raise error throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name); @@ -658,7 +663,7 @@ void ModeButton::SetState(const bool state) void ModeButton::update_bitmap() { - m_bmp = *get_bmp_bundle("mode", m_px_cnt, Slic3r::GUI::wxGetApp().get_mode_btn_color(m_mode_id)); + m_bmp = *get_bmp_bundle("mode", m_bmp_width, m_bmp_height, Slic3r::GUI::wxGetApp().get_mode_btn_color(m_mode_id)); SetBitmap(m_bmp); SetBitmapCurrent(m_bmp); @@ -785,19 +790,28 @@ void MenuWithSeparators::SetSecondSeparator() // PrusaBitmap // ---------------------------------------------------------------------------- ScalableBitmap::ScalableBitmap( wxWindow *parent, - const std::string& icon_name/* = ""*/, - const int px_cnt/* = 16*/, + const std::string& icon_name, + const int width/* = 16*/, + const int height/* = -1*/, const bool grayscale/* = false*/): m_parent(parent), m_icon_name(icon_name), - m_px_cnt(px_cnt) + m_bmp_width(width), m_bmp_height(height) { - m_bmp = *get_bmp_bundle(icon_name, px_cnt); + m_bmp = *get_bmp_bundle(icon_name, width, height); m_bitmap = m_bmp.GetBitmapFor(m_parent); } +ScalableBitmap::ScalableBitmap( wxWindow* parent, + const std::string& icon_name, + const wxSize icon_size, + const bool grayscale/* = false*/) : +ScalableBitmap(parent, icon_name, icon_size.x, icon_size.y, grayscale) +{ +} + void ScalableBitmap::sys_color_changed() { - m_bmp = *get_bmp_bundle(m_icon_name, m_px_cnt); + m_bmp = *get_bmp_bundle(m_icon_name, m_bmp_width, m_bmp_height); } // ---------------------------------------------------------------------------- @@ -811,17 +825,19 @@ ScalableButton::ScalableButton( wxWindow * parent, const wxSize& size /* = wxDefaultSize*/, const wxPoint& pos /* = wxDefaultPosition*/, long style /*= wxBU_EXACTFIT | wxNO_BORDER*/, - int bmp_px_cnt/* = 16*/) : + int width/* = 16*/, + int height/* = -1*/) : m_parent(parent), m_current_icon_name(icon_name), - m_px_cnt(bmp_px_cnt), + m_bmp_width(width), + m_bmp_height(height), m_has_border(!(style & wxNO_BORDER)) { Create(parent, id, label, pos, size, style); Slic3r::GUI::wxGetApp().UpdateDarkUI(this); if (!icon_name.empty()) { - SetBitmap(*get_bmp_bundle(icon_name, m_px_cnt)); + SetBitmap(*get_bmp_bundle(icon_name, width, height)); if (!label.empty()) SetBitmapMargins(int(0.5* em_unit(parent)), 0); } @@ -842,7 +858,8 @@ ScalableButton::ScalableButton( wxWindow * parent, long style /*= wxBU_EXACTFIT | wxNO_BORDER*/) : m_parent(parent), m_current_icon_name(bitmap.name()), - m_px_cnt(bitmap.px_cnt()), + m_bmp_width(bitmap.px_size().x), + m_bmp_height(bitmap.px_size().y), m_has_border(!(style& wxNO_BORDER)) { Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style); @@ -863,7 +880,7 @@ bool ScalableButton::SetBitmap_(const std::string& bmp_name) if (m_current_icon_name.empty()) return false; - wxBitmapBundle bmp = *get_bmp_bundle(m_current_icon_name, m_px_cnt); + wxBitmapBundle bmp = *get_bmp_bundle(m_current_icon_name, m_bmp_width, m_bmp_height); SetBitmap(bmp); SetBitmapCurrent(bmp); SetBitmapPressed(bmp); @@ -891,13 +908,13 @@ void ScalableButton::sys_color_changed() { Slic3r::GUI::wxGetApp().UpdateDarkUI(this, m_has_border); - wxBitmapBundle bmp = *get_bmp_bundle(m_current_icon_name, m_px_cnt); + wxBitmapBundle bmp = *get_bmp_bundle(m_current_icon_name, m_bmp_width, m_bmp_height); SetBitmap(bmp); SetBitmapCurrent(bmp); SetBitmapPressed(bmp); SetBitmapFocus(bmp); if (!m_disabled_icon_name.empty()) - SetBitmapDisabled(*get_bmp_bundle(m_disabled_icon_name, m_px_cnt)); + SetBitmapDisabled(*get_bmp_bundle(m_disabled_icon_name, m_bmp_width, m_bmp_height)); if (!GetLabelText().IsEmpty()) SetBitmapMargins(int(0.5 * em_unit(m_parent)), 0); } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 8b33d902f5..a0ed1bbd4c 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -54,7 +54,7 @@ void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector< int em_unit(wxWindow* win); int mode_icon_px_size(); -wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name, int px_cnt = 16, const std::string& new_color_rgb = std::string()); +wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name, int width = 16, int height = -1, const std::string& new_color_rgb = std::string()); wxBitmapBundle* get_empty_bmp_bundle(int width, int height); wxBitmapBundle* get_solid_bmp_bundle(int width, int height, const std::string& color); @@ -131,6 +131,17 @@ public: void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } }; +inline wxSize get_preferred_size(const wxBitmapBundle& bmp, wxWindow* parent) +{ + if (!bmp.IsOk()) + return wxSize(0,0); +#ifdef __WIN32__ + return bmp.GetPreferredBitmapSizeFor(parent); +#else + return bmp.GetDefaultSize(); +#endif +} + // ---------------------------------------------------------------------------- // ScalableBitmap @@ -141,8 +152,14 @@ class ScalableBitmap public: ScalableBitmap() {}; ScalableBitmap( wxWindow *parent, - const std::string& icon_name = "", - const int px_cnt = 16, + const std::string& icon_name, + const int width = 16, + const int height = -1 , + const bool grayscale = false); + + ScalableBitmap( wxWindow *parent, + const std::string& icon_name, + const wxSize icon_size, const bool grayscale = false); ~ScalableBitmap() {} @@ -153,15 +170,10 @@ public: wxBitmap get_bitmap() { return m_bmp.GetBitmapFor(m_parent); } wxWindow* parent() const { return m_parent;} const std::string& name() const { return m_icon_name; } - int px_cnt() const { return m_px_cnt;} + wxSize px_size() const { return wxSize(m_bmp_width, m_bmp_height);} - wxSize GetSize() const { -#ifdef __WIN32__ - return m_bmp.GetPreferredBitmapSizeFor(m_parent); -#else - return m_bmp.GetDefaultSize(); -#endif - } + void SetBitmap(const wxBitmapBundle& bmp) { m_bmp = bmp; } + wxSize GetSize() const { return get_preferred_size(m_bmp, m_parent); } int GetWidth() const { return GetSize().GetWidth(); } int GetHeight() const { return GetSize().GetHeight(); } @@ -170,7 +182,8 @@ private: wxBitmapBundle m_bmp = wxBitmapBundle(); wxBitmap m_bitmap = wxBitmap(); std::string m_icon_name = ""; - int m_px_cnt {16}; + int m_bmp_width{ 16 }; + int m_bmp_height{ -1 }; }; @@ -229,7 +242,8 @@ public: const wxSize& size = wxDefaultSize, const wxPoint& pos = wxDefaultPosition, long style = wxBU_EXACTFIT | wxNO_BORDER, - int bmp_px_cnt = 16); + int width = 16, + int height = -1); ScalableButton( wxWindow * parent, @@ -256,7 +270,8 @@ private: protected: // bitmap dimensions - int m_px_cnt{ 16 }; + int m_bmp_width{ 16 }; + int m_bmp_height{ -1 }; bool m_has_border {false}; }; From a4767695eae0acf611659f4599d8062747203b34 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 28 Mar 2023 17:42:12 +0200 Subject: [PATCH 03/11] Allow font scaling + Fix for em_unit in respect to the scaled font + TextInput: Fix for non-default size --- src/slic3r/GUI/GUI_Utils.hpp | 19 ++++++------------- src/slic3r/GUI/Preferences.cpp | 2 +- src/slic3r/GUI/Widgets/TextInput.cpp | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 905072374b..fcd410ff22 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -94,8 +94,10 @@ public: m_prev_scale_factor = m_scale_factor; m_normal_font = get_default_font_for_dpi(this, dpi); - if (font_point_size > 0) + if (font_point_size > 0) { + m_font_size = font_point_size; m_normal_font.SetPointSize(font_point_size); + } /* Because of default window font is a primary display font, * We should set correct font for window before getting em_unit value. @@ -111,7 +113,7 @@ public: // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). // So, calculate the m_em_unit value from the font size, as before #if !defined(__WXGTK__) - m_em_unit = std::max(10, 10.0f * m_scale_factor); + m_em_unit = std::max(10/*m_font_size*/, int(m_scale_factor * m_font_size)); #else // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); @@ -178,7 +180,6 @@ public: float prev_scale_factor() const { return m_prev_scale_factor; } int em_unit() const { return m_em_unit; } -// int font_size() const { return m_font_size; } const wxFont& normal_font() const { return m_normal_font; } void enable_force_rescale() { m_force_rescale = true; } @@ -197,7 +198,7 @@ protected: private: float m_scale_factor; int m_em_unit; -// int m_font_size; + int m_font_size {10}; wxFont m_normal_font; float m_prev_scale_factor; @@ -206,14 +207,6 @@ private: int m_new_font_point_size; -// void recalc_font() -// { -// wxClientDC dc(this); -// const auto metrics = dc.GetFontMetrics(); -// m_font_size = metrics.height; -// m_em_unit = metrics.averageWidth; -// } - // check if new scale is differ from previous bool is_new_scale_factor() const { return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; } @@ -254,7 +247,7 @@ private: m_normal_font = this->GetFont(); // update em_unit value for new window font - m_em_unit = std::max(10, 10.0f * m_scale_factor); + m_em_unit = std::max(m_font_size, int(m_scale_factor * m_font_size)); // rescale missed controls sizes and images on_dpi_changed(suggested_rect); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 1e884e3fc0..30a2c67c8b 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -600,7 +600,7 @@ void PreferencesDialog::build() activate_options_tab(m_optgroup_other); create_downloader_path_sizer(); -// create_settings_font_widget(); + create_settings_font_widget(); #if ENABLE_ENVIRONMENT_MAP // Add "Render" tab diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp index 4b7dd44ddc..959cb8e974 100644 --- a/src/slic3r/GUI/Widgets/TextInput.cpp +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -56,7 +56,7 @@ void TextInput::Create(wxWindow * parent, state_handler.attach({&label_color, &text_color}); state_handler.update_binds(); - text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE); + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {4, 4}, size, style | wxBORDER_NONE); #ifdef __WXOSX__ text_ctrl->OSXDisableAllSmartSubstitutions(); #endif // __WXOSX__ From f27ad88d558f02c9feac850407f3a80840b47e79 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 21 Jul 2023 16:59:18 +0200 Subject: [PATCH 04/11] WIP (NewUI with fonts): Next improvements for fonts. * Fixed new font applying for TreeCtrl and DataViewCtrl * Fixed update of the em_unit in respect to the new font size + MSW specific: Fixed re-scaling of the non-standard buttons --- src/slic3r/GUI/ExtraRenderers.cpp | 29 +++++++++++++++---------- src/slic3r/GUI/GUI_Utils.hpp | 18 ++++++++------- src/slic3r/GUI/MainFrame.cpp | 10 +-------- src/slic3r/GUI/Tab.cpp | 1 + src/slic3r/GUI/UnsavedChangesDialog.cpp | 20 ++++------------- src/slic3r/GUI/wxExtensions.cpp | 4 ++-- src/slic3r/GUI/wxExtensions.hpp | 2 +- 7 files changed, 37 insertions(+), 47 deletions(-) diff --git a/src/slic3r/GUI/ExtraRenderers.cpp b/src/slic3r/GUI/ExtraRenderers.cpp index 678dc6f7bd..357c58468a 100644 --- a/src/slic3r/GUI/ExtraRenderers.cpp +++ b/src/slic3r/GUI/ExtraRenderers.cpp @@ -154,7 +154,14 @@ bool BitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state) // workaround for Windows DarkMode : Don't respect to the state & wxDATAVIEW_CELL_SELECTED to avoid update of the text color RenderText(m_value.GetText(), xoffset, rect, dc, state & wxDATAVIEW_CELL_SELECTED ? 0 :state); #else + { + wxDataViewCtrl* const view = GetView(); + if (GetAttr().HasFont()) + dc->SetFont(GetAttr().GetEffectiveFont(view->GetFont())); + else + dc->SetFont(view->GetFont()); RenderText(m_value.GetText(), xoffset, rect, dc, state); + } #endif return true; @@ -165,22 +172,22 @@ wxSize BitmapTextRenderer::GetSize() const if (!m_value.GetText().empty()) { wxSize size; + wxDataViewCtrl* const view = GetView(); + wxClientDC dc(view); + if (GetAttr().HasFont()) + dc.SetFont(GetAttr().GetEffectiveFont(view->GetFont())); + else + dc.SetFont(view->GetFont()); + #if defined(SUPPORTS_MARKUP) && defined(wxHAS_GENERIC_DATAVIEWCTRL) if (m_markupText) - { - wxDataViewCtrl* const view = GetView(); - wxClientDC dc(view); - if (GetAttr().HasFont()) - dc.SetFont(GetAttr().GetEffectiveFont(view->GetFont())); - size = m_markupText->Measure(dc); - - int lines = m_value.GetText().Freq('\n') + 1; - size.SetHeight(size.GetHeight() * lines); - } else #endif // SUPPORTS_MARKUP && wxHAS_GENERIC_DATAVIEWCTRL - size = GetTextExtent(m_value.GetText()); + size = dc.GetTextExtent(m_value.GetText()); + + int lines = m_value.GetText().Freq('\n') + 1; + size.SetHeight(size.GetHeight() * lines); if (m_value.GetBitmap().IsOk()) size.x += m_value.GetBitmap().GetWidth() + 4; diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index fcd410ff22..7d22a3370d 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -94,17 +94,13 @@ public: m_prev_scale_factor = m_scale_factor; m_normal_font = get_default_font_for_dpi(this, dpi); - if (font_point_size > 0) { - m_font_size = font_point_size; + if (font_point_size > 0) m_normal_font.SetPointSize(font_point_size); - } /* Because of default window font is a primary display font, * We should set correct font for window before getting em_unit value. */ -#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList this->SetFont(m_normal_font); -#endif this->CenterOnParent(); #ifdef _WIN32 update_dark_ui(this); @@ -113,7 +109,13 @@ public: // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). // So, calculate the m_em_unit value from the font size, as before #if !defined(__WXGTK__) - m_em_unit = std::max(10/*m_font_size*/, int(m_scale_factor * m_font_size)); +#ifdef _WIN32 + const double font_to_em_koef = 10./9.;// Default font point size on Windows is 9 pt +#else // ifdef __WXOSX__ + const double font_to_em_koef = 10./11.;// Default font point size on OSX is 11 pt +#endif + m_em_unit_from_font_size = int(font_to_em_koef * m_normal_font.GetPointSize()); + m_em_unit = std::max(10, int(m_scale_factor * m_em_unit_from_font_size)); #else // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); @@ -198,7 +200,7 @@ protected: private: float m_scale_factor; int m_em_unit; - int m_font_size {10}; + int m_em_unit_from_font_size {10}; wxFont m_normal_font; float m_prev_scale_factor; @@ -247,7 +249,7 @@ private: m_normal_font = this->GetFont(); // update em_unit value for new window font - m_em_unit = std::max(m_font_size, int(m_scale_factor * m_font_size)); + m_em_unit = std::max(10, int(m_scale_factor * m_em_unit_from_font_size)); // rescale missed controls sizes and images on_dpi_changed(suggested_rect); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index c6bb44851c..b979d8c8b6 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -2305,15 +2305,7 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe) if (wxGetApp().is_gcode_viewer()) return; -#if defined(__WXMSW__) - // ys_FIXME! temporary workaround for correct font scaling - // Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts, - // From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT - this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); -#else - this->SetFont(wxGetApp().normal_font()); -// this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); -#endif // __WXMSW__ +// this->SetFont(wxGetApp().normal_font()); // Load the icon either from the exe, or from the ico file. #if _WIN32 diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5199e45220..9fb14d7eb4 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3712,6 +3712,7 @@ void Tab::rebuild_page_tree() continue; auto itemId = m_treectrl->AppendItem(rootItem, translate_category(p->title(), m_type), p->iconID()); m_treectrl->SetItemTextColour(itemId, p->get_item_colour()); + m_treectrl->SetItemFont(itemId, wxGetApp().normal_font()); if (translate_category(p->title(), m_type) == selected) item = itemId; } diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 5ae26ea9e8..723937aafa 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -839,13 +839,7 @@ UnsavedChangesDialog::UnsavedChangesDialog(Preset::Type type, PresetCollection* void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header) { -#if defined(__WXMSW__) - // ys_FIXME! temporary workaround for correct font scaling - // Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts, - // From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT -// this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); this->SetFont(wxGetApp().normal_font()); -#endif // __WXMSW__ int border = 10; int em = em_unit(); @@ -1338,7 +1332,7 @@ void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect) { int em = em_unit(); - msw_buttons_rescale(this, em, { wxID_CANCEL, m_save_btn_id, m_move_btn_id, m_continue_btn_id }); + msw_buttons_rescale(this, em, { wxID_CANCEL, m_save_btn_id, m_move_btn_id, m_continue_btn_id }, 1.5); const wxSize& size = wxSize(70 * em, 30 * em); SetMinSize(size); @@ -1485,6 +1479,7 @@ void DiffPresetDialog::create_presets_sizer() auto add_preset_combobox = [collection, sizer, new_type, this](PresetComboBox** cb_, PresetBundle* preset_bundle) { *cb_ = new PresetComboBox(this, new_type, wxSize(em_unit() * 35, -1), preset_bundle); PresetComboBox*cb = (*cb_); + cb->SetFont(this->GetFont()); cb->show_modif_preset_separately(); cb->set_selection_changed_function([this, new_type, preset_bundle, cb](int selection) { std::string preset_name = Preset::remove_suffix_modified(cb->GetString(selection).ToUTF8().data()); @@ -1549,6 +1544,7 @@ void DiffPresetDialog::create_info_lines() void DiffPresetDialog::create_tree() { m_tree = new DiffViewCtrl(this, wxSize(em_unit() * 65, em_unit() * 40)); + m_tree->SetFont(this->GetFont()); m_tree->AppendToggleColumn_(L"\u2714", DiffModel::colToggle, wxLinux ? 9 : 6); m_tree->AppendBmpTextColumn("", DiffModel::colIconText, 35); m_tree->AppendBmpTextColumn(_L("Left Preset Value"), DiffModel::colOldValue, 15); @@ -1670,17 +1666,9 @@ void DiffPresetDialog::complete_dialog_creation() } DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) - : DPIDialog(mainframe, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + : DPIDialog(mainframe, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER, "diff_presets_dialog", mainframe->normal_font().GetPointSize()), m_pr_technology(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology()) { -#if defined(__WXMSW__) - // ys_FIXME! temporary workaround for correct font scaling - // Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts, - // From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT -// this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - this->SetFont(mainframe->normal_font()); -#endif // __WXMSW__ - // Init bundles assert(wxGetApp().preset_bundle); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 0984c82c57..71ace3dbe0 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -372,9 +372,9 @@ void edit_tooltip(wxString& tooltip) /* Function for rescale of buttons in Dialog under MSW if dpi is changed. * btn_ids - vector of buttons identifiers */ -void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids) +void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids, double height_koef/* = 1.*/) { - const wxSize& btn_size = wxSize(-1, int(2.5f * em_unit + 0.5f)); + const wxSize& btn_size = wxSize(-1, int(2.5 * em_unit * height_koef + 0.5f)); for (int btn_id : btn_ids) { // There is a case [FirmwareDialog], when we have wxControl instead of wxButton diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index a0ed1bbd4c..803c0cc656 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -50,7 +50,7 @@ void enable_menu_item(wxUpdateUIEvent& evt, std::function const cb_condi class wxDialog; void edit_tooltip(wxString& tooltip); -void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids); +void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids, double height_koef = 1.); int em_unit(wxWindow* win); int mode_icon_px_size(); From 1f0b834a70b3152652c4db296e59f55ac0c2275d Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 26 Jul 2023 08:49:03 +0200 Subject: [PATCH 05/11] WIP (NewUI with fonts): Next improvements for fonts. * AboutDialog, SysInfoDialog, ConfigSnapshotDialog, ConfigWizard: Set correct/scaled font. * PreferencesDialog: * Use SpinInput instead of wxSpinCtrl. * Added layout of the activated tab. * Remove "suppress_round_corners" option and ignore its value for whole application. + Plater: fixed obj_list() function to check existence of the control to avoid crash on recreate_GUI(). + GLCanvas3D: Increased delta value between current and new values of the toolbar icon scale. --- src/slic3r/GUI/AboutDialog.cpp | 6 +++--- src/slic3r/GUI/ConfigSnapshotDialog.cpp | 2 +- src/slic3r/GUI/ConfigWizard.cpp | 3 +-- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GUI_App.cpp | 8 ++++++-- src/slic3r/GUI/GUI_Utils.hpp | 2 ++ src/slic3r/GUI/MainFrame.cpp | 4 ---- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/Preferences.cpp | 13 +++++++++---- src/slic3r/GUI/SysInfoDialog.cpp | 4 ++-- 10 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 0f69b3ad51..919c21a5be 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -70,7 +70,7 @@ CopyrightsDialog::CopyrightsDialog() m_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxSize(40 * em_unit(), 20 * em_unit()), wxHW_SCROLLBAR_AUTO); - wxFont font = get_default_font(this); + wxFont font = this->GetFont();// get_default_font(this); const int fs = font.GetPointSize(); const int fs2 = static_cast(1.2f*fs); int size[] = { fs, fs, fs, fs, fs2, fs2, fs2 }; @@ -244,7 +244,7 @@ AboutDialog::AboutDialog() wxStaticText* title = new wxStaticText(this, wxID_ANY, wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME, wxDefaultPosition, wxDefaultSize); wxFont title_font = GUI::wxGetApp().bold_font(); title_font.SetFamily(wxFONTFAMILY_ROMAN); - title_font.SetPointSize(24); + title_font.SetPointSize(int(2.5 * title_font.GetPointSize()));//title_font.SetPointSize(24); title->SetFont(title_font); vsizer->Add(title, 0, wxALIGN_LEFT | wxTOP, 10); } @@ -267,7 +267,7 @@ AboutDialog::AboutDialog() m_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO/*NEVER*/); { m_html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit())); - wxFont font = get_default_font(this); + wxFont font = wxGetApp().normal_font();// get_default_font(this); const auto text_clr = wxGetApp().get_label_clr_default(); const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue())); const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index 619ed8d737..d8b5dacb19 100644 --- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -141,7 +141,7 @@ ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db // text html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); { - wxFont font = get_default_font(this); + wxFont font = this->GetFont();// get_default_font(this); #ifdef __WXMSW__ const int fs = font.GetPointSize(); const int fs1 = static_cast(0.8f*fs); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 741ab7be00..94cb52e0f8 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1342,8 +1342,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent) , preset_update(true) { const AppConfig *app_config = wxGetApp().app_config; - auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - boldfont.SetWeight(wxFONTWEIGHT_BOLD); + auto boldfont = wxGetApp().bold_font(); auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _L("Check for application updates")); box_slic3r->SetValue(app_config->get("notify_release") != "none"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 86505c1dea..013c07e892 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6247,7 +6247,7 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() #if ENABLE_RETINA_GL new_scale /= m_retina_helper->get_scale_factor(); #endif - if (fabs(new_scale - scale) > 0.01) // scale is changed by 1% and more + if (fabs(new_scale - scale) > 0.015) // scale is changed by 1.5% and more wxGetApp().set_auto_toolbar_icon_scale(new_scale); } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 04c2c5c506..a173b621d2 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1758,7 +1758,7 @@ bool GUI_App::tabs_as_menu() const bool GUI_App::suppress_round_corners() const { - return app_config->get("suppress_round_corners") == "1"; + return true;// app_config->get("suppress_round_corners") == "1"; } wxSize GUI_App::get_min_size() const @@ -2129,6 +2129,9 @@ int GUI_App::GetSingleChoiceIndex(const wxString& message, #ifdef _WIN32 wxSingleChoiceDialog dialog(nullptr, message, caption, choices); wxGetApp().UpdateDlgDarkUI(&dialog); + auto children = dialog.GetChildren(); + for (auto child : children) + child->SetFont(normal_font()); dialog.SetSelection(initialSelection); return dialog.ShowModal() == wxID_OK ? dialog.GetSelection() : -1; @@ -2960,7 +2963,8 @@ ObjectSettings* GUI_App::obj_settings() ObjectList* GUI_App::obj_list() { - return sidebar().obj_list(); + // If this method is called before plater_ has been initialized, return nullptr (to avoid a crash) + return plater_ ? sidebar().obj_list() : nullptr; } ObjectLayers* GUI_App::obj_layers() diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 7d22a3370d..10821038f3 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -96,6 +96,8 @@ public: if (font_point_size > 0) m_normal_font.SetPointSize(font_point_size); + else if (parent) + m_normal_font.SetPointSize(parent->GetFont().GetPointSize()); /* Because of default window font is a primary display font, * We should set correct font for window before getting em_unit value. diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index b979d8c8b6..e68d94348f 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -742,9 +742,7 @@ void MainFrame::init_tabpanel() wxGetApp().UpdateDarkUI(m_tabpanel); -#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font()); -#endif m_tabpanel->Hide(); m_settings_dialog.set_tabpanel(m_tabpanel); @@ -2305,8 +2303,6 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe) if (wxGetApp().is_gcode_viewer()) return; -// this->SetFont(wxGetApp().normal_font()); - // Load the icon either from the exe, or from the ico file. #if _WIN32 { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ddbe95a156..12368e3484 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -789,6 +789,7 @@ void Sidebar::priv::hide_rich_tip(wxButton* btn) Sidebar::Sidebar(Plater *parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(42 * wxGetApp().em_unit(), -1)), p(new priv(parent)) { + SetFont(wxGetApp().normal_font()); p->scrolled = new wxScrolledWindow(this); // p->scrolled->SetScrollbars(0, 100, 1, 2); // ys_DELETE_after_testing. pixelsPerUnitY = 100 from https://github.com/prusa3d/PrusaSlicer/commit/8f019e5fa992eac2c9a1e84311c990a943f80b01, // but this cause the bad layout of the sidebar, when all infoboxes appear. @@ -796,7 +797,6 @@ Sidebar::Sidebar(Plater *parent) // But if we set this value to 5, layout will be better p->scrolled->SetScrollRate(0, 5); - SetFont(wxGetApp().normal_font()); #ifndef __APPLE__ #ifdef _WIN32 wxGetApp().UpdateDarkUI(this); @@ -2092,8 +2092,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) , collapse_toolbar(GLToolbar::Normal, "Collapse") , m_project_filename(wxEmptyString) { - this->q->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - background_process.set_fff_print(&fff_print); background_process.set_sla_print(&sla_print); background_process.set_gcode_result(&gcode_result); @@ -4472,7 +4470,10 @@ void Plater::priv::on_action_layersediting(SimpleEvent&) void Plater::priv::on_object_select(SimpleEvent& evt) { - wxGetApp().obj_list()->update_selections(); + if (auto obj_list = wxGetApp().obj_list()) + obj_list->update_selections(); + else + return; selection_changed(); } diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 30a2c67c8b..a41f67c21b 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -21,6 +21,8 @@ #include "GLCanvas3D.hpp" #include "ConfigWizard.hpp" +#include "Widgets/SpinInput.hpp" + #include #ifdef WIN32 @@ -151,6 +153,8 @@ static void activate_options_tab(std::shared_ptr optgroup) wxBoxSizer* sizer = static_cast(static_cast(optgroup->parent())->GetSizer()); sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 10); + optgroup->parent()->Layout(); + // apply sercher wxGetApp().sidebar().get_searcher().append_preferences_options(optgroup->get_lines()); } @@ -526,14 +530,14 @@ void PreferencesDialog::build() #endif m_optgroup_gui->append_separator(); - +/* append_bool_option(m_optgroup_gui, "suppress_round_corners", L("Suppress round corners for controls (experimental)"), L("If enabled, Settings Tabs will be placed as menu items. If disabled, old UI will be used."), app_config->get("suppress_round_corners") == "1"); m_optgroup_gui->append_separator(); - +*/ append_bool_option(m_optgroup_gui, "show_hints", L("Show \"Tip of the day\" notification after start"), L("If enabled, useful hints are displayed at startup."), @@ -1079,16 +1083,17 @@ void PreferencesDialog::create_settings_font_widget() wxStaticText* font_example = new wxStaticText(parent, wxID_ANY, "Application text"); int val = wxGetApp().normal_font().GetPointSize(); - wxSpinCtrl* size_sc = new wxSpinCtrl(parent, wxID_ANY, format_wxstr("%1%", val), wxDefaultPosition, wxSize(15*em_unit(), -1), wxTE_PROCESS_ENTER | wxSP_ARROW_KEYS + SpinInput* size_sc = new SpinInput(parent, format_wxstr("%1%", val), "", wxDefaultPosition, wxSize(15 * em_unit(), -1), wxTE_PROCESS_ENTER | wxSP_ARROW_KEYS #ifdef _WIN32 | wxBORDER_SIMPLE #endif , 8, 20); wxGetApp().UpdateDarkUI(size_sc); - auto apply_font = [this, font_example, opt_key](const int val, const wxFont& font) { + auto apply_font = [this, font_example, opt_key, stb_sizer](const int val, const wxFont& font) { font_example->SetFont(font); m_values[opt_key] = format("%1%", val); + stb_sizer->Layout(); refresh_og(m_optgroup_other); }; diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index b8c7646b5d..603bfe9870 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -122,13 +122,13 @@ SysInfoDialog::SysInfoDialog() wxStaticText* title = new wxStaticText(this, wxID_ANY, wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME, wxDefaultPosition, wxDefaultSize); wxFont title_font = wxGetApp().bold_font(); title_font.SetFamily(wxFONTFAMILY_ROMAN); - title_font.SetPointSize(22); + title_font.SetPointSize(int(2.5 * title_font.GetPointSize()));//title_font.SetPointSize(22); title->SetFont(title_font); vsizer->Add(title, 0, wxEXPAND | wxALIGN_LEFT | wxTOP, wxGetApp().em_unit()/*50*/); } // main_info_text - wxFont font = get_default_font(this); + wxFont font = GetFont();// get_default_font(this); const auto text_clr = wxGetApp().get_label_clr_default(); auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue())); auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); From 9cf971769deee2978f701f55940738da34b4c7cf Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 21 Sep 2023 11:15:44 +0200 Subject: [PATCH 06/11] WIP (NewUI with fonts): Improvements some controls * SpinInput : Code refactoring * BitmapToggleButton : * Create wxBitmapToggleButton if control doesn't have a label and wxToggleButton otherwise * Linux specific: Calculate default size from label size + Tab: Linux specific: Set background color for tree_ctrl and don't set background color for Tab --- src/slic3r/GUI/Tab.cpp | 5 +++- src/slic3r/GUI/Tab.hpp | 2 +- src/slic3r/GUI/Widgets/BitmapToggleButton.cpp | 29 +++++++++++-------- src/slic3r/GUI/Widgets/DropDown.cpp | 1 - src/slic3r/GUI/Widgets/SpinInput.cpp | 18 ++++++------ src/slic3r/GUI/Widgets/SpinInput.hpp | 8 ++++- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 9fb14d7eb4..46eaf3ed9d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -86,7 +86,7 @@ Tab::Tab(wxBookCtrlBase* parent, const wxString& title, Preset::Type type) : #ifdef __WXMSW__ wxGetApp().UpdateDarkUI(this); -#else +#elif __WXOSX__ SetBackgroundColour(parent->GetBackgroundColour()); #endif @@ -296,6 +296,9 @@ void Tab::create_preset_tab() m_treectrl = new wxTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(20 * m_em_unit, -1), wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_SUNKEN | wxWANTS_CHARS); m_treectrl->SetFont(wxGetApp().normal_font()); +#ifdef __linux__ + m_treectrl->SetBackgroundColour(m_parent->GetBackgroundColour()); +#endif m_left_sizer->Add(m_treectrl, 1, wxEXPAND); // Index of the last icon inserted into m_treectrl m_icon_count = -1; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 69ac11f95c..0f41c0f9da 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -73,7 +73,7 @@ class SubstitutionManager std::function m_cb_hide_delete_all_btn{ nullptr }; std::vector m_substitutions; - std::vector m_chb_match_single_lines; + std::vector m_chb_match_single_lines; void validate_length(); bool is_compatible_with_ui(); diff --git a/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp b/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp index 4531446665..c8f2292090 100644 --- a/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp +++ b/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp @@ -4,17 +4,17 @@ BitmapToggleButton::BitmapToggleButton(wxWindow* parent, const wxString& label, wxWindowID id) { + if (label.IsEmpty()) + wxBitmapToggleButton::Create(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT); + else { #ifdef __linux__ - long style = wxBORDER_NONE | wxBU_EXACTFIT; - if (label.IsEmpty()) - style = style | wxBU_NOTEXT; - // Call Create() from wxToggleButton instead of wxBitmapToggleButton to allow add Label text under Linux - wxToggleButton::Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style); + wxSize def_size = wxSize(parent->GetTextExtent(label).GetX() + 20, 20); #else - wxBitmapToggleButton::Create(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT); - if (!label.IsEmpty()) - SetLabel(label); + wxSize def_size = wxDefaultSize; #endif + // Call Create() from wxToggleButton instead of wxBitmapToggleButton to allow add Label text under Linux + wxToggleButton::Create(parent, id, label, wxDefaultPosition, def_size, wxBORDER_NONE | wxBU_EXACTFIT); + } #ifdef __WXMSW__ if (parent) { @@ -22,7 +22,7 @@ BitmapToggleButton::BitmapToggleButton(wxWindow* parent, const wxString& label, SetForegroundColour(parent->GetForegroundColour()); } #elif __linux__ - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { @@ -39,9 +39,14 @@ BitmapToggleButton::BitmapToggleButton(wxWindow* parent, const wxString& label, void BitmapToggleButton::update_size() { #ifdef __linux__ + wxSize bmp_sz = GetBitmap().GetSize(); + wxSize sz = GetSize(); if (GetLabel().IsEmpty()) - SetSize(GetBitmap().GetSize()); - else + SetSize(bmp_sz); + else + SetSize(sz.x, bmp_sz.y); +#else + wxSize best_sz = GetBestSize(); + SetSize(best_sz); #endif - SetSize(GetBestSize()); } diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index 873a734e80..44e557e89f 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -87,7 +87,6 @@ void DropDown::Invalidate(bool clear) void DropDown::SetSelection(int n) { - assert(n < (int) texts.size()); if (n >= (int) texts.size()) n = -1; if (selection == n) return; diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index 1dce77bb8a..6634638784 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -73,8 +73,8 @@ void SpinInput::Create(wxWindow *parent, text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInput::onTextEnter, this); text_ctrl->Bind(wxEVT_KEY_DOWN, &SpinInput::keyPressed, this); text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu - button_inc = createButton(true); - button_dec = createButton(false); + button_inc = create_button(ButtonId::btnIncrease); + button_dec = create_button(ButtonId::btnDecrease); delta = 0; timer.Bind(wxEVT_TIMER, &SpinInput::onTimer, this); @@ -265,11 +265,11 @@ void SpinInput::render(wxDC& dc) // draw seperator of buttons wxPoint pt = button_inc->GetPosition(); pt.y = size.y / 2; - pt.x += 1; dc.SetPen(wxPen(border_color.defaultColor())); const double scale = dc.GetContentScaleFactor(); - dc.DrawLine(pt, pt + wxSize{button_inc->GetSize().x - int(3. * scale), 0}); + const int btn_w = button_inc->GetSize().GetWidth(); + dc.DrawLine(pt, pt + wxSize{ btn_w - int(scale), 0}); // draw label auto label = GetLabel(); if (!label.IsEmpty()) { @@ -308,16 +308,16 @@ void SpinInput::messureSize() button_dec->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 + 1}); } -Button *SpinInput::createButton(bool inc) +Button *SpinInput::create_button(ButtonId id) { - auto btn = new Button(this, "", inc ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); + auto btn = new Button(this, "", id == ButtonId::btnIncrease ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); btn->SetCornerRadius(0); - btn->SetInactiveIcon(inc ? "spin_inc" : "spin_dec"); + btn->SetInactiveIcon(id == ButtonId::btnIncrease ? "spin_inc" : "spin_dec"); btn->DisableFocusFromKeyboard(); btn->SetSelected(false); btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) { - delta = inc ? 1 : -1; + delta = id == ButtonId::btnIncrease ? 1 : -1; SetValue(val + delta); text_ctrl->SetFocus(); btn->CaptureMouse(); @@ -326,7 +326,7 @@ Button *SpinInput::createButton(bool inc) sendSpinEvent(); }); btn->Bind(wxEVT_LEFT_DCLICK, [=](auto &e) { - delta = inc ? 1 : -1; + delta = id == ButtonId::btnIncrease ? 1 : -1; btn->CaptureMouse(); SetValue(val + delta); sendSpinEvent(); diff --git a/src/slic3r/GUI/Widgets/SpinInput.hpp b/src/slic3r/GUI/Widgets/SpinInput.hpp index 932958e138..364d8c71d5 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.hpp +++ b/src/slic3r/GUI/Widgets/SpinInput.hpp @@ -24,6 +24,12 @@ class SpinInput : public wxNavigationEnabled static const int SpinInputWidth = 200; static const int SpinInputHeight = 50; + enum class ButtonId + { + btnIncrease, + btnDecrease + }; + public: SpinInput(); @@ -90,7 +96,7 @@ private: void messureSize(); - Button *createButton(bool inc); + Button *create_button(ButtonId id); // some useful events void mouseWheelMoved(wxMouseEvent& event); From d42e3823dc3a114a66c291bd95617edf0df34599 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 21 Sep 2023 14:51:35 +0200 Subject: [PATCH 07/11] Preferences: Linux specific: Fixed layouts. (CallAfter() is used to correct set of controlls sizes) --- src/slic3r/GUI/Preferences.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index a41f67c21b..2c566a62af 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -227,7 +227,12 @@ void PreferencesDialog::build() tabs = new Notebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME | wxNB_DEFAULT); #else tabs = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL |wxNB_NOPAGETHEME | wxNB_DEFAULT ); -// tabs->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#ifdef __linux__ + tabs->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxBookCtrlEvent& e) { + e.Skip(); + CallAfter([this]() { tabs->GetCurrentPage()->Layout(); }); + }); +#endif #endif // Add "General" tab @@ -1094,7 +1099,11 @@ void PreferencesDialog::create_settings_font_widget() font_example->SetFont(font); m_values[opt_key] = format("%1%", val); stb_sizer->Layout(); +#ifdef __linux__ + CallAfter([this]() { refresh_og(m_optgroup_other); }); +#else refresh_og(m_optgroup_other); +#endif }; auto change_value = [size_sc, apply_font](wxCommandEvent& evt) { From 1a182999a810af9163026e58646b662dae26a44a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 10 Oct 2023 09:42:18 +0200 Subject: [PATCH 08/11] SkinnedUI: bug fixing and improvements: * SPE-1945 : LINUX - Black background in dark mode in search - "Category" * SPE-1941 : Font size is applied for old PS version (app_config key for font size is changed to "font_pt_size") * SPE-1939 : Preferences : PS widows have incorrect dims when used max font size * SPE-1943 : Fixed gtk resize popup window (Manually merged https://github.com/bambulab/BambuStudio/commit/60dbf71cd6204ffc3b24e4369a66bc3f0b533db2 ) * SPE-1942 : Linux specific: Brim check button on sidebar jumps * SPE-1944 : PrusaConnect URL is missing in physical Printer + Changed icon which is used to comboboxes --- resources/icons/drop_down.svg | 2 +- src/slic3r/GUI/GUI_App.cpp | 20 ++++++++++--- src/slic3r/GUI/GUI_App.hpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 8 ++--- src/slic3r/GUI/PhysicalPrinterDialog.hpp | 4 +-- src/slic3r/GUI/Preferences.cpp | 30 +++++++++++++++---- src/slic3r/GUI/Search.cpp | 4 +++ src/slic3r/GUI/Widgets/BitmapToggleButton.cpp | 12 ++------ src/slic3r/GUI/Widgets/DropDown.cpp | 8 +++++ 10 files changed, 65 insertions(+), 27 deletions(-) diff --git a/resources/icons/drop_down.svg b/resources/icons/drop_down.svg index 3354ddc295..1276e34039 100644 --- a/resources/icons/drop_down.svg +++ b/resources/icons/drop_down.svg @@ -1,3 +1,3 @@ - + diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a173b621d2..23d556fced 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1326,7 +1326,7 @@ bool GUI_App::on_init_inner() if (!delayed_error_load_presets.empty()) show_error(nullptr, delayed_error_load_presets); - mainframe = new MainFrame(app_config->has("font_size") ? atoi(app_config->get("font_size").c_str()) : -1); + mainframe = new MainFrame(app_config->has("font_pt_size") ? atoi(app_config->get("font_pt_size").c_str()) : -1); // hide settings tabs after first Layout if (is_editor()) mainframe->select_tab(size_t(0)); @@ -1761,9 +1761,21 @@ bool GUI_App::suppress_round_corners() const return true;// app_config->get("suppress_round_corners") == "1"; } -wxSize GUI_App::get_min_size() const +wxSize GUI_App::get_min_size(wxWindow* display_win) const { - return wxSize(76*m_em_unit, 49 * m_em_unit); + wxSize min_size(76*m_em_unit, 49 * m_em_unit); + + const wxDisplay display = wxDisplay(display_win); + wxRect display_rect = display.GetGeometry(); + display_rect.width *= 0.75; + display_rect.height *= 0.75; + + if (min_size.x > display_rect.GetWidth()) + min_size.x = display_rect.GetWidth(); + if (min_size.y > display_rect.GetHeight()) + min_size.y = display_rect.GetHeight(); + + return min_size; } float GUI_App::toolbar_icon_scale(const bool is_limited/* = false*/) const @@ -1838,7 +1850,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name) dlg.Update(10, _L("Recreating") + dots); MainFrame *old_main_frame = mainframe; - mainframe = new MainFrame(app_config->has("font_size") ? atoi(app_config->get("font_size").c_str()) : -1); + mainframe = new MainFrame(app_config->has("font_pt_size") ? atoi(app_config->get("font_pt_size").c_str()) : -1); if (is_editor()) // hide settings tabs after first Layout mainframe->select_tab(size_t(0)); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index fb4e1d87ab..e9e7dc17c0 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -249,7 +249,7 @@ public: int em_unit() const { return m_em_unit; } bool tabs_as_menu() const; bool suppress_round_corners() const; - wxSize get_min_size() const; + wxSize get_min_size(wxWindow* display_win) const; float toolbar_icon_scale(const bool is_limited = false) const; void set_auto_toolbar_icon_scale(float scale) const; void check_printer_presets(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index e68d94348f..26befcb803 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -213,7 +213,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S sizer->SetSizeHints(this); Fit(); - const wxSize min_size = wxGetApp().get_min_size(); //wxSize(76*wxGetApp().em_unit(), 49*wxGetApp().em_unit()); + const wxSize min_size = wxGetApp().get_min_size(this); #ifdef __APPLE__ // Using SetMinSize() on Mac messes up the window position in some cases // cf. https://groups.google.com/forum/#!topic/wx-users/yUKPBBfXWO0 diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 807413e047..5ef37e013f 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -184,7 +184,7 @@ PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_ m_add_preset_btn->SetToolTip(_L("Add preset for this printer device")); m_add_preset_btn->Bind(wxEVT_BUTTON, &PhysicalPrinterDialog::AddPreset, this); - m_printer_name = new wxTextCtrl(this, wxID_ANY, printer_name, wxDefaultPosition, wxDefaultSize); + m_printer_name = new ::TextInput(this,printer_name); wxGetApp().UpdateDarkUI(m_printer_name); m_printer_name->Bind(wxEVT_TEXT, [this](wxEvent&) { this->update_full_printer_names(); }); @@ -242,7 +242,7 @@ PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_ if (new_printer) { m_printer_name->SetFocus(); - m_printer_name->SelectAll(); + m_printer_name->GetTextCtrl()->SelectAll(); } this->Fit(); @@ -508,7 +508,7 @@ void PhysicalPrinterDialog::update(bool printer_change) supports_multiple_printers = opt && opt->value == htRepetier; if (opt->value == htPrusaConnect) { // automatically show default prusaconnect address if (Field* printhost_field = m_optgroup->get_field("print_host"); printhost_field) { - if (wxTextCtrl* temp = dynamic_cast(printhost_field->getWindow()); temp && temp->GetValue().IsEmpty()) { + if (text_ctrl* temp = dynamic_cast(printhost_field->getWindow()); temp && temp->GetValue().IsEmpty()) { temp->SetValue(L"https://connect.prusa3d.com"); } } @@ -674,7 +674,7 @@ void PhysicalPrinterDialog::update_full_printer_names() InfoDialog(this, format_wxstr("%1%: \"%2%\" ", _L("Unexpected character"), str), _L("The following characters are not allowed in the name") + ": " + unusable_symbols).ShowModal(); m_printer_name->SetValue(printer_name); - m_printer_name->SetInsertionPointEnd(); + m_printer_name->GetTextCtrl()->SetInsertionPointEnd(); return; } } diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.hpp b/src/slic3r/GUI/PhysicalPrinterDialog.hpp index fd98c3d61a..8668fd1719 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.hpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.hpp @@ -10,10 +10,10 @@ #include #include "libslic3r/Preset.hpp" +#include "Widgets/TextInput.hpp" #include "GUI_Utils.hpp" class wxString; -class wxTextCtrl; class wxStaticText; class ScalableButton; class wxBoxSizer; @@ -67,7 +67,7 @@ class PhysicalPrinterDialog : public DPIDialog wxString m_default_name; DynamicPrintConfig* m_config { nullptr }; - wxTextCtrl* m_printer_name { nullptr }; + ::TextInput* m_printer_name { nullptr }; std::vector m_presets; ConfigOptionsGroup* m_optgroup { nullptr }; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 2c566a62af..07322b849e 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -66,13 +66,25 @@ namespace GUI { PreferencesDialog::PreferencesDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _L("Preferences"), wxDefaultPosition, - wxDefaultSize, wxDEFAULT_DIALOG_STYLE) + wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { #ifdef __WXOSX__ isOSX = true; #endif build(); + wxSize sz = GetSize(); + sz.x += em_unit(); + + const size_t pages_cnt = tabs->GetPageCount(); + for (size_t tab_id = 0; tab_id < pages_cnt; tab_id++) { + wxSizer* tab_sizer = tabs->GetPage(tab_id)->GetSizer(); + wxScrolledWindow* scrolled = static_cast(tab_sizer->GetItem(size_t(0))->GetWindow()); + scrolled->SetScrollRate(0, 5); + } + + SetSize(sz); + m_highlighter.set_timer_owner(this, 0); } @@ -133,14 +145,22 @@ void PreferencesDialog::show(const std::string& highlight_opt_key /*= std::strin static std::shared_ptrcreate_options_tab(const wxString& title, wxBookCtrlBase* tabs) { wxPanel* tab = new wxPanel(tabs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); + tabs->AddPage(tab, _(title)); tab->SetFont(wxGetApp().normal_font()); + auto scrolled = new wxScrolledWindow(tab); + + // Sizer in the scrolled area + auto* scrolled_sizer = new wxBoxSizer(wxVERTICAL); + scrolled->SetSizer(scrolled_sizer); + wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add(scrolled, 1, wxEXPAND); sizer->SetSizeHints(tab); tab->SetSizer(sizer); - std::shared_ptr optgroup = std::make_shared(tab); + std::shared_ptr optgroup = std::make_shared(scrolled); optgroup->label_width = 40; optgroup->set_config_category_and_type(title, int(Preset::TYPE_PREFERENCES)); return optgroup; @@ -722,7 +742,7 @@ void PreferencesDialog::accept(wxEvent&) #endif // __linux__ } - std::vector options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled", "font_size", "suppress_round_corners" }; + std::vector options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled", "font_pt_size", "suppress_round_corners" }; for (const std::string& option : options_to_recreate_GUI) { if (m_values.find(option) != m_values.end()) { @@ -903,7 +923,7 @@ void PreferencesDialog::refresh_og(std::shared_ptr og) { og->parent()->Layout(); tabs->Layout(); - this->layout(); +// this->layout(); } void PreferencesDialog::create_icon_size_slider() @@ -1081,7 +1101,7 @@ void PreferencesDialog::create_settings_font_widget() wxStaticBox* stb = new wxStaticBox(parent, wxID_ANY, _(title)); if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); - const std::string opt_key = "font_size"; + const std::string opt_key = "font_pt_size"; m_blinkers[opt_key] = new BlinkingBitmap(parent); wxSizer* stb_sizer = new wxStaticBoxSizer(stb, wxHORIZONTAL); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 79b7ed70d4..35dec1f481 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -487,7 +487,11 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher) searcher(searcher) { SetFont(GUI::wxGetApp().normal_font()); +#if _WIN32 GUI::wxGetApp().UpdateDarkUI(this); +#elif __WXGTK__ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#endif default_string = _L("Enter a search term"); int border = 10; diff --git a/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp b/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp index c8f2292090..e73b789c5f 100644 --- a/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp +++ b/src/slic3r/GUI/Widgets/BitmapToggleButton.cpp @@ -8,7 +8,8 @@ BitmapToggleButton::BitmapToggleButton(wxWindow* parent, const wxString& label, wxBitmapToggleButton::Create(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT); else { #ifdef __linux__ - wxSize def_size = wxSize(parent->GetTextExtent(label).GetX() + 20, 20); + wxSize label_size = parent->GetTextExtent(label); + wxSize def_size = wxSize(label_size.GetX() + 20, label_size.GetY()); #else wxSize def_size = wxDefaultSize; #endif @@ -38,14 +39,7 @@ BitmapToggleButton::BitmapToggleButton(wxWindow* parent, const wxString& label, void BitmapToggleButton::update_size() { -#ifdef __linux__ - wxSize bmp_sz = GetBitmap().GetSize(); - wxSize sz = GetSize(); - if (GetLabel().IsEmpty()) - SetSize(bmp_sz); - else - SetSize(sz.x, bmp_sz.y); -#else +#ifndef __WXGTK__ wxSize best_sz = GetBestSize(); SetSize(best_sz); #endif diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index 44e557e89f..999dba41f8 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -11,6 +11,10 @@ #include +#ifdef __WXGTK__ +#include +#endif + wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent); BEGIN_EVENT_TABLE(DropDown, wxPopupTransientWindow) @@ -380,6 +384,10 @@ void DropDown::messureSize() szContent.y *= std::min((size_t)15, texts.size()); szContent.y += texts.size() > 15 ? rowSize.y / 2 : 0; wxWindow::SetSize(szContent); +#ifdef __WXGTK__ + // Gtk has a wrapper window for popup widget + gtk_window_resize(GTK_WINDOW(m_widget), szContent.x, szContent.y); +#endif need_sync = false; } From 168dadc0fae444fb9f3054020a393643ad53cba2 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 16 Oct 2023 11:10:11 +0200 Subject: [PATCH 09/11] OSX specific: Set window variant for regular buttons to correct rendering with big font --- src/slic3r/GUI/AboutDialog.cpp | 4 ++++ src/slic3r/GUI/BedShapeDialog.cpp | 10 +++++++++- src/slic3r/GUI/ConfigSnapshotDialog.cpp | 3 ++- src/slic3r/GUI/ConfigWizard.cpp | 21 +++++++++++++++------ src/slic3r/GUI/FirmwareDialog.cpp | 4 ++++ src/slic3r/GUI/GUI_App.cpp | 13 +++++++++++++ src/slic3r/GUI/GUI_App.hpp | 1 + src/slic3r/GUI/GalleryDialog.cpp | 7 +++++-- src/slic3r/GUI/KBShortcutsDialog.cpp | 3 ++- src/slic3r/GUI/MsgDialog.cpp | 1 + src/slic3r/GUI/Plater.cpp | 12 +++++++----- src/slic3r/GUI/Preferences.cpp | 2 ++ src/slic3r/GUI/SysInfoDialog.cpp | 2 ++ src/slic3r/GUI/Tab.cpp | 1 + src/slic3r/GUI/WipeTowerDialog.cpp | 11 +++++++++-- 15 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 919c21a5be..1da5faf2b6 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -83,6 +83,7 @@ CopyrightsDialog::CopyrightsDialog() m_html->Bind(wxEVT_HTML_LINK_CLICKED, &CopyrightsDialog::onLinkClicked, this); wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); wxGetApp().UpdateDlgDarkUI(this, true); this->SetEscapeId(wxID_CLOSE); this->Bind(wxEVT_BUTTON, &CopyrightsDialog::onCloseDialog, this, wxID_CLOSE); @@ -309,16 +310,19 @@ AboutDialog::AboutDialog() wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); m_copy_rights_btn_id = NewControlId(); auto copy_rights_btn = new wxButton(this, m_copy_rights_btn_id, _L("Portions copyright")+dots); buttons->Insert(0, copy_rights_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5); copy_rights_btn->Bind(wxEVT_BUTTON, &AboutDialog::onCopyrightBtn, this); + wxGetApp().SetWindowVariantForButton(copy_rights_btn); m_copy_version_btn_id = NewControlId(); auto copy_version_btn = new wxButton(this, m_copy_version_btn_id, _L("Copy Version Info")); buttons->Insert(1, copy_version_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5); copy_version_btn->Bind(wxEVT_BUTTON, &AboutDialog::onCopyToClipboard, this); + wxGetApp().SetWindowVariantForButton(copy_version_btn); wxGetApp().UpdateDlgDarkUI(this, true); diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index b7e32151cd..a8bbacf6e6 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -150,7 +150,10 @@ void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const Co auto main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_panel, 1, wxEXPAND); - main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); + wxStdDialogButtonSizer* buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); + wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); wxGetApp().UpdateDlgDarkUI(this, true); @@ -214,6 +217,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf line.full_width = 1; line.widget = [this](wxWindow* parent) { wxButton* shape_btn = new wxButton(parent, wxID_ANY, _L("Load shape from STL...")); + wxGetApp().SetWindowVariantForButton(shape_btn); wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL); shape_sizer->Add(shape_btn, 1, wxEXPAND); @@ -294,6 +298,7 @@ wxPanel* BedShapePanel::init_texture_panel() line.full_width = 1; line.widget = [this](wxWindow* parent) { wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load...")); + wxGetApp().SetWindowVariantForButton(load_btn); wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL); load_sizer->Add(load_btn, 1, wxEXPAND); @@ -303,6 +308,7 @@ wxPanel* BedShapePanel::init_texture_panel() filename_sizer->Add(filename_lbl, 1, wxEXPAND); wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove")); + wxGetApp().SetWindowVariantForButton(remove_btn); wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL); remove_sizer->Add(remove_btn, 1, wxEXPAND); @@ -365,6 +371,7 @@ wxPanel* BedShapePanel::init_model_panel() line.full_width = 1; line.widget = [this](wxWindow* parent) { wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load...")); + wxGetApp().SetWindowVariantForButton(load_btn); wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL); load_sizer->Add(load_btn, 1, wxEXPAND); @@ -373,6 +380,7 @@ wxPanel* BedShapePanel::init_model_panel() filename_sizer->Add(filename_lbl, 1, wxEXPAND); wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove")); + wxGetApp().SetWindowVariantForButton(remove_btn); wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL); remove_sizer->Add(remove_btn, 1, wxEXPAND); diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index d8b5dacb19..fb78b0d253 100644 --- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -160,7 +160,8 @@ ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db } wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE); - wxGetApp().UpdateDarkUI(static_cast(this->FindWindowById(wxID_CLOSE, this))); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + wxGetApp().UpdateDarkUI(buttons->GetCancelButton()); this->SetEscapeId(wxID_CLOSE); this->Bind(wxEVT_BUTTON, &ConfigSnapshotDialog::onCloseDialog, this, wxID_CLOSE); vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 94cb52e0f8..7c9c696efa 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -423,6 +423,10 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt title_sizer->Add(sel_all, 0, wxRIGHT, BTN_SPACING); title_sizer->Add(sel_none); + wxGetApp().SetWindowVariantForButton(sel_all_std); + wxGetApp().SetWindowVariantForButton(sel_all); + wxGetApp().SetWindowVariantForButton(sel_none); + wxGetApp().UpdateDarkUI(sel_all_std); wxGetApp().UpdateDarkUI(sel_all); wxGetApp().UpdateDarkUI(sel_none); @@ -748,6 +752,9 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin wxGetApp().UpdateDarkUI(sel_all); wxGetApp().UpdateDarkUI(sel_none); + wxGetApp().SetWindowVariantForButton(sel_all); + wxGetApp().SetWindowVariantForButton(sel_none); + grid->Add(new wxBoxSizer(wxHORIZONTAL)); grid->Add(new wxBoxSizer(wxHORIZONTAL)); grid->Add(new wxBoxSizer(wxHORIZONTAL)); @@ -861,10 +868,8 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector" "" "" - "" "%s

%s" "
" - "
" "" "" , bgr_clr_str @@ -886,7 +891,6 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector" "" "" - "" "%s

%s" "" "" @@ -907,15 +911,13 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector" "
" "
" - "
" "" "" ); } } - - wxFont font = get_default_font_for_dpi(this, get_dpi_for_window(this)); + wxFont font = wxGetApp().normal_font();// get_default_font_for_dpi(this, get_dpi_for_window(this)); const int fs = font.GetPointSize(); int size[] = { fs,fs,fs,fs,fs,fs,fs }; html_window->SetFonts(font.GetFaceName(), font.GetFaceName(), size); @@ -1421,6 +1423,7 @@ Worker::Worker(wxWindow* parent) this->Add(m_input_path, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); auto* button_path = new wxButton(m_parent, wxID_ANY, _L("Browse")); + wxGetApp().SetWindowVariantForButton(button_path); this->Add(button_path, 0, wxEXPAND | wxTOP | wxLEFT, 5); button_path->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { boost::filesystem::path chosen_dest(boost::nowide::narrow(m_input_path->GetValue())); @@ -3351,6 +3354,12 @@ ConfigWizard::ConfigWizard(wxWindow *parent) wxGetApp().UpdateDarkUI(p->btn_finish); wxGetApp().UpdateDarkUI(p->btn_cancel); + wxGetApp().SetWindowVariantForButton(p->btn_sel_all); + wxGetApp().SetWindowVariantForButton(p->btn_prev); + wxGetApp().SetWindowVariantForButton(p->btn_next); + wxGetApp().SetWindowVariantForButton(p->btn_finish); + wxGetApp().SetWindowVariantForButton(p->btn_cancel); + const auto prusa_it = p->bundles.find("PrusaResearch"); wxCHECK_RET(prusa_it != p->bundles.cend(), "Vendor PrusaResearch not found"); const VendorProfile *vendor_prusa = prusa_it->second.vendor_profile; diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index fa035abf66..9d6dc2c979 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -817,11 +817,13 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, /*wxFileSelectorPromptStr*/_L("Select a file"), "Hex files (*.hex)|*.hex|All files|*.*"); p->hex_picker->GetPickerCtrl()->SetLabelText(_(L("Browse"))); + GUI::wxGetApp().SetWindowVariantForButton(static_cast(p->hex_picker->GetPickerCtrl())); auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:"))); p->port_picker = new wxComboBox(panel, wxID_ANY); p->txt_port_autodetect = new wxStaticText(panel, wxID_ANY, _(L("Autodetected"))); p->btn_rescan = new wxButton(panel, wxID_ANY, _(L("Rescan"))); + GUI::wxGetApp().SetWindowVariantForButton(p->btn_rescan); auto *port_sizer = new wxBoxSizer(wxHORIZONTAL); port_sizer->Add(p->port_picker, 1, wxEXPAND | wxRIGHT, SPACING); port_sizer->Add(p->btn_rescan, 0); @@ -864,7 +866,9 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : vsizer->Add(p->spoiler, 1, wxEXPAND | wxBOTTOM, SPACING); p->btn_close = new wxButton(panel, wxID_CLOSE, _(L("Close"))); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac + GUI::wxGetApp().SetWindowVariantForButton(p->btn_close); p->btn_flash = new wxButton(panel, wxID_ANY, p->btn_flash_label_ready); + GUI::wxGetApp().SetWindowVariantForButton(p->btn_flash); p->btn_flash->Disable(); auto *bsizer = new wxBoxSizer(wxHORIZONTAL); bsizer->Add(p->btn_close); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 23d556fced..7c69131c80 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1649,6 +1649,19 @@ void GUI_App::UpdateAllStaticTextDarkUI(wxWindow* parent) #endif } +void GUI_App::SetWindowVariantForButton(wxButton* btn) +{ +#ifdef __APPLE__ + // This is a limit imposed by OSX. The way the native button widget is drawn only allows it to be stretched horizontally, + // and the vertical size is fixed. (see https://stackoverflow.com/questions/29083891/wxpython-button-size-being-ignored-on-osx) + // But standard height is possible to change using SetWindowVariant method (see https://docs.wxwidgets.org/3.0/window_8h.html#a879bccd2c987fedf06030a8abcbba8ac) + if (m_normal_font.GetPointSize() > 15) { + btn->SetWindowVariant(wxWINDOW_VARIANT_LARGE); + btn->SetFont(m_normal_font); + } +#endif +} + void GUI_App::init_fonts() { m_small_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index e9e7dc17c0..66c259b813 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -214,6 +214,7 @@ public: void UpdateDVCDarkUI(wxDataViewCtrl* dvc, bool highlited = false); // update color mode for panel including all static texts controls void UpdateAllStaticTextDarkUI(wxWindow* parent); + void SetWindowVariantForButton(wxButton* btn); void init_fonts(); void update_fonts(const MainFrame *main_frame = nullptr); void set_label_clr_modified(const wxColour& clr); diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index dd7ac911bf..2060769ead 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -98,10 +98,12 @@ GalleryDialog::GalleryDialog(wxWindow* parent) : #endif wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK | wxCLOSE); - m_ok_btn = static_cast(FindWindowById(wxID_OK, this)); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + m_ok_btn = buttons->GetAffirmativeButton(); + wxGetApp().SetWindowVariantForButton(m_ok_btn); m_ok_btn->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(!m_selected_items.empty()); }); - static_cast(FindWindowById(wxID_CLOSE, this))->Bind(wxEVT_BUTTON, [this](wxCommandEvent&){ this->EndModal(wxID_CLOSE); }); + buttons->GetCancelButton()->Bind(wxEVT_BUTTON, [this](wxCommandEvent&){ this->EndModal(wxID_CLOSE); }); this->SetEscapeId(wxID_CLOSE); auto add_btn = [this, buttons]( size_t pos, int& ID, wxString title, wxString tooltip, void (GalleryDialog::* method)(wxEvent&), @@ -109,6 +111,7 @@ GalleryDialog::GalleryDialog(wxWindow* parent) : ID = NewControlId(); wxButton* btn = new wxButton(this, ID, title); btn->SetToolTip(tooltip); + wxGetApp().SetWindowVariantForButton(btn); btn->Bind(wxEVT_UPDATE_UI, [enable_fn](wxUpdateUIEvent& evt) { evt.Enable(enable_fn()); }); buttons->Insert(pos, btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W); this->Bind(wxEVT_BUTTON, method, this, ID); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 49876674a7..e425016cd6 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -50,7 +50,8 @@ KBShortcutsDialog::KBShortcutsDialog() } wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK); - wxGetApp().UpdateDarkUI(static_cast(this->FindWindowById(wxID_OK, this))); + wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + wxGetApp().UpdateDarkUI(buttons->GetAffirmativeButton()); this->SetEscapeId(wxID_OK); main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 5); diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index b8c4151ad0..0b8d609b94 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -85,6 +85,7 @@ void MsgDialog::SetButtonLabel(wxWindowID btn_id, const wxString& label, bool se wxButton* MsgDialog::add_button(wxWindowID btn_id, bool set_focus /*= false*/, const wxString& label/* = wxString()*/) { wxButton* btn = new wxButton(this, btn_id, label); + wxGetApp().SetWindowVariantForButton(btn); if (set_focus) { btn->SetFocus(); // For non-MSW platforms SetFocus is not enought to use it as default, when the dialog is closed by ENTER diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 12368e3484..a3971cd51c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -511,7 +511,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : auto wiping_dialog_btn = [this](wxWindow* parent) { m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _L("Purging volumes") + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - m_wiping_dialog_button->SetFont(wxGetApp().normal_font()); + wxGetApp().SetWindowVariantForButton(m_wiping_dialog_button); wxGetApp().UpdateDarkUI(m_wiping_dialog_button, true); auto sizer = new wxBoxSizer(wxHORIZONTAL); @@ -939,6 +939,7 @@ Sidebar::Sidebar(Plater *parent) #endif //__APPLE__ ScalableBitmap bmp = ScalableBitmap(this, icon_name, bmp_px_cnt); *btn = new ScalableButton(this, wxID_ANY, bmp, "", wxBU_EXACTFIT); + wxGetApp().SetWindowVariantForButton((*btn)); #ifdef _WIN32 (*btn)->Bind(wxEVT_ENTER_WINDOW, [tooltip, btn, this](wxMouseEvent& event) { @@ -970,6 +971,7 @@ Sidebar::Sidebar(Plater *parent) auto init_btn = [this](wxButton **btn, wxString label, const int button_height) { *btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition, wxSize(-1, button_height), wxBU_EXACTFIT); + wxGetApp().SetWindowVariantForButton((*btn)); (*btn)->SetFont(wxGetApp().bold_font()); wxGetApp().UpdateDarkUI((*btn), true); }; @@ -979,7 +981,7 @@ Sidebar::Sidebar(Plater *parent) enable_buttons(false); - auto *btns_sizer = new wxBoxSizer(wxVERTICAL); + auto *btns_sizer = new wxBoxSizer(wxHORIZONTAL); auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); @@ -988,8 +990,8 @@ Sidebar::Sidebar(Plater *parent) // complect_btns_sizer->Add(p->btn_eject_device); - btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); - btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5); + btns_sizer->Add(p->btn_reslice, 1, wxEXPAND | wxTOP | wxBOTTOM, margin_5); + btns_sizer->Add(complect_btns_sizer, 1, wxEXPAND | wxTOP | wxBOTTOM, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(p->scrolled, 1, wxEXPAND); @@ -5301,7 +5303,7 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab // Plater / Public Plater::Plater(wxWindow *parent, MainFrame *main_frame) - : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxGetApp().get_min_size()) + : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxGetApp().get_min_size(parent)) , p(new priv(this, main_frame)) { // Initialization performed in the private c-tor diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 07322b849e..f63b5e8ca5 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -687,6 +687,8 @@ void PreferencesDialog::build() sizer->Add(tabs, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); + wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); this->Bind(wxEVT_BUTTON, &PreferencesDialog::accept, this, wxID_OK); this->Bind(wxEVT_BUTTON, &PreferencesDialog::revert, this, wxID_CANCEL); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index 603bfe9870..ff768d94e8 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -182,7 +182,9 @@ SysInfoDialog::SysInfoDialog() } wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK); + wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); m_btn_copy_to_clipboard = new wxButton(this, wxID_ANY, _L("Copy to Clipboard"), wxDefaultPosition, wxDefaultSize); + wxGetApp().SetWindowVariantForButton(m_btn_copy_to_clipboard); buttons->Insert(0, m_btn_copy_to_clipboard, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5); m_btn_copy_to_clipboard->Bind(wxEVT_BUTTON, &SysInfoDialog::onCopyToClipboard, this); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 46eaf3ed9d..24e5798356 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2249,6 +2249,7 @@ void TabFilament::build() create_line_with_widget(optgroup.get(), "filament_ramming_parameters", "", [this](wxWindow* parent) { auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + wxGetApp().SetWindowVariantForButton(ramming_dialog_btn); wxGetApp().UpdateDarkUI(ramming_dialog_btn); ramming_dialog_btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); ramming_dialog_btn->SetSize(ramming_dialog_btn->GetBestSize()); diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 6671b68d8a..51d77d7c9c 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -42,7 +42,10 @@ RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) auto main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); - main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10); + auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); + Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10); SetSizer(main_sizer); main_sizer->SetSizeHints(this); @@ -181,6 +184,7 @@ WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, c update_ui(this); auto widget_button = new wxButton(this,wxID_ANY,"-",wxPoint(0,0),wxDefaultSize); update_ui(widget_button); + Slic3r::GUI::wxGetApp().SetWindowVariantForButton(widget_button); m_panel_wiping = new WipingPanel(this,matrix,extruders, extruder_colours, widget_button); auto main_sizer = new wxBoxSizer(wxVERTICAL); @@ -191,7 +195,10 @@ WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, c main_sizer->Add(m_panel_wiping, 0, wxEXPAND | wxALL, 5); main_sizer->Add(widget_button, 0, wxALIGN_CENTER_HORIZONTAL | wxCENTER | wxBOTTOM, 5); - main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); + auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); + Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); SetSizer(main_sizer); main_sizer->SetSizeHints(this); From fea655f668bd95185e6e3afe97c674ba59b2eccc Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 17 Oct 2023 14:17:12 +0200 Subject: [PATCH 10/11] Set max font size in respect to the display size. + non-MSW specific: Suppress colored border for focused control. + Fixed layout of the PointCtrl + WipeTowerDialog: use SpinInput control instead of wxSpinCtrl --- src/slic3r/GUI/Field.cpp | 9 ++++---- src/slic3r/GUI/Preferences.cpp | 13 ++++++++++- src/slic3r/GUI/Widgets/StaticBox.cpp | 6 +++++ src/slic3r/GUI/WipeTowerDialog.cpp | 34 +++++++++++++++------------- src/slic3r/GUI/WipeTowerDialog.hpp | 11 +++++---- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 9a8c0287c3..bf3aab1861 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1528,8 +1528,9 @@ void PointCtrl::BUILD() y_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); if (!wxOSX) y_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); - auto static_text_x = new wxStaticText(m_parent, wxID_ANY, "x : "); - auto static_text_y = new wxStaticText(m_parent, wxID_ANY, " y : "); + wxSize label_sz = wxSize(int(field_size.x / 2), field_size.y); + auto static_text_x = new wxStaticText(m_parent, wxID_ANY, "x : ", wxDefaultPosition, label_sz, wxALIGN_RIGHT); + auto static_text_y = new wxStaticText(m_parent, wxID_ANY, "y : ", wxDefaultPosition, label_sz, wxALIGN_RIGHT); static_text_x->SetFont(Slic3r::GUI::wxGetApp().normal_font()); static_text_x->SetBackgroundStyle(wxBG_STYLE_PAINT); static_text_y->SetFont(Slic3r::GUI::wxGetApp().normal_font()); @@ -1540,9 +1541,9 @@ void PointCtrl::BUILD() wxGetApp().UpdateDarkUI(static_text_x, false, true); wxGetApp().UpdateDarkUI(static_text_y, false, true); - temp->Add(static_text_x, 0, wxALIGN_CENTER_VERTICAL, 0); + temp->Add(static_text_x); temp->Add(x_textctrl); - temp->Add(static_text_y, 0, wxALIGN_CENTER_VERTICAL, 0); + temp->Add(static_text_y); temp->Add(y_textctrl); x_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(x_textctrl); }), x_textctrl->GetId()); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index f63b5e8ca5..e1fa4b07f6 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1094,6 +1094,17 @@ void PreferencesDialog::create_settings_mode_color_widget() append_preferences_option_to_searcher(m_optgroup_gui, opt_key, title); } +static int get_max_font_pt_size() +{ + const unsigned disp_count = wxDisplay::GetCount(); + for (int i = 0; i < disp_count; i++) { + const wxRect display_rect = wxDisplay(i).GetGeometry(); + if (display_rect.width >= 2560 && display_rect.height >= 1440) + return 20; + } + return 15; +} + void PreferencesDialog::create_settings_font_widget() { wxWindow* parent = m_optgroup_other->parent(); @@ -1114,7 +1125,7 @@ void PreferencesDialog::create_settings_font_widget() #ifdef _WIN32 | wxBORDER_SIMPLE #endif - , 8, 20); + , 8, get_max_font_pt_size()); wxGetApp().UpdateDarkUI(size_sc); auto apply_font = [this, font_example, opt_key, stb_sizer](const int val, const wxFont& font) { diff --git a/src/slic3r/GUI/Widgets/StaticBox.cpp b/src/slic3r/GUI/Widgets/StaticBox.cpp index 29d5ff69e3..f2dd175f39 100644 --- a/src/slic3r/GUI/Widgets/StaticBox.cpp +++ b/src/slic3r/GUI/Widgets/StaticBox.cpp @@ -23,8 +23,14 @@ StaticBox::StaticBox() , radius(8) { border_color = StateColor(std::make_pair(clr_border_disabled, (int) StateColor::Disabled), +#ifndef __WXMSW__ + std::make_pair(clr_border_nornal, (int) StateColor::Focused), +#endif std::make_pair(clr_border_hovered, (int) StateColor::Hovered), std::make_pair(clr_border_nornal, (int) StateColor::Normal)); +#ifndef __WXMSW__ + border_color.setTakeFocusedAsHovered(false); +#endif } StaticBox::StaticBox(wxWindow* parent, diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 51d77d7c9c..061245d52d 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -15,17 +15,20 @@ #include -int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit(); } +using namespace Slic3r::GUI; + +int scale(const int val) { return val * wxGetApp().em_unit(); } int ITEM_WIDTH() { return scale(6); } static void update_ui(wxWindow* window) { - Slic3r::GUI::wxGetApp().UpdateDarkUI(window); + wxGetApp().UpdateDarkUI(window); } RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) : wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) { + SetFont(wxGetApp().normal_font()); update_ui(this); m_panel_ramming = new RammingPanel(this,parameters); @@ -43,8 +46,8 @@ RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) auto main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); - Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); - Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10); SetSizer(main_sizer); main_sizer->SetSizeHints(this); @@ -59,8 +62,7 @@ RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) EndModal(wxID_OK); },wxID_OK); this->Show(); -// wxMessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " - Slic3r::GUI::MessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " + MessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " "properly shape the end of the unloaded filament so it does not prevent insertion of the new filament and can itself " "be reinserted later. This phase is important and different materials can require different extrusion speeds to get " "the good shape. For this reason, the extrusion rates during ramming are adjustable.\n\nThis is an expert-level " @@ -108,9 +110,9 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) sizer_chart->Add(m_chart, 0, wxALL, 5); m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0.,5.0,3.,0.5); - m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0,10000,0); - m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); - m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); + m_widget_volume = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0,10000,0); + m_widget_ramming_line_width_multiplicator = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); + m_widget_ramming_step_multiplicator = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); #ifdef _WIN32 update_ui(m_widget_time->GetText()); @@ -181,10 +183,11 @@ std::string RammingPanel::get_parameters() WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours) : wxDialog(parent, wxID_ANY, _(L("Wipe tower - Purging volume adjustment")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) { + SetFont(wxGetApp().normal_font()); update_ui(this); auto widget_button = new wxButton(this,wxID_ANY,"-",wxPoint(0,0),wxDefaultSize); update_ui(widget_button); - Slic3r::GUI::wxGetApp().SetWindowVariantForButton(widget_button); + wxGetApp().SetWindowVariantForButton(widget_button); m_panel_wiping = new WipingPanel(this,matrix,extruders, extruder_colours, widget_button); auto main_sizer = new wxBoxSizer(wxVERTICAL); @@ -196,8 +199,8 @@ WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, c main_sizer->Add(m_panel_wiping, 0, wxEXPAND | wxALL, 5); main_sizer->Add(widget_button, 0, wxALIGN_CENTER_HORIZONTAL | wxCENTER | wxBOTTOM, 5); auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); - Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); - Slic3r::GUI::wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); + wxGetApp().SetWindowVariantForButton(buttons->GetAffirmativeButton()); + wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton()); main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); SetSizer(main_sizer); main_sizer->SetSizeHints(this); @@ -321,9 +324,9 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("unloaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); gridsizer_simple->Add(new wxStaticText(m_page_simple,wxID_ANY,wxString(_(L("loaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); - auto add_spin_ctrl = [this](std::vector& vec, float initial) + auto add_spin_ctrl = [this](std::vector<::SpinInput*>& vec, float initial) { - wxSpinCtrl* spin_ctrl = new wxSpinCtrl(m_page_simple, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1), style | wxALIGN_RIGHT, 0, 300, (int)initial); + ::SpinInput* spin_ctrl = new ::SpinInput(m_page_simple, "", wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1), style | wxALIGN_RIGHT, 0, 300, (int)initial); update_ui(spin_ctrl); vec.push_back(spin_ctrl); @@ -451,8 +454,7 @@ bool WipingPanel::advanced_matches_simple() { // Switches the dialog from simple to advanced mode and vice versa void WipingPanel::toggle_advanced(bool user_action) { if (m_advanced && !advanced_matches_simple() && user_action) { -// if (wxMessageDialog(this,wxString(_(L("Switching to simple settings will discard changes done in the advanced mode!\n\nDo you want to proceed?"))), - if (Slic3r::GUI::MessageDialog(this, _L("Switching to simple settings will discard changes done in the advanced mode!\n\nDo you want to proceed?"), + if (MessageDialog(this, _L("Switching to simple settings will discard changes done in the advanced mode!\n\nDo you want to proceed?"), _L("Warning"),wxYES_NO|wxICON_EXCLAMATION).ShowModal() != wxID_YES) return; } diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index 7181a4fdf1..f64d1363a5 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -12,6 +12,7 @@ #include #include "RammingChart.hpp" +#include "Widgets/SpinInput.hpp" class RammingPanel : public wxPanel { @@ -22,9 +23,9 @@ public: private: Chart* m_chart = nullptr; - wxSpinCtrl* m_widget_volume = nullptr; - wxSpinCtrl* m_widget_ramming_line_width_multiplicator = nullptr; - wxSpinCtrl* m_widget_ramming_step_multiplicator = nullptr; + ::SpinInput* m_widget_volume = nullptr; + ::SpinInput* m_widget_ramming_line_width_multiplicator = nullptr; + ::SpinInput* m_widget_ramming_step_multiplicator = nullptr; wxSpinCtrlDouble* m_widget_time = nullptr; int m_ramming_step_multiplicator; int m_ramming_line_width_multiplicator; @@ -60,8 +61,8 @@ private: void fill_in_matrix(); bool advanced_matches_simple(); - std::vector m_old; - std::vector m_new; + std::vector<::SpinInput*> m_old; + std::vector<::SpinInput*> m_new; std::vector> edit_boxes; std::vector m_colours; unsigned int m_number_of_extruders = 0; From 8d1165d6ed9a5be6767b3e8297ac99e5ec78bafd Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 18 Oct 2023 14:03:37 +0200 Subject: [PATCH 11/11] SpinInputDouble + Update font size for application in respect to the display size --- src/slic3r/GUI/ConfigWizard.cpp | 7 +- src/slic3r/GUI/ConfigWizard_private.hpp | 5 +- src/slic3r/GUI/GUI_App.cpp | 25 +- src/slic3r/GUI/GUI_App.hpp | 1 + src/slic3r/GUI/Preferences.cpp | 13 +- src/slic3r/GUI/Widgets/SpinInput.cpp | 697 ++++++++++++++++-------- src/slic3r/GUI/Widgets/SpinInput.hpp | 196 +++++-- src/slic3r/GUI/WipeTowerDialog.cpp | 7 +- src/slic3r/GUI/WipeTowerDialog.hpp | 2 +- 9 files changed, 626 insertions(+), 327 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 7c9c696efa..5c6811932e 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1981,7 +1981,7 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) set_extrusion_width("solid_infill_extrusion_width", 0.45); } -class SpinCtrlDouble: public wxSpinCtrlDouble +class SpinCtrlDouble: public ::SpinInputDouble { public: SpinCtrlDouble(wxWindow* parent) @@ -1991,10 +1991,7 @@ public: #else long style = wxSP_ARROW_KEYS; #endif - Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, style); -#ifdef _WIN32 - wxGetApp().UpdateDarkUI(this->GetText()); -#endif + Create(parent, "", wxEmptyString, wxDefaultPosition, wxSize(6* wxGetApp().em_unit(), -1), style); this->Refresh(); } ~SpinCtrlDouble() {} diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index ce43fd5e71..3bbc9649d9 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -32,6 +32,7 @@ #include "SavePresetDialog.hpp" #include "wxExtensions.hpp" +#include "Widgets/SpinInput.hpp" namespace fs = boost::filesystem; @@ -510,8 +511,8 @@ struct PageDiameters: ConfigWizardPage struct PageTemperatures: ConfigWizardPage { - wxSpinCtrlDouble *spin_extr; - wxSpinCtrlDouble *spin_bed; + ::SpinInputDouble *spin_extr; + ::SpinInputDouble *spin_bed; PageTemperatures(ConfigWizard *parent); virtual void apply_custom_config(DynamicPrintConfig &config); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 7c69131c80..a27a4c8682 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1093,6 +1093,16 @@ bool GUI_App::OnInit() } } +static int get_app_font_pt_size(const AppConfig* app_config) +{ + if (!app_config->has("font_pt_size")) + return -1; + const int font_pt_size = atoi(app_config->get("font_pt_size").c_str()); + const int max_font_pt_size = wxGetApp().get_max_font_pt_size(); + + return (font_pt_size > max_font_pt_size) ? max_font_pt_size : font_pt_size; +} + bool GUI_App::on_init_inner() { // Set initialization of image handlers before any UI actions - See GH issue #7469 @@ -1326,7 +1336,7 @@ bool GUI_App::on_init_inner() if (!delayed_error_load_presets.empty()) show_error(nullptr, delayed_error_load_presets); - mainframe = new MainFrame(app_config->has("font_pt_size") ? atoi(app_config->get("font_pt_size").c_str()) : -1); + mainframe = new MainFrame(get_app_font_pt_size(app_config)); // hide settings tabs after first Layout if (is_editor()) mainframe->select_tab(size_t(0)); @@ -1662,6 +1672,17 @@ void GUI_App::SetWindowVariantForButton(wxButton* btn) #endif } +int GUI_App::get_max_font_pt_size() +{ + const unsigned disp_count = wxDisplay::GetCount(); + for (int i = 0; i < disp_count; i++) { + const wxRect display_rect = wxDisplay(i).GetGeometry(); + if (display_rect.width >= 2560 && display_rect.height >= 1440) + return 20; + } + return 15; +} + void GUI_App::init_fonts() { m_small_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); @@ -1863,7 +1884,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name) dlg.Update(10, _L("Recreating") + dots); MainFrame *old_main_frame = mainframe; - mainframe = new MainFrame(app_config->has("font_pt_size") ? atoi(app_config->get("font_pt_size").c_str()) : -1); + mainframe = new MainFrame(get_app_font_pt_size(app_config)); if (is_editor()) // hide settings tabs after first Layout mainframe->select_tab(size_t(0)); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 66c259b813..059804edf3 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -251,6 +251,7 @@ public: bool tabs_as_menu() const; bool suppress_round_corners() const; wxSize get_min_size(wxWindow* display_win) const; + int get_max_font_pt_size(); float toolbar_icon_scale(const bool is_limited = false) const; void set_auto_toolbar_icon_scale(float scale) const; void check_printer_presets(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index e1fa4b07f6..f3651be9b2 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1094,17 +1094,6 @@ void PreferencesDialog::create_settings_mode_color_widget() append_preferences_option_to_searcher(m_optgroup_gui, opt_key, title); } -static int get_max_font_pt_size() -{ - const unsigned disp_count = wxDisplay::GetCount(); - for (int i = 0; i < disp_count; i++) { - const wxRect display_rect = wxDisplay(i).GetGeometry(); - if (display_rect.width >= 2560 && display_rect.height >= 1440) - return 20; - } - return 15; -} - void PreferencesDialog::create_settings_font_widget() { wxWindow* parent = m_optgroup_other->parent(); @@ -1125,7 +1114,7 @@ void PreferencesDialog::create_settings_font_widget() #ifdef _WIN32 | wxBORDER_SIMPLE #endif - , 8, get_max_font_pt_size()); + , 8, wxGetApp().get_max_font_pt_size()); wxGetApp().UpdateDarkUI(size_sc); auto apply_font = [this, font_example, opt_key, stb_sizer](const int val, const wxFont& font) { diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index 6634638784..c693a52843 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -10,22 +10,23 @@ #include #include -BEGIN_EVENT_TABLE(SpinInput, wxPanel) +BEGIN_EVENT_TABLE(SpinInputBase, wxPanel) -EVT_KEY_DOWN(SpinInput::keyPressed) -EVT_MOUSEWHEEL(SpinInput::mouseWheelMoved) +EVT_KEY_DOWN(SpinInputBase::keyPressed) +EVT_MOUSEWHEEL(SpinInputBase::mouseWheelMoved) -EVT_PAINT(SpinInput::paintEvent) +EVT_PAINT(SpinInputBase::paintEvent) END_EVENT_TABLE() + /* * Called by the system of by wxWidgets when the panel needs * to be redrawn. You can also trigger this call by * calling Refresh()/Update(). */ -SpinInput::SpinInput() +SpinInputBase::SpinInputBase() : label_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x6B6B6B, (int) StateColor::Normal)) , text_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x262E30, (int) StateColor::Normal)) { @@ -34,6 +35,230 @@ SpinInput::SpinInput() border_width = 1; } +Button * SpinInputBase::create_button(ButtonId id) +{ + auto btn = new Button(this, "", id == ButtonId::btnIncrease ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); + btn->SetCornerRadius(0); + btn->SetInactiveIcon(id == ButtonId::btnIncrease ? "spin_inc" : "spin_dec"); + btn->DisableFocusFromKeyboard(); + btn->SetSelected(false); + + bind_inc_dec_button(btn, id); + + return btn; +} + +void SpinInputBase::SetCornerRadius(double radius) +{ + this->radius = radius; + Refresh(); +} + +void SpinInputBase::SetLabel(const wxString &label) +{ + wxWindow::SetLabel(label); + messureSize(); + Refresh(); +} + +void SpinInputBase::SetLabelColor(StateColor const &color) +{ + label_color = color; + state_handler.update_binds(); +} + +void SpinInputBase::SetTextColor(StateColor const &color) +{ + text_color = color; + state_handler.update_binds(); +} + +void SpinInputBase::SetSize(wxSize const &size) +{ + wxWindow::SetSize(size); + Rescale(); +} + +wxString SpinInputBase::GetTextValue() const +{ + return text_ctrl->GetValue(); +} + +void SpinInput::SetRange(int min, int max) +{ + this->min = min; + this->max = max; +} + +void SpinInputBase::SetSelection(long from, long to) +{ + if (text_ctrl) + text_ctrl->SetSelection(from, to); +} + +bool SpinInputBase::SetFont(wxFont const& font) +{ + if (text_ctrl) + return text_ctrl->SetFont(font); + return StaticBox::SetFont(font); +} + +bool SpinInputBase::SetBackgroundColour(const wxColour& colour) +{ + const int clr_background_disabled = Slic3r::GUI::wxGetApp().dark_mode() ? clr_background_disabled_dark : clr_background_disabled_light; + StateColor clr_state(std::make_pair(clr_background_disabled, (int)StateColor::Disabled), + std::make_pair(clr_background_focused, (int)StateColor::Checked), + std::make_pair(colour, (int)StateColor::Focused), + std::make_pair(colour, (int)StateColor::Normal)); + + StaticBox::SetBackgroundColor(clr_state); + if (text_ctrl) + text_ctrl->SetBackgroundColour(colour); + if (button_inc) + button_inc->SetBackgroundColor(clr_state); + if (button_dec) + button_dec->SetBackgroundColor(clr_state); + + return true; +} + +bool SpinInputBase::SetForegroundColour(const wxColour& colour) +{ + StateColor clr_state(std::make_pair(clr_foreground_disabled, (int)StateColor::Disabled), + std::make_pair(colour, (int)StateColor::Normal)); + + SetLabelColor(clr_state); + SetTextColor(clr_state); + + if (text_ctrl) + text_ctrl->SetForegroundColour(colour); + if (button_inc) + button_inc->SetTextColor(clr_state); + if (button_dec) + button_dec->SetTextColor(clr_state); + + return true; +} + +void SpinInputBase::SetBorderColor(StateColor const &color) +{ + StaticBox::SetBorderColor(color); + if (button_inc) + button_inc->SetBorderColor(color); + if (button_dec) + button_dec->SetBorderColor(color); +} + +void SpinInputBase::DoSetToolTipText(wxString const &tip) +{ + wxWindow::DoSetToolTipText(tip); + text_ctrl->SetToolTip(tip); +} + +void SpinInputBase::Rescale() +{ + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + + button_inc->Rescale(); + button_dec->Rescale(); + messureSize(); +} + +bool SpinInputBase::Enable(bool enable) +{ + bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); + if (result) { + wxCommandEvent e(EVT_ENABLE_CHANGED); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + button_inc->Enable(enable); + button_dec->Enable(enable); + } + return result; +} + +void SpinInputBase::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void SpinInputBase::render(wxDC& dc) +{ + StaticBox::render(dc); + int states = state_handler.states(); + wxSize size = GetSize(); + // draw seperator of buttons + wxPoint pt = button_inc->GetPosition(); + pt.y = size.y / 2; + dc.SetPen(wxPen(border_color.defaultColor())); + + const double scale = dc.GetContentScaleFactor(); + const int btn_w = button_inc->GetSize().GetWidth(); + dc.DrawLine(pt, pt + wxSize{ btn_w - int(scale), 0}); + // draw label + auto label = GetLabel(); + if (!label.IsEmpty()) { + pt.x = size.x - labelSize.x - 5; + pt.y = (size.y - labelSize.y) / 2; + dc.SetFont(GetFont()); + dc.SetTextForeground(label_color.colorForStates(states)); + dc.DrawText(label, pt); + } +} + +void SpinInputBase::messureSize() +{ + wxSize size = GetSize(); + wxSize textSize = text_ctrl->GetSize(); + int h = textSize.y + 8; + if (size.y != h) { + size.y = h; + SetSize(size); + SetMinSize(size); + } + + wxSize btnSize = {14, (size.y - 4) / 2}; + btnSize.x = btnSize.x * btnSize.y / 10; + + const double scale = this->GetContentScaleFactor(); + + wxClientDC dc(this); + labelSize = dc.GetMultiLineTextExtent(GetLabel()); + textSize.x = size.x - labelSize.x - btnSize.x - 16; + text_ctrl->SetSize(textSize); + text_ctrl->SetPosition({int(3. * scale), (size.y - textSize.y) / 2}); + button_inc->SetSize(btnSize); + button_dec->SetSize(btnSize); + button_inc->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 - btnSize.y/* - 1*/}); + button_dec->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 + 1}); +} + +void SpinInputBase::onText(wxCommandEvent &event) +{ + sendSpinEvent(); + event.SetId(GetId()); + ProcessEventLocally(event); +} + +void SpinInputBase::sendSpinEvent() +{ + wxCommandEvent event(wxEVT_SPINCTRL, GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + + +// SpinInput SpinInput::SpinInput(wxWindow *parent, wxString text, @@ -42,7 +267,7 @@ SpinInput::SpinInput(wxWindow *parent, const wxSize & size, long style, int min, int max, int initial) - : SpinInput() + : SpinInputBase() { Create(parent, text, label, pos, size, style, min, max, initial); } @@ -91,35 +316,29 @@ void SpinInput::Create(wxWindow *parent, messureSize(); } -void SpinInput::SetCornerRadius(double radius) +void SpinInput::bind_inc_dec_button(Button *btn, ButtonId id) { - this->radius = radius; - Refresh(); -} - -void SpinInput::SetLabel(const wxString &label) -{ - wxWindow::SetLabel(label); - messureSize(); - Refresh(); -} - -void SpinInput::SetLabelColor(StateColor const &color) -{ - label_color = color; - state_handler.update_binds(); -} - -void SpinInput::SetTextColor(StateColor const &color) -{ - text_color = color; - state_handler.update_binds(); -} - -void SpinInput::SetSize(wxSize const &size) -{ - wxWindow::SetSize(size); - Rescale(); + btn->Bind(wxEVT_LEFT_DOWN, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? 1 : -1; + SetValue(val + delta); + text_ctrl->SetFocus(); + btn->CaptureMouse(); + delta *= 8; + timer.Start(100); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_DCLICK, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? 1 : -1; + btn->CaptureMouse(); + SetValue(val + delta); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_UP, [this, btn](auto& e) { + btn->ReleaseMouse(); + timer.Stop(); + text_ctrl->SelectAll(); + delta = 0; + }); } void SpinInput::SetValue(const wxString &text) @@ -144,202 +363,6 @@ int SpinInput::GetValue()const return val; } -wxString SpinInput::GetTextValue() const -{ - return text_ctrl->GetValue(); -} - -void SpinInput::SetRange(int min, int max) -{ - this->min = min; - this->max = max; -} - -void SpinInput::SetSelection(long from, long to) -{ - if (text_ctrl) - text_ctrl->SetSelection(from, to); -} - -bool SpinInput::SetFont(wxFont const& font) -{ - if (text_ctrl) - return text_ctrl->SetFont(font); - return StaticBox::SetFont(font); -} - -bool SpinInput::SetBackgroundColour(const wxColour& colour) -{ - const int clr_background_disabled = Slic3r::GUI::wxGetApp().dark_mode() ? clr_background_disabled_dark : clr_background_disabled_light; - StateColor clr_state(std::make_pair(clr_background_disabled, (int)StateColor::Disabled), - std::make_pair(clr_background_focused, (int)StateColor::Checked), - std::make_pair(colour, (int)StateColor::Focused), - std::make_pair(colour, (int)StateColor::Normal)); - - StaticBox::SetBackgroundColor(clr_state); - if (text_ctrl) - text_ctrl->SetBackgroundColour(colour); - if (button_inc) - button_inc->SetBackgroundColor(clr_state); - if (button_dec) - button_dec->SetBackgroundColor(clr_state); - - return true; -} - -bool SpinInput::SetForegroundColour(const wxColour& colour) -{ - StateColor clr_state(std::make_pair(clr_foreground_disabled, (int)StateColor::Disabled), - std::make_pair(colour, (int)StateColor::Normal)); - - SetLabelColor(clr_state); - SetTextColor(clr_state); - - if (text_ctrl) - text_ctrl->SetForegroundColour(colour); - if (button_inc) - button_inc->SetTextColor(clr_state); - if (button_dec) - button_dec->SetTextColor(clr_state); - - return true; -} - -void SpinInput::SetBorderColor(StateColor const &color) -{ - StaticBox::SetBorderColor(color); - if (button_inc) - button_inc->SetBorderColor(color); - if (button_dec) - button_dec->SetBorderColor(color); -} - -void SpinInput::DoSetToolTipText(wxString const &tip) -{ - wxWindow::DoSetToolTipText(tip); - text_ctrl->SetToolTip(tip); -} - -void SpinInput::Rescale() -{ - SetFont(Slic3r::GUI::wxGetApp().normal_font()); - text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); - - button_inc->Rescale(); - button_dec->Rescale(); - messureSize(); -} - -bool SpinInput::Enable(bool enable) -{ - bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); - if (result) { - wxCommandEvent e(EVT_ENABLE_CHANGED); - e.SetEventObject(this); - GetEventHandler()->ProcessEvent(e); - text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); - text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); - button_inc->Enable(enable); - button_dec->Enable(enable); - } - return result; -} - -void SpinInput::paintEvent(wxPaintEvent& evt) -{ - // depending on your system you may need to look at double-buffered dcs - wxPaintDC dc(this); - render(dc); -} - -/* - * Here we do the actual rendering. I put it in a separate - * method so that it can work no matter what type of DC - * (e.g. wxPaintDC or wxClientDC) is used. - */ -void SpinInput::render(wxDC& dc) -{ - StaticBox::render(dc); - int states = state_handler.states(); - wxSize size = GetSize(); - // draw seperator of buttons - wxPoint pt = button_inc->GetPosition(); - pt.y = size.y / 2; - dc.SetPen(wxPen(border_color.defaultColor())); - - const double scale = dc.GetContentScaleFactor(); - const int btn_w = button_inc->GetSize().GetWidth(); - dc.DrawLine(pt, pt + wxSize{ btn_w - int(scale), 0}); - // draw label - auto label = GetLabel(); - if (!label.IsEmpty()) { - pt.x = size.x - labelSize.x - 5; - pt.y = (size.y - labelSize.y) / 2; - dc.SetFont(GetFont()); - dc.SetTextForeground(label_color.colorForStates(states)); - dc.DrawText(label, pt); - } -} - -void SpinInput::messureSize() -{ - wxSize size = GetSize(); - wxSize textSize = text_ctrl->GetSize(); - int h = textSize.y + 8; - if (size.y != h) { - size.y = h; - SetSize(size); - SetMinSize(size); - } - - wxSize btnSize = {14, (size.y - 4) / 2}; - btnSize.x = btnSize.x * btnSize.y / 10; - - const double scale = this->GetContentScaleFactor(); - - wxClientDC dc(this); - labelSize = dc.GetMultiLineTextExtent(GetLabel()); - textSize.x = size.x - labelSize.x - btnSize.x - 16; - text_ctrl->SetSize(textSize); - text_ctrl->SetPosition({int(3. * scale), (size.y - textSize.y) / 2}); - button_inc->SetSize(btnSize); - button_dec->SetSize(btnSize); - button_inc->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 - btnSize.y/* - 1*/}); - button_dec->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 + 1}); -} - -Button *SpinInput::create_button(ButtonId id) -{ - auto btn = new Button(this, "", id == ButtonId::btnIncrease ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); - btn->SetCornerRadius(0); - btn->SetInactiveIcon(id == ButtonId::btnIncrease ? "spin_inc" : "spin_dec"); - btn->DisableFocusFromKeyboard(); - btn->SetSelected(false); - - btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) { - delta = id == ButtonId::btnIncrease ? 1 : -1; - SetValue(val + delta); - text_ctrl->SetFocus(); - btn->CaptureMouse(); - delta *= 8; - timer.Start(100); - sendSpinEvent(); - }); - btn->Bind(wxEVT_LEFT_DCLICK, [=](auto &e) { - delta = id == ButtonId::btnIncrease ? 1 : -1; - btn->CaptureMouse(); - SetValue(val + delta); - sendSpinEvent(); - }); - btn->Bind(wxEVT_LEFT_UP, [=](auto &e) { - btn->ReleaseMouse(); - timer.Stop(); - text_ctrl->SelectAll(); - delta = 0; - }); - return btn; -} - void SpinInput::onTimer(wxTimerEvent &evnet) { if (delta < -1 || delta > 1) { delta /= 2; @@ -367,7 +390,9 @@ void SpinInput::onTextLostFocus(wxEvent &event) void SpinInput::onTextEnter(wxCommandEvent &event) { long value; - if (!text_ctrl->GetValue().ToLong(&value)) { value = val; } + if (!text_ctrl->GetValue().ToLong(&value)) + value = val; + if (value != val) { SetValue(value); sendSpinEvent(); @@ -376,13 +401,6 @@ void SpinInput::onTextEnter(wxCommandEvent &event) ProcessEventLocally(event); } -void SpinInput::onText(wxCommandEvent &event) -{ - sendSpinEvent(); - event.SetId(GetId()); - ProcessEventLocally(event); -} - void SpinInput::mouseWheelMoved(wxMouseEvent &event) { auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? 1 : -1; @@ -412,9 +430,204 @@ void SpinInput::keyPressed(wxKeyEvent &event) } } -void SpinInput::sendSpinEvent() + + +// SpinInputDouble + +SpinInputDouble::SpinInputDouble(wxWindow * parent, + wxString text, + wxString label, + const wxPoint &pos, + const wxSize & size, + long style, + double min, double max, double initial, + double inc) + : SpinInputBase() { - wxCommandEvent event(wxEVT_SPINCTRL, GetId()); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + Create(parent, text, label, pos, size, style, min, max, initial, inc); } + +void SpinInputDouble::Create(wxWindow *parent, + wxString text, + wxString label, + const wxPoint &pos, + const wxSize & size, + long style, + double min, double max, double initial, + double inc) +{ + StaticBox::Create(parent, wxID_ANY, pos, size); + wxWindow::SetLabel(label); + + state_handler.attach({&label_color, &text_color}); + state_handler.update_binds(); + + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS)); +#ifdef __WXOSX__ + text_ctrl->OSXDisableAllSmartSubstitutions(); +#endif // __WXOSX__ + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + state_handler.attach_child(text_ctrl); + + text_ctrl->Bind(wxEVT_KILL_FOCUS, &SpinInputDouble::onTextLostFocus, this); + text_ctrl->Bind(wxEVT_TEXT, &SpinInputDouble::onText, this); + text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInputDouble::onTextEnter, this); + text_ctrl->Bind(wxEVT_KEY_DOWN, &SpinInputDouble::keyPressed, this); + text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu + button_inc = create_button(ButtonId::btnIncrease); + button_dec = create_button(ButtonId::btnDecrease); + delta = 0; + timer.Bind(wxEVT_TIMER, &SpinInputDouble::onTimer, this); + + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + if (parent) { + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); + } + + double initialFromText; + if (text.ToDouble(&initialFromText)) initial = initialFromText; + SetRange(min, max); + SetIncrement(inc); + SetValue(initial); + messureSize(); +} + +void SpinInputDouble::bind_inc_dec_button(Button *btn, ButtonId id) +{ + btn->Bind(wxEVT_LEFT_DOWN, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? inc : -inc; + SetValue(val + delta); + text_ctrl->SetFocus(); + btn->CaptureMouse(); + delta *= 8; + timer.Start(100); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_DCLICK, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? inc : -inc; + btn->CaptureMouse(); + SetValue(val + delta); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_UP, [this, btn](auto& e) { + btn->ReleaseMouse(); + timer.Stop(); + text_ctrl->SelectAll(); + delta = 0; + }); +} + +void SpinInputDouble::SetValue(const wxString &text) +{ + double value; + if ( text.ToDouble(&value) ) + SetValue(value); + else + text_ctrl->SetValue(text); +} + +void SpinInputDouble::SetValue(double value) +{ + if (Slic3r::is_approx(value, val)) + return; + + if (value < min) value = min; + else if (value > max) value = max; + this->val = value; + wxString str_val = wxString::FromDouble(value, digits); + text_ctrl->SetValue(str_val); +} + +double SpinInputDouble::GetValue()const +{ + return val; +} + +void SpinInputDouble::SetRange(double min, double max) +{ + this->min = min; + this->max = max; +} + +void SpinInputDouble::SetIncrement(double inc_in) +{ + inc = inc_in; +} + +void SpinInputDouble::SetDigits(unsigned digits_in) +{ + digits = int(digits_in); +} + +void SpinInputDouble::onTimer(wxTimerEvent &evnet) { + if (delta < -inc || delta > inc) { + delta /= 2; + return; + } + SetValue(val + delta); + sendSpinEvent(); +} + +void SpinInputDouble::onTextLostFocus(wxEvent &event) +{ + timer.Stop(); + for (auto * child : GetChildren()) + if (auto btn = dynamic_cast(child)) + if (btn->HasCapture()) + btn->ReleaseMouse(); + wxCommandEvent e; + onTextEnter(e); + // pass to outer + event.SetId(GetId()); + ProcessEventLocally(event); + e.Skip(); +} + +void SpinInputDouble::onTextEnter(wxCommandEvent &event) +{ + double value; + if (!text_ctrl->GetValue().ToDouble(&value)) + val = value; + + if (!Slic3r::is_approx(value, val)) { + SetValue(value); + sendSpinEvent(); + } + event.SetId(GetId()); + ProcessEventLocally(event); +} + +void SpinInputDouble::mouseWheelMoved(wxMouseEvent &event) +{ + auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? inc : -inc; + SetValue(val + delta); + sendSpinEvent(); + text_ctrl->SetFocus(); +} + +void SpinInputDouble::keyPressed(wxKeyEvent &event) +{ + switch (event.GetKeyCode()) { + case WXK_UP: + case WXK_DOWN: + double value; + if (!text_ctrl->GetValue().ToDouble(&value)) + val = value; + + if (event.GetKeyCode() == WXK_DOWN && value > min) { + value -= inc; + } else if (event.GetKeyCode() == WXK_UP && value + inc < max) { + value += inc; + } + if (!Slic3r::is_approx(value, val)) { + SetValue(value); + sendSpinEvent(); + } + break; + default: event.Skip(); break; + } +} + + + diff --git a/src/slic3r/GUI/Widgets/SpinInput.hpp b/src/slic3r/GUI/Widgets/SpinInput.hpp index 364d8c71d5..f81ec0b80d 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.hpp +++ b/src/slic3r/GUI/Widgets/SpinInput.hpp @@ -6,20 +6,16 @@ class Button; -class SpinInput : public wxNavigationEnabled +class SpinInputBase : public wxNavigationEnabled { - wxSize labelSize; - StateColor label_color; - StateColor text_color; - wxTextCtrl * text_ctrl{nullptr}; - Button * button_inc {nullptr}; - Button * button_dec {nullptr}; - wxTimer timer; - - int val; - int min; - int max; - int delta; +protected: + wxSize labelSize; + StateColor label_color; + StateColor text_color; + wxTextCtrl * text_ctrl{nullptr}; + Button * button_inc {nullptr}; + Button * button_dec {nullptr}; + wxTimer timer; static const int SpinInputWidth = 200; static const int SpinInputHeight = 50; @@ -31,8 +27,69 @@ class SpinInput : public wxNavigationEnabled }; public: - SpinInput(); + SpinInputBase(); + void SetCornerRadius(double radius); + + void SetLabel(const wxString &label) wxOVERRIDE; + + void SetLabelColor(StateColor const &color); + + void SetTextColor(StateColor const &color); + + void SetSize(wxSize const &size); + + void Rescale(); + + virtual bool Enable(bool enable = true) wxOVERRIDE; + + wxTextCtrl * GetText() { return text_ctrl; } + + virtual void SetValue(const wxString &text) = 0; + + wxString GetTextValue() const; + + bool SetFont(wxFont const& font) override; + + bool SetBackgroundColour(const wxColour& colour) override; + bool SetForegroundColour(const wxColour& colour) override; + void SetBorderColor(StateColor const& color); + void SetSelection(long from, long to); + +protected: + void DoSetToolTipText(wxString const &tip) override; + + void paintEvent(wxPaintEvent& evt); + + void render(wxDC& dc); + + void messureSize(); + + Button *create_button(ButtonId id); + virtual void bind_inc_dec_button(Button *btn, ButtonId id) = 0; + + // some useful events + virtual void mouseWheelMoved(wxMouseEvent& event) = 0; + virtual void keyPressed(wxKeyEvent& event) = 0; + virtual void onTimer(wxTimerEvent &evnet) = 0; + virtual void onTextLostFocus(wxEvent &event) = 0; + virtual void onTextEnter(wxCommandEvent &event) = 0; + + void onText(wxCommandEvent &event); + + void sendSpinEvent(); + + DECLARE_EVENT_TABLE() +}; + +class SpinInput : public SpinInputBase +{ + int val; + int min; + int max; + int delta; + +public: SpinInput(wxWindow * parent, wxString text, wxString label = "", @@ -51,64 +108,83 @@ public: int max = 100, int initial = 0); - void SetCornerRadius(double radius); - - void SetLabel(const wxString &label) wxOVERRIDE; - - void SetLabelColor(StateColor const &color); - - void SetTextColor(StateColor const &color); - - void SetSize(wxSize const &size); - - void Rescale(); - - virtual bool Enable(bool enable = true) wxOVERRIDE; - - wxTextCtrl * GetText() { return text_ctrl; } - - void SetValue(const wxString &text); + void SetValue(const wxString &text) override; void SetValue (int value); - - int GetValue () const; - wxString GetTextValue() const; + int GetValue () const; void SetRange(int min, int max); - bool SetFont(wxFont const& font) override; - - bool SetBackgroundColour(const wxColour& colour) override; - bool SetForegroundColour(const wxColour& colour) override; - void SetBorderColor(StateColor const& color); - int GetMin() const { return this->min; } int GetMax() const { return this->max; } - void SetSelection(long from, long to); protected: - void DoSetToolTipText(wxString const &tip) override; - -private: - void paintEvent(wxPaintEvent& evt); - - void render(wxDC& dc); - - void messureSize(); - - Button *create_button(ButtonId id); - + void bind_inc_dec_button(Button* btn, ButtonId id) override; // some useful events - void mouseWheelMoved(wxMouseEvent& event); - void keyPressed(wxKeyEvent& event); - void onTimer(wxTimerEvent &evnet); - void onTextLostFocus(wxEvent &event); - void onText(wxCommandEvent &event); - void onTextEnter(wxCommandEvent &event); + void mouseWheelMoved(wxMouseEvent& event) override; + void keyPressed(wxKeyEvent& event) override; + void onTimer(wxTimerEvent& evnet) override; + void onTextLostFocus(wxEvent& event) override; + void onTextEnter(wxCommandEvent& event) override; +}; - void sendSpinEvent(); +class SpinInputDouble : public SpinInputBase +{ + double val; + double min; + double max; + double inc; + double delta; + int digits {-1}; - DECLARE_EVENT_TABLE() +public: + + SpinInputDouble() : SpinInputBase() {} + + SpinInputDouble(wxWindow* parent, + wxString text, + wxString label = "", + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + double min = 0., + double max = 100., + double initial = 0., + double inc = 1.); + + void Create(wxWindow* parent, + wxString text, + wxString label = "", + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + double min = 0., + double max = 100., + double initial = 0., + double inc = 1.); + + void SetValue(const wxString& text) override; + + void SetValue(double value); + double GetValue() const; + + //wxString GetTextValue() const override; + + void SetRange(double min, double max); + void SetIncrement(double inc); + void SetDigits(unsigned digits); + + double GetMin() const { return this->min; } + double GetMax() const { return this->max; } + +protected: + void bind_inc_dec_button(Button* btn, ButtonId id) override; + // some useful events + void mouseWheelMoved(wxMouseEvent& event) override; + void keyPressed(wxKeyEvent& event) override; + void onTimer(wxTimerEvent& evnet) override; + void onTextLostFocus(wxEvent& event) override; + void onTextEnter(wxCommandEvent& event) override; }; #endif // !slic3r_GUI_SpinInput_hpp_ diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 061245d52d..664223c1d3 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -109,7 +109,8 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) #endif sizer_chart->Add(m_chart, 0, wxALL, 5); - m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0.,5.0,3.,0.5); + m_widget_time = new ::SpinInputDouble(this,"", wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1), style, 0., 5., 3., 0.5); + m_widget_time->SetDigits(2); m_widget_volume = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0,10000,0); m_widget_ramming_line_width_multiplicator = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); m_widget_ramming_step_multiplicator = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); @@ -136,7 +137,6 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) sizer_param->Add(gsizer_param, 0, wxTOP, scale(10)); m_widget_time->SetValue(m_chart->get_time()); - m_widget_time->SetDigits(2); m_widget_volume->SetValue(m_chart->get_volume()); m_widget_volume->Disable(); m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator); @@ -152,8 +152,9 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) sizer->SetSizeHints(this); SetSizer(sizer); - m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);}); + m_widget_time->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { m_chart->set_xy_range(m_widget_time->GetValue(),-1); }); m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value + m_widget_time->GetText()->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} ); Refresh(true); // erase background diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index f64d1363a5..f6dd110262 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -26,7 +26,7 @@ private: ::SpinInput* m_widget_volume = nullptr; ::SpinInput* m_widget_ramming_line_width_multiplicator = nullptr; ::SpinInput* m_widget_ramming_step_multiplicator = nullptr; - wxSpinCtrlDouble* m_widget_time = nullptr; + ::SpinInputDouble* m_widget_time = nullptr; int m_ramming_step_multiplicator; int m_ramming_line_width_multiplicator;