diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/slic3r/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/Field.cpp | 15 | ||||
-rw-r--r-- | src/slic3r/GUI/Field.hpp | 24 | ||||
-rw-r--r-- | src/slic3r/GUI/OG_CustomCtrl.cpp | 384 | ||||
-rw-r--r-- | src/slic3r/GUI/OG_CustomCtrl.hpp | 89 | ||||
-rw-r--r-- | src/slic3r/GUI/OptionsGroup.cpp | 199 | ||||
-rw-r--r-- | src/slic3r/GUI/OptionsGroup.hpp | 10 | ||||
-rw-r--r-- | src/slic3r/GUI/wxExtensions.hpp | 2 |
8 files changed, 643 insertions, 82 deletions
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 105d02613..c44b76970 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -111,6 +111,8 @@ set(SLIC3R_GUI_SOURCES GUI/Field.hpp GUI/OptionsGroup.cpp GUI/OptionsGroup.hpp + GUI/OG_CustomCtrl.cpp + GUI/OG_CustomCtrl.hpp GUI/BedShapeDialog.cpp GUI/BedShapeDialog.hpp GUI/2DBed.cpp diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 0bb3f0068..55c785317 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -63,18 +63,23 @@ Field::~Field() m_back_to_initial_value = nullptr; if (m_back_to_sys_value) m_back_to_sys_value = nullptr; + if (getWindow()) { + wxWindow* win = getWindow(); + win->Destroy(); + win = nullptr; + } } void Field::PostInitialize() { auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - m_Undo_btn = new RevertButton(m_parent, "bullet_white.png"); - m_Undo_to_sys_btn = new RevertButton(m_parent, "bullet_white.png"); +// m_Undo_btn = new RevertButton(m_parent, "bullet_white.png"); +// m_Undo_to_sys_btn = new RevertButton(m_parent, "bullet_white.png"); - m_Undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_back_to_initial_value(); })); - m_Undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_back_to_sys_value(); })); +// m_Undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_back_to_initial_value(); })); +// m_Undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_back_to_sys_value(); })); - m_blinking_bmp = new BlinkingBitmap(m_parent); +// m_blinking_bmp = new BlinkingBitmap(m_parent); switch (m_opt.type) { diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index aa047d030..c716259db 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -168,7 +168,7 @@ public: bool set_undo_bitmap(const ScalableBitmap *bmp) { if (m_undo_bitmap != bmp) { m_undo_bitmap = bmp; - m_Undo_btn->SetBitmap_(*bmp); +// m_Undo_btn->SetBitmap_(*bmp); return true; } return false; @@ -177,33 +177,33 @@ public: bool set_undo_to_sys_bitmap(const ScalableBitmap *bmp) { if (m_undo_to_sys_bitmap != bmp) { m_undo_to_sys_bitmap = bmp; - m_Undo_to_sys_btn->SetBitmap_(*bmp); +// m_Undo_to_sys_btn->SetBitmap_(*bmp); return true; } return false; } bool set_label_colour(const wxColour *clr) { - if (m_Label == nullptr) return false; +// if (m_Label == nullptr) return false; if (m_label_color != clr) { m_label_color = clr; - m_Label->SetForegroundColour(*clr); - m_Label->Refresh(true); +// m_Label->SetForegroundColour(*clr); +// m_Label->Refresh(true); } return false; } bool set_label_colour_force(const wxColour *clr) { if (m_Label == nullptr) return false; - m_Label->SetForegroundColour(*clr); - m_Label->Refresh(true); +// m_Label->SetForegroundColour(*clr); +// m_Label->Refresh(true); return false; } bool set_undo_tooltip(const wxString *tip) { if (m_undo_tooltip != tip) { m_undo_tooltip = tip; - m_Undo_btn->SetToolTip(*tip); +// m_Undo_btn->SetToolTip(*tip); return true; } return false; @@ -212,7 +212,7 @@ public: bool set_undo_to_sys_tooltip(const wxString *tip) { if (m_undo_to_sys_tooltip != tip) { m_undo_to_sys_tooltip = tip; - m_Undo_to_sys_btn->SetToolTip(*tip); +// m_Undo_to_sys_btn->SetToolTip(*tip); return true; } return false; @@ -235,6 +235,12 @@ public: BlinkingBitmap* blinking_bitmap() const { return m_blinking_bmp;} + const ScalableBitmap* undo_bitmap() { return m_undo_bitmap; } + const wxString* undo_tooltip() { return m_undo_tooltip; } + const ScalableBitmap* undo_to_sys_bitmap() { return m_undo_to_sys_bitmap; } + const wxString* undo_to_sys_tooltip() { return m_undo_to_sys_tooltip; } + const wxColour* label_color() { return m_label_color; } + protected: RevertButton* m_Undo_btn = nullptr; // Bitmap and Tooltip text for m_Undo_btn. The wxButton will be updated only if the new wxBitmap pointer differs from the currently rendered one. diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp new file mode 100644 index 000000000..0641f0103 --- /dev/null +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -0,0 +1,384 @@ +#include "OG_CustomCtrl.hpp" +#include "OptionsGroup.hpp" +#include "ConfigExceptions.hpp" +#include "Plater.hpp" +#include "GUI_App.hpp" + +#include <utility> +#include <wx/numformatter.h> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> +#include "libslic3r/Exception.hpp" +#include "libslic3r/Utils.hpp" +#include "I18N.hpp" + +namespace Slic3r { namespace GUI { + +OG_CustomCtrl::OG_CustomCtrl( wxWindow* parent, + OptionsGroup* og, + const wxPoint& pos /* = wxDefaultPosition*/, + const wxSize& size/* = wxDefaultSize*/, + const wxValidator& val /* = wxDefaultValidator*/, + const wxString& name/* = wxEmptyString*/) : + wxControl(parent, wxID_ANY, pos, size, wxWANTS_CHARS | wxBORDER_NONE), + m_og(og) +{ + if (!wxOSX) + SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX + + // init bitmaps + m_bmp_mode_simple = ScalableBitmap(this, "mode_simple" , wxOSX ? 10 : 12); + m_bmp_mode_advanced = ScalableBitmap(this, "mode_advanced", wxOSX ? 10 : 12); + m_bmp_mode_expert = ScalableBitmap(this, "mode_expert" , wxOSX ? 10 : 12); + m_bmp_blinking = ScalableBitmap(this, "search_blink"); + + m_border = lround(0.2 * wxGetApp().em_unit()); + m_v_gap = lround(1.0 * wxGetApp().em_unit()); + m_h_gap = lround(0.2 * wxGetApp().em_unit()); + + init_ctrl_lines();// from og.lines() + + this->Bind(wxEVT_PAINT, &OG_CustomCtrl::OnPaint, this); + this->Bind(wxEVT_MOTION, &OG_CustomCtrl::OnMotion, this); + this->Bind(wxEVT_LEFT_DOWN, &OG_CustomCtrl::OnLeftDown, this); + this->Bind(wxEVT_LEFT_UP, &OG_CustomCtrl::OnLeftUp, this); + + const wxFont& font = wxGetApp().normal_font(); + m_font = wxOSX ? font.Smaller() : font; +} + +void OG_CustomCtrl::init_ctrl_lines() +{ + wxCoord v_pos = 0; + + for (const Line& line : m_og->get_lines()) + { + if (line.full_width && ( + // description line + line.widget != nullptr || + // description line with widget (button) + !line.get_extra_widgets().empty()) + ) + continue; + + auto option_set = line.get_options(); + + wxCoord height = 0; + + // if we have a single option with no label, no sidetext just add it directly to sizer + if (option_set.size() == 1 && m_og->label_width == 0 && option_set.front().opt.full_width && + option_set.front().opt.label.empty() && + option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && + line.get_extra_widgets().size() == 0) + { + height = m_bmp_blinking.bmp().GetHeight() + m_v_gap; + ctrl_lines.emplace_back(CtrlLine{ height, this, line, true }); + } + else if (m_og->label_width != 0 && !line.label.IsEmpty()) + { + wxSize label_sz = GetTextExtent(line.label); + height = label_sz.y * (label_sz.GetWidth() > (m_og->label_width*wxGetApp().em_unit()) ? 2 : 1) + m_v_gap; + ctrl_lines.emplace_back(CtrlLine{ height, this, line }); + } + else + int i = 0; + v_pos += height; + } + + this->SetMinSize(wxSize(wxDefaultCoord, v_pos)); +} + +wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) +{ + wxCoord v_pos = 0; + wxCoord h_pos = 0; + for (auto ctrl_line : ctrl_lines) { + if (&ctrl_line.m_og_line == &line) + { + h_pos = m_bmp_mode_simple.bmp().GetWidth() + m_h_gap; + if (line.near_label_widget) { + if (field_in) + h_pos += m_bmp_blinking.bmp().GetWidth() + m_h_gap; // ysFIXME + else + break; + } + + wxString label = line.label; + if (m_og->label_width != 0 && !label.IsEmpty()) + h_pos += m_og->label_width * wxGetApp().em_unit(); + + if (line.widget) + break; + + // If we have a single option with no sidetext + const std::vector<Option>& option_set = line.get_options(); + if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && + option_set.front().opt.label.empty() && + option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) + { + h_pos += 3 * (m_bmp_blinking.bmp().GetWidth() + m_h_gap); + break; + } + + for (auto opt : option_set) { + Field* field = m_og->get_field(opt.opt_id); + ConfigOptionDef option = opt.opt; + // add label if any + if (!option.label.empty()) { + //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 + label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? + _CTX(option.label, "Layers") : _(option.label); + label += ":"; + + h_pos += GetTextExtent(label).x + m_h_gap; + } + h_pos += 3 * (m_bmp_blinking.bmp().GetWidth() + m_h_gap); + + if (field == field_in) + break; + h_pos += field->getWindow()->GetSize().x; + + if (option_set.size() == 1 && option_set.front().opt.full_width) + break; + + // add sidetext if any + if (!option.sidetext.empty() || m_og->sidetext_width > 0) + h_pos += m_og->sidetext_width * wxGetApp().em_unit(); + + if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back()) + h_pos += lround(0.6 * wxGetApp().em_unit()); + } + break; + } + v_pos += ctrl_line.m_height; + } + + return wxPoint(h_pos, v_pos); +} + + +void OG_CustomCtrl::OnPaint(wxPaintEvent&) +{ +#ifdef _WIN32 + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#else + SetBackgroundColour(GetParent()->GetBackgroundColour()); +#endif // _WIN32 + + wxPaintDC dc(this); + dc.SetFont(m_font); + + wxCoord v_pos = 0; + for (auto line : ctrl_lines) { + if (!line.is_visible) + continue; + line.render(dc, v_pos); + v_pos += line.m_height; + } +} + +void OG_CustomCtrl::OnMotion(wxMouseEvent& event) +{ + bool action = false; + + const wxPoint pos = event.GetLogicalPosition(wxClientDC(this)); + Refresh(); + Update(); + event.Skip(); +} + +void OG_CustomCtrl::OnLeftDown(wxMouseEvent& event) +{ + if (HasCapture()) + return; + this->CaptureMouse(); + + event.Skip(); +} + +void OG_CustomCtrl::OnLeftUp(wxMouseEvent& event) +{ + if (HasCapture()) + return; + this->CaptureMouse(); + + event.Skip(); +} + +bool OG_CustomCtrl::update_visibility(ConfigOptionMode mode) +{ + return true; +} + +void OG_CustomCtrl::msw_rescale() +{ + const wxFont& font = GUI::wxGetApp().normal_font(); + m_font = wxOSX ? font.Smaller() : font; + + wxSize new_sz = GUI::wxGetApp().em_unit() * this->GetSize(); + SetMinSize(new_sz); + GetParent()->Layout(); +} + +void OG_CustomCtrl::sys_color_changed() +{ + +} + + +void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) +{ + Field* field = nullptr; + field = m_ctrl->m_og->get_field(m_og_line.get_options().front().opt_id); + + if (draw_just_act_buttons) { + if (field) + draw_act_bmps(dc, wxPoint(0, v_pos), m_ctrl->m_bmp_blinking.bmp(), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp()); + return; + } + + wxCoord h_pos = draw_mode_bmp(dc, v_pos); + + if (m_og_line.near_label_widget) + h_pos += m_ctrl->m_bmp_blinking.bmp().GetWidth() + m_ctrl->m_h_gap;//m_og_line.near_label_widget->GetSize().x;; + + const std::vector<Option>& option_set = m_og_line.get_options(); + + wxString label = m_og_line.label; + if (m_ctrl->m_og->label_width != 0 && !label.IsEmpty()) + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label+":", (option_set.size() == 1 && field ? field->label_color() : m_og_line.full_Label_color), m_ctrl->m_og->label_width*wxGetApp().em_unit()); + + // If there's a widget, build it and add the result to the sizer. + if (m_og_line.widget != nullptr) + return; + + // If we're here, we have more than one option or a single option with sidetext + // so we need a horizontal sizer to arrange these things + + // If we have a single option with no sidetext just add it directly to the grid sizer + if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && + option_set.front().opt.label.empty() && + option_set.front().side_widget == nullptr && m_og_line.get_extra_widgets().size() == 0) + { + if (field) + draw_act_bmps(dc, wxPoint(h_pos, v_pos), m_ctrl->m_bmp_blinking.bmp(), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp()); + return; + } + + for (auto opt : option_set) { + field = m_ctrl->m_og->get_field(opt.opt_id); + ConfigOptionDef option = opt.opt; + // add label if any + if (!option.label.empty()) { + //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 + label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? + _CTX(option.label, "Layers") : _(option.label); + label += ":"; + + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label, field ? field->label_color() : nullptr, m_ctrl->m_og->sublabel_width * wxGetApp().em_unit()); + } + + if (field) { + h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), m_ctrl->m_bmp_blinking.bmp(), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp()); + h_pos += field->getWindow()->GetSize().x; + } + + // add field + if (option_set.size() == 1 && option_set.front().opt.full_width) + break; + + // add sidetext if any + if (!option.sidetext.empty() || m_ctrl->m_og->sidetext_width > 0) + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), _(option.sidetext), nullptr, m_ctrl->m_og->sidetext_width * wxGetApp().em_unit()); + + if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back()) + h_pos += lround(0.6 * wxGetApp().em_unit()); + } +} + +wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos) +{ + ConfigOptionMode mode = m_og_line.get_options()[0].opt.mode; + const wxBitmap& bmp = mode == ConfigOptionMode::comSimple ? m_ctrl->m_bmp_mode_simple.bmp() : + mode == ConfigOptionMode::comAdvanced ? m_ctrl->m_bmp_mode_advanced.bmp() : m_ctrl->m_bmp_mode_expert.bmp(); + + wxCoord y_draw = v_pos + lround((m_height - bmp.GetHeight()) / 2); + + dc.DrawBitmap(bmp, m_ctrl->m_border, y_draw); + + return m_ctrl->m_border + bmp.GetWidth() + m_ctrl->m_h_gap; +} + +wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width) +{ + wxString multiline_text; + if (width > 0 && dc.GetTextExtent(text).x > width) { + multiline_text = text; + + size_t idx = size_t(-1); + for (size_t i = 0; i < multiline_text.Len(); i++) + { + if (multiline_text[i] == ' ') + { + if (dc.GetTextExtent(multiline_text.SubString(0, i)).x < width) + idx = i; + else { + if (idx != size_t(-1)) + multiline_text[idx] = '\n'; + else + multiline_text[i] = '\n'; + break; + } + } + } + + if (idx != size_t(-1)) + multiline_text[idx] = '\n'; + } + + const wxString& out_text = multiline_text.IsEmpty() ? text : multiline_text; + wxCoord text_width, text_height; + dc.GetMultiLineTextExtent(out_text, &text_width, &text_height); + + pos.y = pos.y + lround((m_height - text_height) / 2); + + wxColour old_clr = dc.GetTextForeground(); + dc.SetTextForeground(color ? *color : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + dc.DrawText(out_text, pos); + dc.SetTextForeground(old_clr); + + if (width < 1) + width = text_width; + + return pos.x + width + m_ctrl->m_h_gap; +} + +wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_blinking, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo) +{ + wxCoord h_pos = pos.x; + wxCoord pos_y = pos.y + lround((m_height - bmp_blinking.GetHeight()) / 2); + + dc.DrawBitmap(bmp_blinking, h_pos, pos_y); + + int bmp_dim = bmp_blinking.GetWidth(); + m_rect_blinking = wxRect(h_pos, pos_y, bmp_dim, bmp_dim); + + h_pos += bmp_dim + m_ctrl->m_h_gap; + dc.DrawBitmap(bmp_undo_to_sys, h_pos, pos_y); + + bmp_dim = bmp_undo_to_sys.GetWidth(); + m_rect_undo_to_sys_icon = wxRect(h_pos, pos_y, bmp_dim, bmp_dim); + + h_pos += bmp_dim + m_ctrl->m_h_gap; + dc.DrawBitmap(bmp_undo, h_pos, pos_y); + + bmp_dim = bmp_undo.GetWidth(); + m_rect_undo_icon = wxRect(h_pos, pos_y, bmp_dim, bmp_dim); + + h_pos += bmp_dim + m_ctrl->m_h_gap; + + return h_pos; +} + +} // GUI +} // Slic3r diff --git a/src/slic3r/GUI/OG_CustomCtrl.hpp b/src/slic3r/GUI/OG_CustomCtrl.hpp new file mode 100644 index 000000000..4111f5568 --- /dev/null +++ b/src/slic3r/GUI/OG_CustomCtrl.hpp @@ -0,0 +1,89 @@ +#ifndef slic3r_OG_CustomCtrl_hpp_ +#define slic3r_OG_CustomCtrl_hpp_ + +#include <wx/stattext.h> +#include <wx/settings.h> + +#include <map> +#include <functional> + +#include "libslic3r/Config.hpp" +#include "libslic3r/PrintConfig.hpp" + +#include "OptionsGroup.hpp" +#include "I18N.hpp" + +// Translate the ifdef +#ifdef __WXOSX__ + #define wxOSX true +#else + #define wxOSX false +#endif + +//#define BORDER(a, b) ((wxOSX ? a : b)) + +namespace Slic3r { namespace GUI { + +// Static text shown among the options. +class OG_CustomCtrl :public wxControl +{ + wxFont m_font; + + ScalableBitmap m_bmp_mode_simple; + ScalableBitmap m_bmp_mode_advanced; + ScalableBitmap m_bmp_mode_expert; + ScalableBitmap m_bmp_blinking; + + struct CtrlLine { + wxCoord m_height { wxDefaultCoord }; + OG_CustomCtrl* m_ctrl { nullptr }; + const Line& m_og_line; + + bool draw_just_act_buttons { false }; + bool is_visible { true }; + + void render(wxDC& dc, wxCoord v_pos); + wxCoord draw_mode_bmp(wxDC& dc, wxCoord v_pos); + wxCoord draw_text (wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width); + wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_blinking, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo); + + void set_visible(bool show) { is_visible = show; } + + wxRect m_rect_blinking; + wxRect m_rect_undo_icon; + wxRect m_rect_undo_to_sys_icon; + }; + + std::vector<CtrlLine> ctrl_lines; + +public: + OG_CustomCtrl( wxWindow* parent, + OptionsGroup* og, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + const wxValidator& val = wxDefaultValidator, + const wxString& name = wxEmptyString); + ~OG_CustomCtrl() {} + + void OnPaint(wxPaintEvent&); + void OnMotion(wxMouseEvent& event); + void OnLeftDown(wxMouseEvent& event); + void OnLeftUp(wxMouseEvent& event); + + void init_ctrl_lines(); + bool update_visibility(ConfigOptionMode mode); + void msw_rescale(); + void sys_color_changed(); + + wxPoint get_pos(const Line& line, Field* field = nullptr); + + OptionsGroup* m_og; + int m_border; + int m_v_gap; + int m_h_gap; + +}; + +}} + +#endif /* slic3r_OG_CustomCtrl_hpp_ */ diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index f1215474d..c75b4525e 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -2,6 +2,7 @@ #include "ConfigExceptions.hpp" #include "Plater.hpp" #include "GUI_App.hpp" +#include "OG_CustomCtrl.hpp" #include <utility> #include <wx/numformatter.h> @@ -114,7 +115,7 @@ OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title, void OptionsGroup::add_undo_buttons_to_sizer(wxSizer* sizer, const t_field& field) { - if (!m_show_modified_btns) { + if (!m_show_modified_btns && field->m_Undo_btn) { field->m_Undo_btn->set_as_hidden(); field->m_Undo_to_sys_btn->set_as_hidden(); field->m_blinking_bmp->Hide(); @@ -147,11 +148,14 @@ void OptionsGroup::append_line(const Line& line) void OptionsGroup::activate_line(Line& line) { + m_use_custom_ctrl_as_parent = false; + if (line.full_width && ( line.widget != nullptr || !line.get_extra_widgets().empty()) ) { if (line.widget != nullptr) { + // description lines sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); return; } @@ -168,6 +172,11 @@ void OptionsGroup::activate_line(Line& line) } } + if (!custom_ctrl && m_show_modified_btns) { + custom_ctrl = new OG_CustomCtrl((wxWindow*)this->stb, this); + sizer->Add(custom_ctrl, 0, wxEXPAND | wxALL, wxOSX || !staticbox ? 0 : 5); + } + auto option_set = line.get_options(); // Set sidetext width for a better alignment of options in line @@ -181,36 +190,29 @@ void OptionsGroup::activate_line(Line& line) option_set.front().opt.label.empty() && option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { - wxSizer* tmp_sizer; -#if 0//#ifdef __WXGTK__ - tmp_sizer = new wxBoxSizer(wxVERTICAL); - m_panel->SetSizer(tmp_sizer); - m_panel->Layout(); -#else - tmp_sizer = sizer; -#endif /* __WXGTK__ */ const auto& option = option_set.front(); const auto& field = build_field(option); - auto btn_sizer = new wxBoxSizer(wxHORIZONTAL); - add_undo_buttons_to_sizer(btn_sizer, field); - tmp_sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, 0); + if (!custom_ctrl) { + auto btn_sizer = new wxBoxSizer(wxHORIZONTAL); + add_undo_buttons_to_sizer(btn_sizer, field); + sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, 0); + } if (is_window_field(field)) - tmp_sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); + sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); if (is_sizer_field(field)) - tmp_sizer->Add(field->getSizer(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); + sizer->Add(field->getSizer(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); return; } auto grid_sizer = m_grid_sizer; -#if 0//#ifdef __WXGTK__ - m_panel->SetSizer(m_grid_sizer); - m_panel->Layout(); -#endif /* __WXGTK__ */ + + if (custom_ctrl) + m_use_custom_ctrl_as_parent = true; // if we have an extra column, build it - if (extra_column) + if (extra_column && !m_show_modified_btns) { m_extra_column_item_ptrs.push_back(extra_column(this->ctrl_parent(), line)); grid_sizer->Add(m_extra_column_item_ptrs.back(), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 3); @@ -219,55 +221,76 @@ void OptionsGroup::activate_line(Line& line) // Build a label if we have it wxStaticText* label=nullptr; if (label_width != 0) { - if (! line.near_label_widget || ! line.label.IsEmpty()) { - // Only create the label if it is going to be displayed. - long label_style = staticbox ? 0 : wxALIGN_RIGHT; + if (custom_ctrl) { + if (line.near_label_widget) { + m_near_label_widget_ptrs.push_back(line.near_label_widget(this->ctrl_parent())); + + wxPoint pos = custom_ctrl->get_pos(line); + m_near_label_widget_ptrs.back()->SetPosition(pos); + } + } + else { + if (!line.near_label_widget || !line.label.IsEmpty()) { + // Only create the label if it is going to be displayed. + long label_style = staticbox ? 0 : wxALIGN_RIGHT; #ifdef __WXGTK__ - // workaround for correct text align of the StaticBox on Linux - // flags wxALIGN_RIGHT and wxALIGN_CENTRE don't work when Ellipsize flags are _not_ given. - // Text is properly aligned only when Ellipsize is checked. - label_style |= staticbox ? 0 : wxST_ELLIPSIZE_END; + // workaround for correct text align of the StaticBox on Linux + // flags wxALIGN_RIGHT and wxALIGN_CENTRE don't work when Ellipsize flags are _not_ given. + // Text is properly aligned only when Ellipsize is checked. + label_style |= staticbox ? 0 : wxST_ELLIPSIZE_END; #endif /* __WXGTK__ */ - label = new wxStaticText(this->ctrl_parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ": "), - wxDefaultPosition, wxSize(label_width * wxGetApp().em_unit(), -1), label_style); - label->SetBackgroundStyle(wxBG_STYLE_PAINT); - label->SetFont(wxGetApp().normal_font()); - label->Wrap(label_width*wxGetApp().em_unit()); // avoid a Linux/GTK bug - } - if (!line.near_label_widget) - grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5); - else { - m_near_label_widget_ptrs.push_back(line.near_label_widget(this->ctrl_parent())); - - if (line.label.IsEmpty()) - grid_sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); + label = new wxStaticText(this->ctrl_parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ": "), + wxDefaultPosition, wxSize(label_width * wxGetApp().em_unit(), -1), label_style); + label->SetBackgroundStyle(wxBG_STYLE_PAINT); + label->SetFont(wxGetApp().normal_font()); + label->Wrap(label_width * wxGetApp().em_unit()); // avoid a Linux/GTK bug + } + if (!line.near_label_widget) + grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5); else { - // If we're here, we have some widget near the label - // so we need a horizontal sizer to arrange these things - auto sizer = new wxBoxSizer(wxHORIZONTAL); - grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); - sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); - sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); + m_near_label_widget_ptrs.push_back(line.near_label_widget(this->ctrl_parent())); + + if (line.label.IsEmpty()) + grid_sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); + else { + // If we're here, we have some widget near the label + // so we need a horizontal sizer to arrange these things + auto sizer = new wxBoxSizer(wxHORIZONTAL); + grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); + sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); + sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); + } } + if (label != nullptr && line.label_tooltip != "") + label->SetToolTip(line.label_tooltip); } - if (label != nullptr && line.label_tooltip != "") - label->SetToolTip(line.label_tooltip); } if (line.full_Label != nullptr) *line.full_Label = label; // Initiate the pointer to the control of the full label, if we need this one. // If there's a widget, build it and add the result to the sizer. if (line.widget != nullptr) { - auto wgt = line.widget(this->ctrl_parent()); + auto wgt = line.widget(custom_ctrl ? custom_ctrl : this->ctrl_parent()); + if (custom_ctrl) { + auto children = wgt->GetChildren(); + wxPoint pos = custom_ctrl->get_pos(line); + for (auto child : children) + if (child->IsWindow()) { + child->GetWindow()->SetPosition(pos); + pos.x += child->GetWindow()->GetBestSize().x + custom_ctrl->m_h_gap; + } + } // If widget doesn't have label, don't use border - grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5); + else + grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5); return; } // If we're here, we have more than one option or a single option with sidetext // so we need a horizontal sizer to arrange these things auto sizer = new wxBoxSizer(wxHORIZONTAL); - grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); + if (!custom_ctrl) + grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); // If we have a single option with no sidetext just add it directly to the grid sizer if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && option_set.front().opt.label.empty() && @@ -275,20 +298,28 @@ void OptionsGroup::activate_line(Line& line) const auto& option = option_set.front(); const auto& field = build_field(option, label); - add_undo_buttons_to_sizer(sizer, field); - if (is_window_field(field)) - sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, //(option.opt.full_width ? wxEXPAND : 0) | - wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2); - if (is_sizer_field(field)) - sizer->Add(field->getSizer(), 1, /*(*/option.opt.full_width ? wxEXPAND : /*0) |*/ wxALIGN_CENTER_VERTICAL, 0); - return; + if (!custom_ctrl) + add_undo_buttons_to_sizer(sizer, field); + if (is_window_field(field)) { + if (custom_ctrl) { + field->getWindow()->SetPosition(custom_ctrl->get_pos(line, field.get())); + if (option.opt.full_width) + field->getWindow()->SetSize(wxSize(3 * Field::def_width_wider() * wxGetApp().em_unit(), -1)); + } + else + sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, + wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2); + } + if (is_sizer_field(field)) + sizer->Add(field->getSizer(), 1, option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL, 0); + return; } for (auto opt : option_set) { ConfigOptionDef option = opt.opt; wxSizer* sizer_tmp = sizer; // add label if any - if (!option.label.empty()) { + if (!option.label.empty() && !custom_ctrl) { //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? _CTX(option.label, "Layers") : @@ -303,22 +334,40 @@ void OptionsGroup::activate_line(Line& line) // add field const Option& opt_ref = opt; auto& field = build_field(opt_ref, label); - add_undo_buttons_to_sizer(sizer_tmp, field); + if (!custom_ctrl) + add_undo_buttons_to_sizer(sizer_tmp, field); if (option_set.size() == 1 && option_set.front().opt.full_width) { - const auto v_sizer = new wxBoxSizer(wxVERTICAL); - sizer_tmp->Add(v_sizer, 1, wxEXPAND); - is_sizer_field(field) ? - v_sizer->Add(field->getSizer(), 0, wxEXPAND) : - v_sizer->Add(field->getWindow(), 0, wxEXPAND); + if (custom_ctrl) { + if (is_window_field(field)) + field->getWindow()->SetPosition(custom_ctrl->get_pos(line, field.get())); + else { + } + } + else { + const auto v_sizer = new wxBoxSizer(wxVERTICAL); + sizer_tmp->Add(v_sizer, 1, wxEXPAND); + is_sizer_field(field) ? + v_sizer->Add(field->getSizer(), 0, wxEXPAND) : + v_sizer->Add(field->getWindow(), 0, wxEXPAND); + } break;//return; } - is_sizer_field(field) ? - sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) : - sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0); + if (custom_ctrl) { + if (is_window_field(field)) + field->getWindow()->SetPosition(custom_ctrl->get_pos(line, field.get())); + else { + } + } + else { + is_sizer_field(field) ? + sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) : + sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0); + } // add sidetext if any + if (!custom_ctrl) if (!option.sidetext.empty() || sidetext_width > 0) { auto sidetext = new wxStaticText( this->ctrl_parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, wxSize(sidetext_width != -1 ? sidetext_width*wxGetApp().em_unit() : -1, -1), wxALIGN_LEFT); @@ -333,11 +382,18 @@ void OptionsGroup::activate_line(Line& line) sizer_tmp->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification } + if (custom_ctrl) + continue; + if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back()) { sizer_tmp->AddSpacer(6); } } + + if (custom_ctrl) + return; + // add extra sizers if any for (auto extra_widget : line.get_extra_widgets()) { @@ -417,6 +473,15 @@ void OptionsGroup::clear() if(line.full_Label) *line.full_Label = nullptr; + if (custom_ctrl) { + for (auto const &item : m_fields) { + wxWindow* win = item.second.get()->getWindow(); + if (win) + win = nullptr; + } + custom_ctrl = nullptr; + } + m_extra_column_item_ptrs.clear(); m_near_label_widget_ptrs.clear(); m_fields.clear(); diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 3ea94fa36..406d0d3d6 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -26,6 +26,7 @@ namespace Slic3r { namespace GUI { // Thrown if the building of a parameter page is canceled. class UIBuildCanceled : public std::exception {}; +class OG_CustomCtrl; /// Widget type describes a function object that returns a wxWindow (our widget) and accepts a wxWidget (parent window). using widget_t = std::function<wxSizer*(wxWindow*)>;//!std::function<wxWindow*(wxWindow*)>; @@ -52,6 +53,7 @@ public: wxString label_tooltip {wxString("")}; size_t full_width {0}; wxStaticText** full_Label {nullptr}; + wxColor* full_Label_color {nullptr}; widget_t widget {nullptr}; std::function<wxWindow*(wxWindow*)> near_label_widget{ nullptr }; @@ -84,6 +86,7 @@ public: const wxString title; size_t label_width = 20 ;// {200}; wxSizer* sizer {nullptr}; + OG_CustomCtrl* custom_ctrl{ nullptr }; column_t extra_column {nullptr}; t_change m_on_change { nullptr }; // To be called when the field loses focus, to assign a new initial value to the field. @@ -119,7 +122,7 @@ public: #endif /* __WXGTK__ */ wxWindow* ctrl_parent() const { - return this->stb ? (wxWindow*)this->stb : this->parent(); + return this->stb ? (this->custom_ctrl && m_use_custom_ctrl_as_parent ? (wxWindow*)this->custom_ctrl : (wxWindow*)this->stb) : this->parent(); } void append_line(const Line& line); @@ -188,6 +191,8 @@ public: wxGridSizer* get_grid_sizer() { return m_grid_sizer; } + const std::vector<Line>& get_lines() { return m_lines; } + protected: std::map<t_config_option_key, Option> m_options; wxWindow* m_parent {nullptr}; @@ -206,6 +211,9 @@ protected: // "true" if option is created in preset tabs bool m_show_modified_btns{ false }; + // "true" if control should be created on custom_ctrl + bool m_use_custom_ctrl_as_parent { false }; + // This panel is needed for correct showing of the ToolTips for Button, StaticText and CheckBox // Tooltips on GTK doesn't work inside wxStaticBoxSizer unless you insert a panel // inside it before you insert the other controls. diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 2bdc68e32..40596b4de 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -348,6 +348,8 @@ public: void activate(); void blink(); + const wxBitmap& get_bmp() const { return bmp.bmp(); } + private: ScalableBitmap bmp; bool show {false}; |