This commit is contained in:
enricoturri1966 2020-11-03 08:41:14 +01:00
commit 54d6834553
16 changed files with 1405 additions and 513 deletions

View file

@ -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

View file

@ -13,6 +13,7 @@
#include <wx/tooltip.h>
#include <wx/notebook.h>
#include <boost/algorithm/string/predicate.hpp>
#include "OG_CustomCtrl.hpp"
#ifdef __WXOSX__
#define wxOSX true
@ -63,18 +64,16 @@ 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->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);
switch (m_opt.type)
{
@ -94,6 +93,7 @@ void Field::PostInitialize()
// initialize m_unit_value
m_em_unit = em_unit(m_parent);
parent_is_custom_ctrl = dynamic_cast<OG_CustomCtrl*>(m_parent) != nullptr;
BUILD();
@ -216,10 +216,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
break;
}
wxString label = m_Label->GetLabel();
if (label.Last() == '\n') label.RemoveLast();
while (label.Last() == ' ') label.RemoveLast();
if (label.Last() == ':') label.RemoveLast();
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str()));
set_value(double_to_string(m_opt.min), true);
m_value = double(m_opt.min);
@ -305,28 +302,14 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
}
}
void Field::msw_rescale(bool rescale_sidetext)
void Field::msw_rescale()
{
m_Undo_to_sys_btn->msw_rescale();
m_Undo_btn->msw_rescale();
m_blinking_bmp->msw_rescale();
// update em_unit value
m_em_unit = em_unit(m_parent);
// update sidetext if it is needed
if (m_side_text && rescale_sidetext)
{
auto size = wxSize(def_width_thinner() * m_em_unit, -1);
m_side_text->SetSize(size);
m_side_text->SetMinSize(size);
}
}
void Field::sys_color_changed()
{
m_Undo_to_sys_btn->msw_rescale();
m_Undo_btn->msw_rescale();
}
template<class T>
@ -387,6 +370,8 @@ void TextCtrl::BUILD() {
const long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER/*0*/;
auto temp = new wxTextCtrl(m_parent, wxID_ANY, 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 ?
Slic3r::GUI::wxGetApp().code_font():
Slic3r::GUI::wxGetApp().normal_font());
@ -550,17 +535,24 @@ boost::any& TextCtrl::get_value()
return m_value;
}
void TextCtrl::msw_rescale(bool rescale_sidetext/* = false*/)
void TextCtrl::msw_rescale()
{
Field::msw_rescale(rescale_sidetext);
Field::msw_rescale();
auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord);
if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit);
if (m_opt.height >= 0)
size.SetHeight(m_opt.height*m_em_unit);
else if (parent_is_custom_ctrl && opt_height > 0)
size.SetHeight(lround(opt_height*m_em_unit));
if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit);
if (size != wxDefaultSize)
{
wxTextCtrl* field = dynamic_cast<wxTextCtrl*>(window);
field->SetMinSize(size);
if (parent_is_custom_ctrl)
field->SetSize(size);
else
field->SetMinSize(size);
}
}
@ -650,7 +642,7 @@ boost::any& CheckBox::get_value()
return m_value;
}
void CheckBox::msw_rescale(bool rescale_sidetext/* = false*/)
void CheckBox::msw_rescale()
{
Field::msw_rescale();
@ -704,6 +696,9 @@ void SpinCtrl::BUILD() {
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
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.)
@ -785,23 +780,32 @@ void SpinCtrl::propagate_value()
suppress_propagation = false;
}
void SpinCtrl::msw_rescale(bool rescale_sidetext/* = false*/)
void SpinCtrl::msw_rescale()
{
Field::msw_rescale(rescale_sidetext);
Field::msw_rescale();
wxSpinCtrl* field = dynamic_cast<wxSpinCtrl*>(window);
field->SetMinSize(wxSize(def_width() * m_em_unit, int(1.9f*field->GetFont().GetPixelSize().y)));
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)));
}
#ifdef __WXOSX__
using choice_ctrl = wxBitmapComboBox;
#else
using choice_ctrl = wxComboBox;
#endif // __WXOSX__
void Choice::BUILD() {
wxSize size(def_width_wider() * m_em_unit, wxDefaultCoord);
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);
wxBitmapComboBox* temp;
choice_ctrl* temp;
if (!m_opt.gui_type.empty() && m_opt.gui_type.compare("select_open") != 0) {
m_is_editable = true;
temp = new wxBitmapComboBox(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size);
temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size);
}
else {
#ifdef __WXOSX__
@ -809,11 +813,11 @@ void Choice::BUILD() {
* so ToolTip doesn't shown.
* Next workaround helps to solve this problem
*/
temp = new wxBitmapComboBox();
temp = new choice_ctrl();
temp->SetTextCtrlStyle(wxTE_READONLY);
temp->Create(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr);
#else
temp = new wxBitmapComboBox(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);
#endif //__WXOSX__
}
@ -836,7 +840,8 @@ void Choice::BUILD() {
set_selection();
}
#ifndef __WXGTK__
#ifdef __WXOSX__
//#ifndef __WXGTK__
/* Workaround for a correct rendering of the control without Bitmap (under MSW and OSX):
*
* 1. We should create small Bitmap to fill Bitmaps RefData,
@ -863,7 +868,7 @@ void Choice::BUILD() {
}
double old_val = !m_value.empty() ? boost::any_cast<double>(m_value) : -99999;
if (is_defined_input_value<wxBitmapComboBox>(window, m_opt.type)) {
if (is_defined_input_value<choice_ctrl>(window, m_opt.type)) {
if (fabs(old_val - boost::any_cast<double>(get_value())) <= 0.0001)
return;
else
@ -886,7 +891,7 @@ void Choice::set_selection()
wxString text_value = wxString("");
wxBitmapComboBox* field = dynamic_cast<wxBitmapComboBox*>(window);
choice_ctrl* field = dynamic_cast<choice_ctrl*>(window);
switch (m_opt.type) {
case coFloat:
case coPercent: {
@ -956,7 +961,7 @@ void Choice::set_value(const std::string& value, bool change_event) //! Redunda
++idx;
}
wxBitmapComboBox* field = dynamic_cast<wxBitmapComboBox*>(window);
choice_ctrl* field = dynamic_cast<choice_ctrl*>(window);
idx == m_opt.enum_values.size() ?
field->SetValue(value) :
field->SetSelection(idx);
@ -968,7 +973,7 @@ void Choice::set_value(const boost::any& value, bool change_event)
{
m_disable_change_event = !change_event;
wxBitmapComboBox* field = dynamic_cast<wxBitmapComboBox*>(window);
choice_ctrl* field = dynamic_cast<choice_ctrl*>(window);
switch (m_opt.type) {
case coInt:
@ -1044,7 +1049,7 @@ void Choice::set_values(const std::vector<std::string>& values)
// # it looks that Clear() also clears the text field in recent wxWidgets versions,
// # but we want to preserve it
auto ww = dynamic_cast<wxBitmapComboBox*>(window);
auto ww = dynamic_cast<choice_ctrl*>(window);
auto value = ww->GetValue();
ww->Clear();
ww->Append("");
@ -1077,7 +1082,7 @@ void Choice::set_values(const wxArrayString &values)
boost::any& Choice::get_value()
{
wxBitmapComboBox* field = dynamic_cast<wxBitmapComboBox*>(window);
choice_ctrl* field = dynamic_cast<choice_ctrl*>(window);
wxString ret_str = field->GetValue();
@ -1137,16 +1142,20 @@ boost::any& Choice::get_value()
return m_value;
}
void Choice::msw_rescale(bool rescale_sidetext/* = false*/)
void Choice::enable() { dynamic_cast<choice_ctrl*>(window)->Enable(); };
void Choice::disable() { dynamic_cast<choice_ctrl*>(window)->Disable(); };
void Choice::msw_rescale()
{
Field::msw_rescale();
wxBitmapComboBox* field = dynamic_cast<wxBitmapComboBox*>(window);
choice_ctrl* field = dynamic_cast<choice_ctrl*>(window);
#ifdef __WXOSX__
const wxString selection = field->GetValue();// field->GetString(index);
/* To correct scaling (set new controll size) of a wxBitmapCombobox
* we need to refill control with new bitmaps. So, in our case :
* 1. clear conrol
* 1. clear control
* 2. add content
* 3. add scaled "empty" bitmap to the at least one item
*/
@ -1179,6 +1188,16 @@ void Choice::msw_rescale(bool rescale_sidetext/* = false*/)
idx == m_opt.enum_values.size() ?
field->SetValue(selection) :
field->SetSelection(idx);
#else
auto size = wxSize(def_width_wider() * m_em_unit, wxDefaultCoord);
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 (parent_is_custom_ctrl)
field->SetSize(size);
else
field->SetMinSize(size);
#endif
}
void ColourPicker::BUILD()
@ -1195,6 +1214,8 @@ void ColourPicker::BUILD()
}
auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size);
if (parent_is_custom_ctrl && m_opt.height < 0)
opt_height = (double)temp->GetSize().GetHeight() / m_em_unit;
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
@ -1251,15 +1272,21 @@ boost::any& ColourPicker::get_value()
return m_value;
}
void ColourPicker::msw_rescale(bool rescale_sidetext/* = false*/)
void ColourPicker::msw_rescale()
{
Field::msw_rescale();
wxColourPickerCtrl* field = dynamic_cast<wxColourPickerCtrl*>(window);
auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord);
if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit);
if (m_opt.height >= 0)
size.SetHeight(m_opt.height * m_em_unit);
else if (parent_is_custom_ctrl && opt_height > 0)
size.SetHeight(lround(opt_height * m_em_unit));
if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit);
field->SetMinSize(size);
if (parent_is_custom_ctrl)
field->SetSize(size);
else
field->SetMinSize(size);
if (field->GetColour() == wxTransparentColour)
set_undef_value(field);
@ -1279,6 +1306,9 @@ void PointCtrl::BUILD()
x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, wxTE_PROCESS_ENTER);
y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, wxTE_PROCESS_ENTER);
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);
y_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font());
@ -1296,9 +1326,6 @@ void PointCtrl::BUILD()
temp->Add(static_text_y, 0, wxALIGN_CENTER_VERTICAL, 0);
temp->Add(y_textctrl);
// x_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), x_textctrl->GetId());
// y_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), y_textctrl->GetId());
x_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(x_textctrl); }), x_textctrl->GetId());
y_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(y_textctrl); }), y_textctrl->GetId());
@ -1312,14 +1339,21 @@ void PointCtrl::BUILD()
y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y));
}
void PointCtrl::msw_rescale(bool rescale_sidetext/* = false*/)
void PointCtrl::msw_rescale()
{
Field::msw_rescale();
const wxSize field_size(4 * m_em_unit, -1);
wxSize field_size(4 * m_em_unit, -1);
x_textctrl->SetMinSize(field_size);
y_textctrl->SetMinSize(field_size);
if (parent_is_custom_ctrl) {
field_size.SetHeight(lround(opt_height * m_em_unit));
x_textctrl->SetSize(field_size);
y_textctrl->SetSize(field_size);
}
else {
x_textctrl->SetMinSize(field_size);
y_textctrl->SetMinSize(field_size);
}
}
bool PointCtrl::value_was_changed(wxTextCtrl* win)
@ -1411,7 +1445,7 @@ void StaticText::BUILD()
temp->SetToolTip(get_tooltip_text(legend));
}
void StaticText::msw_rescale(bool rescale_sidetext/* = false*/)
void StaticText::msw_rescale()
{
Field::msw_rescale();

View file

@ -87,6 +87,8 @@ protected:
void on_set_focus(wxEvent& event);
/// Call the attached on_change method.
void on_change_field();
public:
/// Call the attached m_back_to_initial_value method.
void on_back_to_initial_value();
/// Call the attached m_back_to_sys_value method.
@ -119,6 +121,9 @@ public:
const t_config_option_key m_opt_id;//! {""};
int m_opt_idx = 0;
double opt_height{ 0.0 };
bool parent_is_custom_ctrl{ false };
/// Sets a value for this control.
/// subclasses should overload with a specific version
/// Postcondition: Method does not fire the on_change event.
@ -140,9 +145,6 @@ public:
void field_changed() { on_change_field(); }
// set icon to "UndoToSystemValue" button according to an inheritance of preset
// void set_nonsys_btn_icon(const wxBitmap& icon);
Field(const ConfigOptionDef& opt, const t_config_option_key& id) : m_opt(opt), m_opt_id(id) {};
Field(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : m_parent(parent), m_opt(opt), m_opt_id(id) {};
virtual ~Field();
@ -151,8 +153,6 @@ public:
virtual wxSizer* getSizer() { return nullptr; }
virtual wxWindow* getWindow() { return nullptr; }
wxStaticText* getLabel() { return m_Label; }
bool is_matched(const std::string& string, const std::string& pattern);
void get_value_by_opt_type(wxString& str, const bool check_value = true);
@ -168,7 +168,6 @@ public:
bool set_undo_bitmap(const ScalableBitmap *bmp) {
if (m_undo_bitmap != bmp) {
m_undo_bitmap = bmp;
m_Undo_btn->SetBitmap_(*bmp);
return true;
}
return false;
@ -177,33 +176,21 @@ 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);
return true;
}
return false;
}
bool set_label_colour(const wxColour *clr) {
if (m_Label == nullptr) return false;
if (m_label_color != clr) {
m_label_color = clr;
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);
return false;
}
bool set_undo_tooltip(const wxString *tip) {
if (m_undo_tooltip != tip) {
m_undo_tooltip = tip;
m_Undo_btn->SetToolTip(*tip);
return true;
}
return false;
@ -212,17 +199,16 @@ 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);
return true;
}
return false;
}
void set_side_text_ptr(wxStaticText* side_text) {
m_side_text = side_text;
bool* get_blink_ptr() {
return &m_blink;
}
virtual void msw_rescale(bool rescale_sidetext = false);
virtual void msw_rescale();
void sys_color_changed();
bool get_enter_pressed() const { return bEnterPressed; }
@ -233,26 +219,26 @@ public:
static int def_width_wider() ;
static int def_width_thinner() ;
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; }
const bool blink() { return m_blink; }
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.
const ScalableBitmap* m_undo_bitmap = nullptr;
const wxString* m_undo_tooltip = nullptr;
RevertButton* m_Undo_to_sys_btn = nullptr;
// Bitmap and Tooltip text for m_Undo_to_sys_btn. The wxButton will be updated only if the new wxBitmap pointer differs from the currently rendered one.
const ScalableBitmap* m_undo_to_sys_bitmap = nullptr;
const wxString* m_undo_to_sys_tooltip = nullptr;
BlinkingBitmap* m_blinking_bmp{ nullptr };
bool m_blink{ false };
wxStaticText* m_Label = nullptr;
// Color for Label. The wxColour will be updated only if the new wxColour pointer differs from the currently rendered one.
const wxColour* m_label_color = nullptr;
wxStaticText* m_side_text = nullptr;
// current value
boost::any m_value;
// last maeningful value
@ -308,7 +294,7 @@ public:
boost::any& get_value() override;
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override;
void disable() override;
@ -336,7 +322,7 @@ public:
void set_na_value() override;
boost::any& get_value() override;
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override { dynamic_cast<wxCheckBox*>(window)->Enable(); }
void disable() override { dynamic_cast<wxCheckBox*>(window)->Disable(); }
@ -379,7 +365,7 @@ public:
return m_value = value;
}
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override { dynamic_cast<wxSpinCtrl*>(window)->Enable(); }
void disable() override { dynamic_cast<wxSpinCtrl*>(window)->Disable(); }
@ -408,10 +394,10 @@ public:
void set_values(const wxArrayString &values);
boost::any& get_value() override;
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override { dynamic_cast<wxBitmapComboBox*>(window)->Enable(); };
void disable() override{ dynamic_cast<wxBitmapComboBox*>(window)->Disable(); };
void enable() override ;//{ dynamic_cast<wxBitmapComboBox*>(window)->Enable(); };
void disable() override;//{ dynamic_cast<wxBitmapComboBox*>(window)->Disable(); };
wxWindow* getWindow() override { return window; }
};
@ -434,7 +420,7 @@ public:
}
void set_value(const boost::any& value, bool change_event = false) override;
boost::any& get_value() override;
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override { dynamic_cast<wxColourPickerCtrl*>(window)->Enable(); };
void disable() override{ dynamic_cast<wxColourPickerCtrl*>(window)->Disable(); };
@ -460,7 +446,7 @@ public:
void set_value(const boost::any& value, bool change_event = false);
boost::any& get_value() override;
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override {
x_textctrl->Enable();
@ -495,7 +481,7 @@ public:
boost::any& get_value()override { return m_value; }
void msw_rescale(bool rescale_sidetext = false) override;
void msw_rescale() override;
void enable() override { dynamic_cast<wxStaticText*>(window)->Enable(); };
void disable() override{ dynamic_cast<wxStaticText*>(window)->Disable(); };

View file

@ -0,0 +1,646 @@
#include "OG_CustomCtrl.hpp"
#include "OptionsGroup.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
#include "libslic3r/AppConfig.hpp"
#include <wx/utils.h>
#include <boost/algorithm/string/split.hpp>
#include "libslic3r/Utils.hpp"
#include "I18N.hpp"
namespace Slic3r { namespace GUI {
static bool is_point_in_rect(const wxPoint& pt, const wxRect& rect)
{
return rect.GetLeft() <= pt.x && pt.x <= rect.GetRight() &&
rect.GetTop() <= pt.y && pt.y <= rect.GetBottom();
}
static wxSize get_bitmap_size(const wxBitmap& bmp)
{
#ifdef __APPLE__
return bmp.GetScaledSize();
#else
return bmp.GetSize();
#endif
}
static wxString get_url(const wxString& path_end, bool get_default = false)
{
if (path_end.IsEmpty())
return wxEmptyString;
wxString language = wxGetApp().app_config->get("translation_language");
wxString lang_marker = language.IsEmpty() ? "en" : language.BeforeFirst('_');
return wxString("https://help.prusa3d.com/") + lang_marker + "/article/" + path_end;
}
OG_CustomCtrl::OG_CustomCtrl( wxWindow* parent,
OptionsGroup* og,
const wxPoint& pos /* = wxDefaultPosition*/,
const wxSize& size/* = wxDefaultSize*/,
const wxValidator& val /* = wxDefaultValidator*/,
const wxString& name/* = wxEmptyString*/) :
wxPanel(parent, wxID_ANY, pos, size, /*wxWANTS_CHARS |*/ wxBORDER_NONE | wxTAB_TRAVERSAL),
opt_group(og)
{
if (!wxOSX)
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
m_font = wxGetApp().normal_font();
m_em_unit = em_unit(m_parent);
m_v_gap = lround(1.0 * m_em_unit);
m_h_gap = lround(0.2 * m_em_unit);
m_bmp_mode_sz = get_bitmap_size(create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12));
m_bmp_blinking_sz = get_bitmap_size(create_scaled_bitmap("search_blink", this));
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);
}
void OG_CustomCtrl::init_ctrl_lines()
{
const std::vector<Line>& og_lines = opt_group->get_lines();
for (const Line& line : og_lines)
{
if (line.full_width && (
// description line
line.widget != nullptr ||
// description line with widget (button)
!line.get_extra_widgets().empty())
)
continue;
const std::vector<Option>& option_set = line.get_options();
wxCoord height;
// if we have a single option with no label, no sidetext just add it directly to sizer
if (option_set.size() == 1 && opt_group->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_sz.GetHeight() + m_v_gap;
ctrl_lines.emplace_back(CtrlLine(height, this, line, true));
}
else if (opt_group->label_width != 0 && !line.label.IsEmpty())
{
wxSize label_sz = GetTextExtent(line.label);
height = label_sz.y * (label_sz.GetWidth() > int(opt_group->label_width * m_em_unit) ? 2 : 1) + m_v_gap;
ctrl_lines.emplace_back(CtrlLine(height, this, line));
}
else
int i = 0;
}
}
int OG_CustomCtrl::get_height(const Line& line)
{
for (auto ctrl_line : ctrl_lines)
if (&ctrl_line.og_line == &line)
return ctrl_line.height;
return 0;
}
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.og_line == &line)
{
h_pos = m_bmp_mode_sz.GetWidth() + m_h_gap;
if (line.near_label_widget_win) {
wxSize near_label_widget_sz = line.near_label_widget_win->GetSize();
if (field_in)
h_pos += near_label_widget_sz.GetWidth() + m_h_gap;
else
break;
}
wxString label = line.label;
if (opt_group->label_width != 0 && !label.IsEmpty())
h_pos += opt_group->label_width * m_em_unit + m_h_gap;
int blinking_button_width = m_bmp_blinking_sz.GetWidth() + m_h_gap;
if (line.widget) {
h_pos += blinking_button_width;
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 * blinking_button_width;
break;
}
for (auto opt : option_set) {
Field* field = opt_group->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 += ":";
wxPaintDC dc(this);
dc.SetFont(m_font);
h_pos += dc.GetMultiLineTextExtent(label).x + m_h_gap;
}
h_pos += 3 * blinking_button_width;
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() || opt_group->sidetext_width > 0)
h_pos += opt_group->sidetext_width * m_em_unit + m_h_gap;
if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
h_pos += lround(0.6 * m_em_unit);
}
break;
}
if (ctrl_line.is_visible)
v_pos += ctrl_line.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
// case, when custom controll is destroyed but doesn't deleted from the evet loop
if(!this->opt_group->custom_ctrl)
return;
wxPaintDC dc(this);
dc.SetFont(m_font);
wxCoord v_pos = 0;
for (CtrlLine& line : ctrl_lines) {
if (!line.is_visible)
continue;
line.render(dc, v_pos);
v_pos += line.height;
}
}
void OG_CustomCtrl::OnMotion(wxMouseEvent& event)
{
const wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
wxString tooltip;
wxString language = wxGetApp().app_config->get("translation_language");
for (CtrlLine& line : ctrl_lines) {
line.is_focused = is_point_in_rect(pos, line.rect_label);
if (line.is_focused) {
tooltip = get_url(line.og_line.label_path);
break;
}
for (size_t opt_idx = 0; opt_idx < line.rects_undo_icon.size(); opt_idx++)
if (is_point_in_rect(pos, line.rects_undo_icon[opt_idx])) {
const std::vector<Option>& option_set = line.og_line.get_options();
Field* field = opt_group->get_field(option_set[opt_idx].opt_id);
if (field)
tooltip = *field->undo_tooltip();
break;
}
for (size_t opt_idx = 0; opt_idx < line.rects_undo_to_sys_icon.size(); opt_idx++)
if (is_point_in_rect(pos, line.rects_undo_to_sys_icon[opt_idx])) {
const std::vector<Option>& option_set = line.og_line.get_options();
Field* field = opt_group->get_field(option_set[opt_idx].opt_id);
if (field)
tooltip = *field->undo_to_sys_tooltip();
break;
}
if (!tooltip.IsEmpty())
break;
}
// Set tooltips with information for each icon
this->SetToolTip(tooltip);
Refresh();
Update();
event.Skip();
}
void OG_CustomCtrl::OnLeftDown(wxMouseEvent& event)
{
const wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
for (const CtrlLine& line : ctrl_lines) {
if (line.launch_browser())
return;
for (size_t opt_idx = 0; opt_idx < line.rects_undo_icon.size(); opt_idx++)
if (is_point_in_rect(pos, line.rects_undo_icon[opt_idx])) {
const std::vector<Option>& option_set = line.og_line.get_options();
Field* field = opt_group->get_field(option_set[opt_idx].opt_id);
if (field)
field->on_back_to_initial_value();
event.Skip();
return;
}
for (size_t opt_idx = 0; opt_idx < line.rects_undo_to_sys_icon.size(); opt_idx++)
if (is_point_in_rect(pos, line.rects_undo_to_sys_icon[opt_idx])) {
const std::vector<Option>& option_set = line.og_line.get_options();
Field* field = opt_group->get_field(option_set[opt_idx].opt_id);
if (field)
field->on_back_to_sys_value();
event.Skip();
return;
}
}
}
bool OG_CustomCtrl::update_visibility(ConfigOptionMode mode)
{
wxCoord v_pos = 0;
size_t invisible_lines = 0;
for (CtrlLine& line : ctrl_lines) {
line.update_visibility(mode);
if (line.is_visible)
v_pos += (wxCoord)line.height;
else
invisible_lines++;
}
this->SetMinSize(wxSize(wxDefaultCoord, v_pos));
return invisible_lines != ctrl_lines.size();
}
void OG_CustomCtrl::correct_window_position(wxWindow* win, const Line& line, Field* field/* = nullptr*/)
{
wxPoint pos = get_pos(line, field);
int line_height = get_height(line);
pos.y += std::max(0, int(0.5 * (line_height - win->GetSize().y)));
win->SetPosition(pos);
};
void OG_CustomCtrl::correct_widgets_position(wxSizer* widget, const Line& line, Field* field/* = nullptr*/) {
auto children = widget->GetChildren();
wxPoint line_pos = get_pos(line, field);
int line_height = get_height(line);
for (auto child : children)
if (child->IsWindow()) {
wxPoint pos = line_pos;
wxSize sz = child->GetWindow()->GetSize();
pos.y += std::max(0, int(0.5 * (line_height - sz.y)));
child->GetWindow()->SetPosition(pos);
line_pos.x += sz.x + m_h_gap;
}
};
void OG_CustomCtrl::msw_rescale()
{
m_font = wxGetApp().normal_font();
m_em_unit = em_unit(m_parent);
m_v_gap = lround(1.0 * m_em_unit);
m_h_gap = lround(0.2 * m_em_unit);
m_bmp_mode_sz = create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12).GetSize();
m_bmp_blinking_sz = create_scaled_bitmap("search_blink", this).GetSize();
wxCoord v_pos = 0;
for (CtrlLine& line : ctrl_lines) {
line.msw_rescale();
if (line.is_visible)
v_pos += (wxCoord)line.height;
}
this->SetMinSize(wxSize(wxDefaultCoord, v_pos));
GetParent()->Layout();
}
void OG_CustomCtrl::sys_color_changed()
{
msw_rescale();
}
OG_CustomCtrl::CtrlLine::CtrlLine( wxCoord height,
OG_CustomCtrl* ctrl,
const Line& og_line,
bool draw_just_act_buttons /* = false*/):
height(height),
ctrl(ctrl),
og_line(og_line),
draw_just_act_buttons(draw_just_act_buttons)
{
for (size_t i = 0; i < og_line.get_options().size(); i++) {
rects_undo_icon.emplace_back(wxRect());
rects_undo_to_sys_icon.emplace_back(wxRect());
}
}
void OG_CustomCtrl::CtrlLine::correct_items_positions()
{
if (draw_just_act_buttons || !is_visible)
return;
if (og_line.near_label_widget_win)
ctrl->correct_window_position(og_line.near_label_widget_win, og_line);
if (og_line.widget_sizer)
ctrl->correct_widgets_position(og_line.widget_sizer, og_line);
if (og_line.extra_widget_sizer)
ctrl->correct_widgets_position(og_line.extra_widget_sizer, og_line);
const std::vector<Option>& option_set = og_line.get_options();
for (auto opt : option_set) {
Field* field = ctrl->opt_group->get_field(opt.opt_id);
if (!field)
continue;
if (field->getSizer())
ctrl->correct_widgets_position(field->getSizer(), og_line, field);
else if (field->getWindow())
ctrl->correct_window_position(field->getWindow(), og_line, field);
}
}
void OG_CustomCtrl::CtrlLine::msw_rescale()
{
// if we have a single option with no label, no sidetext
if (draw_just_act_buttons)
height = get_bitmap_size(create_scaled_bitmap("empty")).GetHeight();
if (ctrl->opt_group->label_width != 0 && !og_line.label.IsEmpty()) {
wxSize label_sz = ctrl->GetTextExtent(og_line.label);
height = label_sz.y * (label_sz.GetWidth() > int(ctrl->opt_group->label_width * ctrl->m_em_unit) ? 2 : 1) + ctrl->m_v_gap;
}
if (og_line.get_options().front().opt.full_width) {
Field* field = ctrl->opt_group->get_field(og_line.get_options().front().opt_id);
if (field->getWindow())
field->getWindow()->SetSize(wxSize(3 * Field::def_width_wider() * ctrl->m_em_unit, -1));
}
correct_items_positions();
}
void OG_CustomCtrl::CtrlLine::update_visibility(ConfigOptionMode mode)
{
const std::vector<Option>& option_set = og_line.get_options();
const ConfigOptionMode& line_mode = option_set.front().opt.mode;
is_visible = line_mode <= mode;
if (draw_just_act_buttons)
return;
if (og_line.near_label_widget_win)
og_line.near_label_widget_win->Show(is_visible);
if (og_line.widget_sizer)
og_line.widget_sizer->ShowItems(is_visible);
if (og_line.extra_widget_sizer)
og_line.extra_widget_sizer->ShowItems(is_visible);
for (auto opt : option_set) {
Field* field = ctrl->opt_group->get_field(opt.opt_id);
if (!field)
continue;
if (field->getSizer()) {
auto children = field->getSizer()->GetChildren();
for (auto child : children)
if (child->IsWindow())
child->GetWindow()->Show(is_visible);
}
else if (field->getWindow())
field->getWindow()->Show(is_visible);
}
correct_items_positions();
}
void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
{
Field* field = ctrl->opt_group->get_field(og_line.get_options().front().opt_id);
if (draw_just_act_buttons) {
if (field)
draw_act_bmps(dc, wxPoint(0, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink());
return;
}
wxCoord h_pos = draw_mode_bmp(dc, v_pos);
if (og_line.near_label_widget_win)
h_pos += og_line.near_label_widget_win->GetSize().x + ctrl->m_h_gap;
const std::vector<Option>& option_set = og_line.get_options();
wxString label = og_line.label;
bool is_url_string = false;
if (ctrl->opt_group->label_width != 0 && !label.IsEmpty()) {
const wxColour* text_clr = (option_set.size() == 1 && field ? field->label_color() : og_line.full_Label_color);
is_url_string = !og_line.label_path.IsEmpty();
h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label + ":", text_clr, ctrl->opt_group->label_width * ctrl->m_em_unit, is_url_string);
}
// If there's a widget, build it and set result to the correct position.
if (og_line.widget != nullptr) {
draw_blinking_bmp(dc, wxPoint(h_pos, v_pos), og_line.blink);
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 && og_line.get_extra_widgets().size() == 0)
{
if (field && field->undo_to_sys_bitmap())
draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink());
return;
}
size_t bmp_rect_id = 0;
for (const Option& opt : option_set) {
field = ctrl->opt_group->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 += ":";
if (is_url_string)
is_url_string = false;
else if(opt == option_set.front())
is_url_string = !og_line.label_path.IsEmpty();
h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label, field ? field->label_color() : nullptr, ctrl->opt_group->sublabel_width * ctrl->m_em_unit, is_url_string);
}
if (field && field->undo_to_sys_bitmap()) {
h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink(), bmp_rect_id++);
if (field->getSizer())
{
auto children = field->getSizer()->GetChildren();
for (auto child : children)
if (child->IsWindow())
h_pos += child->GetWindow()->GetSize().x + ctrl->m_h_gap;
}
else if (field->getWindow())
h_pos += field->getWindow()->GetSize().x + ctrl->m_h_gap;
}
// add field
if (option_set.size() == 1 && option_set.front().opt.full_width)
break;
// add sidetext if any
if (!option.sidetext.empty() || ctrl->opt_group->sidetext_width > 0)
h_pos = draw_text(dc, wxPoint(h_pos, v_pos), _(option.sidetext), nullptr, ctrl->opt_group->sidetext_width * ctrl->m_em_unit);
if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
h_pos += lround(0.6 * ctrl->m_em_unit);
}
}
wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos)
{
ConfigOptionMode mode = og_line.get_options()[0].opt.mode;
const std::string& bmp_name = mode == ConfigOptionMode::comSimple ? "mode_simple" :
mode == ConfigOptionMode::comAdvanced ? "mode_advanced" : "mode_expert";
wxBitmap bmp = create_scaled_bitmap(bmp_name, ctrl, wxOSX ? 10 : 12);
wxCoord y_draw = v_pos + lround((height - get_bitmap_size(bmp).GetHeight()) / 2);
dc.DrawBitmap(bmp, 0, y_draw);
return get_bitmap_size(bmp).GetWidth() + ctrl->m_h_gap;
}
wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width, bool is_url/* = false*/)
{
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';
}
if (!text.IsEmpty()) {
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((height - text_height) / 2);
if (width > 0 && is_url)
rect_label = wxRect(pos, wxSize(text_width, text_height));
wxColour old_clr = dc.GetTextForeground();
wxFont old_font = dc.GetFont();
if (is_focused && is_url)
// temporary workaround for the OSX because of strange Bold font behavior on BigSerf
#ifdef __APPLE__
dc.SetFont(old_font.Underlined());
#else
dc.SetFont(old_font.Bold().Underlined());
#endif
dc.SetTextForeground(color ? *color : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
dc.DrawText(out_text, pos);
dc.SetTextForeground(old_clr);
dc.SetFont(old_font);
if (width < 1)
width = text_width;
}
return pos.x + width + ctrl->m_h_gap;
}
wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking, size_t rect_id)
{
wxBitmap bmp_blinking = create_scaled_bitmap(is_blinking ? "search_blink" : "empty", ctrl);
wxCoord h_pos = pos.x;
wxCoord v_pos = pos.y + lround((height - get_bitmap_size(bmp_blinking).GetHeight()) / 2);
dc.DrawBitmap(bmp_blinking, h_pos, v_pos);
int bmp_dim = get_bitmap_size(bmp_blinking).GetWidth();
h_pos += bmp_dim + ctrl->m_h_gap;
return wxPoint(h_pos, v_pos);
}
wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id)
{
pos = draw_blinking_bmp(dc, pos, is_blinking, rect_id);
wxCoord h_pos = pos.x;
wxCoord v_pos = pos.y;
dc.DrawBitmap(bmp_undo_to_sys, h_pos, v_pos);
int bmp_dim = get_bitmap_size(bmp_undo_to_sys).GetWidth();
rects_undo_to_sys_icon[rect_id] = wxRect(h_pos, v_pos, bmp_dim, bmp_dim);
h_pos += bmp_dim + ctrl->m_h_gap;
dc.DrawBitmap(bmp_undo, h_pos, v_pos);
bmp_dim = get_bitmap_size(bmp_undo).GetWidth();
rects_undo_icon[rect_id] = wxRect(h_pos, v_pos, bmp_dim, bmp_dim);
h_pos += bmp_dim + ctrl->m_h_gap;
return h_pos;
}
bool OG_CustomCtrl::CtrlLine::launch_browser() const
{
return is_focused && !og_line.label_path.IsEmpty() && wxLaunchDefaultBrowser(get_url(og_line.label_path));
}
} // GUI
} // Slic3r

View file

@ -0,0 +1,99 @@
#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
namespace Slic3r { namespace GUI {
// Static text shown among the options.
class OG_CustomCtrl :public wxPanel
{
wxFont m_font;
int m_v_gap;
int m_h_gap;
int m_em_unit;
wxSize m_bmp_mode_sz;
wxSize m_bmp_blinking_sz;
struct CtrlLine {
wxCoord height { wxDefaultCoord };
OG_CustomCtrl* ctrl { nullptr };
const Line& og_line;
bool draw_just_act_buttons { false };
bool is_visible { true };
bool is_focused { false };
CtrlLine( wxCoord height,
OG_CustomCtrl* ctrl,
const Line& og_line,
bool draw_just_act_buttons = false);
~CtrlLine() { ctrl = nullptr; }
void correct_items_positions();
void msw_rescale();
void update_visibility(ConfigOptionMode mode);
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, bool is_url = false);
wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking, size_t rect_id = 0);
wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0);
bool launch_browser() const;
std::vector<wxRect> rects_undo_icon;
std::vector<wxRect> rects_undo_to_sys_icon;
wxRect rect_label;
};
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 init_ctrl_lines();
bool update_visibility(ConfigOptionMode mode);
void correct_window_position(wxWindow* win, const Line& line, Field* field = nullptr);
void correct_widgets_position(wxSizer* widget, const Line& line, Field* field = nullptr);
void msw_rescale();
void sys_color_changed();
wxPoint get_pos(const Line& line, Field* field = nullptr);
int get_height(const Line& line);
OptionsGroup* opt_group;
};
}}
#endif /* slic3r_OG_CustomCtrl_hpp_ */

View file

@ -2,6 +2,7 @@
#include "ConfigExceptions.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
#include "OG_CustomCtrl.hpp"
#include <utility>
#include <wx/numformatter.h>
@ -13,15 +14,15 @@
namespace Slic3r { namespace GUI {
const t_field& OptionsGroup::build_field(const Option& opt, wxStaticText* label/* = nullptr*/) {
return build_field(opt.opt_id, opt.opt, label);
const t_field& OptionsGroup::build_field(const Option& opt) {
return build_field(opt.opt_id, opt.opt);
}
const t_field& OptionsGroup::build_field(const t_config_option_key& id, wxStaticText* label/* = nullptr*/) {
const t_field& OptionsGroup::build_field(const t_config_option_key& id) {
const ConfigOptionDef& opt = m_options.at(id).opt;
return build_field(id, opt, label);
return build_field(id, opt);
}
const t_field& OptionsGroup::build_field(const t_config_option_key& id, const ConfigOptionDef& opt, wxStaticText* label/* = nullptr*/) {
const t_field& OptionsGroup::build_field(const t_config_option_key& id, const ConfigOptionDef& opt) {
// Check the gui_type field first, fall through
// is the normal type.
if (opt.gui_type.compare("select") == 0) {
@ -87,9 +88,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
this->on_set_focus(opt_id);
};
field->m_parent = parent();
//! Label to change background color, when option is modified
field->m_Label = label;
field->m_back_to_initial_value = [this](std::string opt_id) {
if (!m_disabled)
this->back_to_initial_value(opt_id);
@ -112,18 +111,44 @@ OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title,
{
}
void OptionsGroup::add_undo_buttons_to_sizer(wxSizer* sizer, const t_field& field)
void OptionsGroup::show_field(const t_config_option_key& opt_key, bool show/* = true*/)
{
if (!m_show_modified_btns) {
field->m_Undo_btn->set_as_hidden();
field->m_Undo_to_sys_btn->set_as_hidden();
field->m_blinking_bmp->Hide();
return;
}
Field* field = get_field(opt_key);
if (!field) return;
wxWindow* win = field->getWindow();
if (!win) return;
wxSizerItem* win_item = m_grid_sizer->GetItem(win, true);
if (!win_item) return;
sizer->Add(field->m_blinking_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 2);
sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL);
const size_t cols = (size_t)m_grid_sizer->GetCols();
const size_t rows = (size_t)m_grid_sizer->GetEffectiveRowsCount();
auto show_row = [this, show, cols, win_item](wxSizerItem* item, size_t row_shift) {
// check if item contanes required win
if (!item->IsWindow() || item != win_item)
return false;
// show/hide hole line contanes this window
for (size_t i = 0; i < cols; ++i)
m_grid_sizer->Show(row_shift + i, show);
return true;
};
size_t row_shift = 0;
for (size_t j = 0; j < rows; ++j) {
for (size_t i = 0; i < cols; ++i) {
wxSizerItem* item = m_grid_sizer->GetItem(row_shift + i);
if (!item)
continue;
if (item->IsSizer()) {
for (wxSizerItem* child_item : item->GetSizer()->GetChildren())
if (show_row(child_item, row_shift))
return;
}
else if (show_row(item, row_shift))
return;
}
row_shift += cols;
}
}
void OptionsGroup::append_line(const Line& line)
@ -147,11 +172,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 +196,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,114 +214,107 @@ 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 (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);
}
// Build a label if we have it
// 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;
#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;
#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);
if (custom_ctrl) {
if (line.near_label_widget)
line.near_label_widget_win = line.near_label_widget(this->ctrl_parent());
}
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);
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;
#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 if (!line.label.IsEmpty()) {
// 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());
// If widget doesn't have label, don't use border
grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5);
if (custom_ctrl)
line.widget_sizer = wgt;
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() &&
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
const auto& option = option_set.front();
const auto& field = build_field(option, label);
const auto& field = build_field(option);
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) {
if (is_window_field(field) && option.opt.full_width)
field->getWindow()->SetSize(wxSize(3 * Field::def_width_wider() * wxGetApp().em_unit(), -1));
}
else {
if (is_window_field(field))
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") :
@ -302,42 +328,41 @@ 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 (option_set.size() == 1 && option_set.front().opt.full_width)
{
const auto v_sizer = new wxBoxSizer(wxVERTICAL);
sizer_tmp->Add(v_sizer, 1, wxEXPAND);
auto& field = build_field(opt_ref);
if (!custom_ctrl) {
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);
break;
}
is_sizer_field(field) ?
v_sizer->Add(field->getSizer(), 0, wxEXPAND) :
v_sizer->Add(field->getWindow(), 0, wxEXPAND);
break;//return;
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 (!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);
sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT);
sidetext->SetFont(wxGetApp().normal_font());
sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
}
// add side widget if any
if (opt.side_widget != nullptr) {
sizer_tmp->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification
}
if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
sizer_tmp->AddSpacer(6);
}
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 (!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);
sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT);
sidetext->SetFont(wxGetApp().normal_font());
sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
field->set_side_text_ptr(sidetext);
}
// add side widget if any
if (opt.side_widget != nullptr) {
sizer_tmp->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification
}
if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
{
sizer_tmp->AddSpacer(6);
}
}
// add extra sizers if any
for (auto extra_widget : line.get_extra_widgets())
{
@ -350,7 +375,9 @@ void OptionsGroup::activate_line(Line& line)
return;
}
sizer->Add(extra_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification
line.extra_widget_sizer = extra_widget(this->ctrl_parent());
if (!custom_ctrl)
sizer->Add(line.extra_widget_sizer, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification
}
}
@ -405,7 +432,7 @@ bool OptionsGroup::activate(std::function<void()> throw_if_canceled)
return true;
}
// delete all controls from the option group
void OptionsGroup::clear()
void OptionsGroup::clear(bool destroy_custom_ctrl)
{
if (!sizer)
return;
@ -413,20 +440,43 @@ void OptionsGroup::clear()
m_grid_sizer = nullptr;
sizer = nullptr;
for (Line& line : m_lines)
if(line.full_Label)
*line.full_Label = nullptr;
for (Line& line : m_lines) {
if (line.near_label_widget_win)
line.near_label_widget_win = nullptr;
if (line.widget_sizer) {
line.widget_sizer->Clear(true);
line.widget_sizer = nullptr;
}
if (line.extra_widget_sizer) {
line.extra_widget_sizer->Clear(true);
line.extra_widget_sizer = nullptr;
}
}
if (custom_ctrl) {
for (auto const &item : m_fields) {
wxWindow* win = item.second.get()->getWindow();
if (win)
win = nullptr;
}
if (destroy_custom_ctrl)
custom_ctrl->Destroy();
else
custom_ctrl = nullptr;
}
m_extra_column_item_ptrs.clear();
m_near_label_widget_ptrs.clear();
m_fields.clear();
}
Line OptionsGroup::create_single_option_line(const Option& option) const {
Line OptionsGroup::create_single_option_line(const Option& option, const wxString& path/* = wxEmptyString*/) const {
// Line retval{ _(option.opt.label), _(option.opt.tooltip) };
wxString tooltip = _(option.opt.tooltip);
edit_tooltip(tooltip);
Line retval{ _(option.opt.label), tooltip };
retval.label_path = path;
Option tmp(option);
tmp.opt.label = std::string("");
retval.append_option(tmp);
@ -590,6 +640,13 @@ bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode)
{
if (m_options_mode.empty() || !m_grid_sizer)
return true;
if (custom_ctrl) {
bool show = custom_ctrl->update_visibility(mode);
this->Show(show);
return show;
}
int opt_mode_size = m_options_mode.size();
if (m_grid_sizer->GetEffectiveRowsCount() != opt_mode_size &&
opt_mode_size == 1)
@ -624,62 +681,55 @@ void ConfigOptionsGroup::msw_rescale()
for (auto extra_col : m_extra_column_item_ptrs)
rescale_extra_column_item(extra_col);
// update bitmaps for near label widgets (like "Set uniform scale" button on settings panel)
if (rescale_near_label_widget)
for (auto near_label_widget : m_near_label_widget_ptrs)
rescale_near_label_widget(near_label_widget);
// update undo buttons : rescale bitmaps
for (const auto& field : m_fields)
field.second->msw_rescale(sidetext_width>0);
field.second->msw_rescale();
const int em = em_unit(parent());
// rescale width of label column
if (m_grid_sizer && !m_options_mode.empty() && label_width > 1)
{
const int cols = m_grid_sizer->GetCols();
const int rows = m_grid_sizer->GetEffectiveRowsCount();
const int label_col = extra_column == nullptr ? 0 : 1;
for (int i = 0; i < rows; i++)
{
const wxSizerItem* label_item = m_grid_sizer->GetItem(i*cols+label_col);
if (label_item->IsWindow())
{
auto label = dynamic_cast<wxStaticText*>(label_item->GetWindow());
if (label != nullptr) {
label->SetMinSize(wxSize(label_width*em, -1));
auto rescale = [](wxSizer* sizer) {
for (wxSizerItem* item : sizer->GetChildren())
if (item->IsWindow()) {
wxWindow* win = item->GetWindow();
// check if window is ScalableButton
ScalableButton* sc_btn = dynamic_cast<ScalableButton*>(win);
if (sc_btn) {
sc_btn->msw_rescale();
sc_btn->SetSize(sc_btn->GetBestSize());
return;
}
// check if window is wxButton
wxButton* btn = dynamic_cast<wxButton*>(win);
if (btn) {
btn->SetSize(btn->GetBestSize());
return;
}
}
else if (label_item->IsSizer()) // case when we have near_label_widget
{
const wxSizerItem* l_item = label_item->GetSizer()->GetItem(1);
if (l_item->IsWindow())
{
auto label = dynamic_cast<wxStaticText*>(l_item->GetWindow());
if (label != nullptr) {
label->SetMinSize(wxSize(label_width*em, -1));
}
}
}
}
m_grid_sizer->Layout();
};
// scale widgets and extra widgets if any exists
for (const Line& line : m_lines) {
if (line.widget_sizer)
rescale(line.widget_sizer);
if (line.extra_widget_sizer)
rescale(line.extra_widget_sizer);
}
if (custom_ctrl)
custom_ctrl->msw_rescale();
}
void ConfigOptionsGroup::sys_color_changed()
{
// update bitmaps for near label widgets (like "Set uniform scale" button on settings panel)
if (rescale_near_label_widget)
for (auto near_label_widget : m_near_label_widget_ptrs)
rescale_near_label_widget(near_label_widget);
// update undo buttons : rescale bitmaps
for (const auto& field : m_fields)
field.second->sys_color_changed();
}
void ConfigOptionsGroup::refresh()
{
if (custom_ctrl)
custom_ctrl->Refresh();
}
boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize) {
if (deserialize) {
@ -858,6 +908,21 @@ Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int op
return opt_id.empty() ? nullptr : get_field(opt_id);
}
std::pair<OG_CustomCtrl*, bool*> ConfigOptionsGroup::get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/)
{
Field* field = get_fieldc(opt_key, opt_index);
if (field)
return {custom_ctrl, field->get_blink_ptr()};
for (Line& line : m_lines)
for (const Option& opt : line.get_options())
if (opt.opt_id == opt_key && line.widget)
return { custom_ctrl, line.get_blink_ptr() };
return { nullptr, nullptr };
}
// Change an option on m_config, possibly call ModelConfig::touch().
void ConfigOptionsGroup::change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/)

View file

@ -26,13 +26,11 @@ 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*)>;
//auto default_label_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); //GetSystemColour
//auto modified_label_clr = *new wxColour(254, 189, 101);
/// Wraps a ConfigOptionDef and adds function object for creating a side_widget.
struct Option {
ConfigOptionDef opt { ConfigOptionDef() };
@ -40,6 +38,10 @@ struct Option {
widget_t side_widget {nullptr};
bool readonly {false};
bool operator==(const Option& rhs) const {
return (rhs.opt_id == this->opt_id);
}
Option(const ConfigOptionDef& _opt, t_config_option_key id) :
opt(_opt), opt_id(id) {}
};
@ -48,12 +50,18 @@ using t_option = std::unique_ptr<Option>; //!
/// Represents option lines
class Line {
public:
wxString label {wxString("")};
wxString label_tooltip {wxString("")};
wxString label;
wxString label_tooltip;
wxString label_path;
size_t full_width {0};
wxStaticText** full_Label {nullptr};
wxColour* full_Label_color {nullptr};
bool blink {false};
widget_t widget {nullptr};
std::function<wxWindow*(wxWindow*)> near_label_widget{ nullptr };
wxWindow* near_label_widget_win {nullptr};
wxSizer* widget_sizer {nullptr};
wxSizer* extra_widget_sizer {nullptr};
void append_option(const Option& option) {
m_options.push_back(option);
@ -66,6 +74,7 @@ public:
const std::vector<widget_t>& get_extra_widgets() const {return m_extra_widgets;}
const std::vector<Option>& get_options() const { return m_options; }
bool* get_blink_ptr() { return &blink; }
private:
std::vector<Option> m_options;//! {std::vector<Option>()};
@ -84,6 +93,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 +129,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);
@ -129,10 +139,10 @@ public:
// create all controls for the option group from the m_lines
bool activate(std::function<void()> throw_if_canceled = [](){});
// delete all controls from the option group
void clear();
void clear(bool destroy_custom_ctrl = false);
Line create_single_option_line(const Option& option) const;
void append_single_option_line(const Option& option) { append_line(create_single_option_line(option)); }
Line create_single_option_line(const Option& option, const wxString& path = wxEmptyString) const;
void append_single_option_line(const Option& option, const wxString& path = wxEmptyString) { append_line(create_single_option_line(option, path)); }
// return a non-owning pointer reference
inline Field* get_field(const t_config_option_key& id) const{
@ -152,19 +162,7 @@ public:
return out;
}
bool set_side_text(const t_config_option_key& opt_key, const wxString& side_text) {
if (m_fields.find(opt_key) == m_fields.end()) return false;
auto st = m_fields.at(opt_key)->m_side_text;
if (!st) return false;
st->SetLabel(side_text);
return true;
}
void show_field(const t_config_option_key& opt_key, bool show = true) {
Field* field = get_field(opt_key);
field->getWindow()->Show(show);
field->getLabel()->Show(show);
}
void show_field(const t_config_option_key& opt_key, bool show = true);
void hide_field(const t_config_option_key& opt_key) { show_field(opt_key, false); }
void set_name(const wxString& new_name) {
@ -185,15 +183,16 @@ public:
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
column_t extra_clmn = nullptr);
~OptionsGroup() { clear(true); }
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};
std::vector<ConfigOptionMode> m_options_mode;
std::vector<wxWindow*> m_extra_column_item_ptrs;
std::vector<wxWindow*> m_near_label_widget_ptrs;
std::vector<Line> m_lines;
@ -206,6 +205,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.
@ -216,10 +218,9 @@ protected:
/// Generate a wxSizer or wxWindow from a configuration option
/// Precondition: opt resolves to a known ConfigOption
/// Postcondition: fields contains a wx gui object.
const t_field& build_field(const t_config_option_key& id, const ConfigOptionDef& opt, wxStaticText* label = nullptr);
const t_field& build_field(const t_config_option_key& id, wxStaticText* label = nullptr);
const t_field& build_field(const Option& opt, wxStaticText* label = nullptr);
void add_undo_buttons_to_sizer(wxSizer* sizer, const t_field& field);
const t_field& build_field(const t_config_option_key& id, const ConfigOptionDef& opt);
const t_field& build_field(const t_config_option_key& id);
const t_field& build_field(const Option& opt);
virtual void on_kill_focus(const std::string& opt_key) {};
virtual void on_set_focus(const std::string& opt_key);
@ -243,20 +244,20 @@ public:
void set_config_category(const std::string &category) { this->m_config_category = category; }
void set_config(DynamicPrintConfig* config) { m_config = config; m_modelconfig = nullptr; }
Option get_option(const std::string& opt_key, int opt_index = -1);
Line create_single_option_line(const std::string& title, int idx = -1) /*const*/{
Line create_single_option_line(const std::string& title, const wxString& path = wxEmptyString, int idx = -1) /*const*/{
Option option = get_option(title, idx);
return OptionsGroup::create_single_option_line(option);
return OptionsGroup::create_single_option_line(option, path);
}
Line create_single_option_line(const Option& option) const {
return OptionsGroup::create_single_option_line(option);
Line create_single_option_line(const Option& option, const wxString& path = wxEmptyString) const {
return OptionsGroup::create_single_option_line(option, path);
}
void append_single_option_line(const Option& option) {
OptionsGroup::append_single_option_line(option);
void append_single_option_line(const Option& option, const wxString& path = wxEmptyString) {
OptionsGroup::append_single_option_line(option, path);
}
void append_single_option_line(const std::string title, int idx = -1)
void append_single_option_line(const std::string title, const wxString& path = wxEmptyString, int idx = -1)
{
Option option = get_option(title, idx);
append_single_option_line(option);
append_single_option_line(option, path);
}
void on_change_OG(const t_config_option_key& opt_id, const boost::any& value) override;
@ -272,10 +273,12 @@ public:
bool update_visibility(ConfigOptionMode mode);
void msw_rescale();
void sys_color_changed();
void refresh();
boost::any config_value(const std::string& opt_key, int opt_index, bool deserialize);
// return option value from config
boost::any get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index = -1);
Field* get_fieldc(const t_config_option_key& opt_key, int opt_index);
std::pair<OG_CustomCtrl*, bool*> get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/);
private:
// Reference to libslic3r config or ModelConfig::get(), non-owning pointer.
@ -296,7 +299,6 @@ private:
class ogStaticText :public wxStaticText{
public:
ogStaticText() {}
// ogStaticText(wxWindow* parent, const char *text) : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize) {}
ogStaticText(wxWindow* parent, const wxString& text);
~ogStaticText() {}

View file

@ -433,6 +433,7 @@ void PhysicalPrinterDialog::update()
if (tech == ptFFF) {
m_optgroup->show_field("host_type");
m_optgroup->hide_field("printhost_authorization_type");
m_optgroup->show_field("printhost_apikey", true);
for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" })
m_optgroup->hide_field(opt_key);
const auto opt = m_config->option<ConfigOptionEnum<PrintHostType>>("host_type");
@ -452,7 +453,13 @@ void PhysicalPrinterDialog::update()
}
m_optgroup->show_field("printhost_port", supports_multiple_printers);
m_printhost_port_browse_btn->Show(supports_multiple_printers);
m_printhost_port_browse_btn->Show(supports_multiple_printers);
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
m_printhost_test_btn->Enable(!m_config->opt_string("print_host").empty() && host->can_test());
m_printhost_browse_btn->Enable(host->has_auto_discovery());
this->SetSize(this->GetBestSize());
this->Layout();
}

View file

@ -349,6 +349,8 @@ wxBitmap* PresetComboBox::get_bmp( std::string bitmap_key, bool wide_icons, con
bitmap_key += is_system ? ",syst" : ",nsyst";
bitmap_key += ",h" + std::to_string(icon_height);
if (wxGetApp().dark_mode())
bitmap_key += ",dark";
wxBitmap* bmp = bitmap_cache().find(bitmap_key);
if (bmp == nullptr) {
@ -393,6 +395,8 @@ wxBitmap* PresetComboBox::get_bmp( std::string bitmap_key, const std::string& m
bitmap_key += is_compatible ? ",cmpt" : ",ncmpt";
bitmap_key += is_system ? ",syst" : ",nsyst";
bitmap_key += ",h" + std::to_string(icon_height);
if (wxGetApp().dark_mode())
bitmap_key += ",dark";
wxBitmap* bmp = bitmap_cache().find(bitmap_key);
if (bmp == nullptr) {

View file

@ -12,6 +12,7 @@
#include "WipeTowerDialog.hpp"
#include "ButtonsDescription.hpp"
#include "Search.hpp"
#include "OG_CustomCtrl.hpp"
#include <wx/app.h>
#include <wx/button.h>
@ -52,40 +53,49 @@ wxDEFINE_EVENT(EVT_TAB_PRESETS_CHANGED, SimpleEvent);
void Tab::Highlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/)
{
timer.SetOwner(owner, timerid);
m_timer.SetOwner(owner, timerid);
}
void Tab::Highlighter::init(BlinkingBitmap* bmp)
void Tab::Highlighter::init(std::pair<OG_CustomCtrl*, bool*> params)
{
if (timer.IsRunning())
if (m_timer.IsRunning())
invalidate();
if (!bmp)
if (!params.first || !params.second)
return;
timer.Start(300, false);
m_timer.Start(300, false);
bbmp = bmp;
bbmp->activate();
m_custom_ctrl = params.first;
m_show_blink_ptr = params.second;
*m_show_blink_ptr = true;
m_custom_ctrl->Refresh();
}
void Tab::Highlighter::invalidate()
{
timer.Stop();
m_timer.Stop();
if (bbmp) {
bbmp->invalidate();
bbmp = nullptr;
if (m_custom_ctrl && m_show_blink_ptr) {
*m_show_blink_ptr = false;
m_custom_ctrl->Refresh();
m_show_blink_ptr = nullptr;
m_custom_ctrl = nullptr;
}
blink_counter = 0;
m_blink_counter = 0;
}
void Tab::Highlighter::blink()
{
if (!bbmp)
if (m_custom_ctrl && m_show_blink_ptr) {
*m_show_blink_ptr = !*m_show_blink_ptr;
m_custom_ctrl->Refresh();
}
else
return;
bbmp->blink();
if ((++blink_counter) == 11)
if ((++m_blink_counter) == 11)
invalidate();
}
@ -344,12 +354,6 @@ void Tab::create_preset_tab()
m_presets_choice->add_physical_printer();
});
// Fill cache for mode bitmaps
m_mode_bitmap_cache.reserve(3);
m_mode_bitmap_cache.push_back(ScalableBitmap(this, "mode_simple" , mode_icon_px_size()));
m_mode_bitmap_cache.push_back(ScalableBitmap(this, "mode_advanced", mode_icon_px_size()));
m_mode_bitmap_cache.push_back(ScalableBitmap(this, "mode_expert" , mode_icon_px_size()));
// Initialize the DynamicPrintConfig by default keys/values.
build();
@ -414,7 +418,7 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str
#else
auto panel = this;
#endif
PageShp page(new Page(/*panel*/m_page_view, title, icon_idx, m_mode_bitmap_cache));
PageShp page(new Page(m_page_view, title, icon_idx));
// page->SetBackgroundStyle(wxBG_STYLE_SYSTEM);
#ifdef __WINDOWS__
// page->SetDoubleBuffered(true);
@ -487,17 +491,14 @@ void Tab::update_labels_colour()
}
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
opt.first == "compatible_prints" || opt.first == "compatible_printers" ) {
wxStaticText* label = m_colored_Labels.find(opt.first) == m_colored_Labels.end() ? nullptr : m_colored_Labels.at(opt.first);
if (label) {
label->SetForegroundColour(*color);
label->Refresh(true);
}
if (m_colored_Label_colors.find(opt.first) != m_colored_Label_colors.end())
*m_colored_Label_colors.at(opt.first) = *color;
continue;
}
Field* field = get_field(opt.first);
if (field == nullptr) continue;
field->set_label_colour_force(color);
field->set_label_colour(color);
}
auto cur_item = m_treectrl->GetFirstVisibleItem();
@ -525,17 +526,18 @@ void Tab::decorate()
{
for (const auto opt : m_options_list)
{
wxStaticText* label = nullptr;
Field* field = nullptr;
Field* field = nullptr;
wxColour* colored_label_clr = nullptr;
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
opt.first == "compatible_prints" || opt.first == "compatible_printers")
label = (m_colored_Labels.find(opt.first) == m_colored_Labels.end()) ? nullptr : m_colored_Labels.at(opt.first);
opt.first == "compatible_prints" || opt.first == "compatible_printers")
colored_label_clr = (m_colored_Label_colors.find(opt.first) == m_colored_Label_colors.end()) ? nullptr : m_colored_Label_colors.at(opt.first);
if (!label)
if (!colored_label_clr) {
field = get_field(opt.first);
if (!label && !field)
continue;
if (!field)
continue;
}
bool is_nonsys_value = false;
bool is_modified_value = true;
@ -565,10 +567,9 @@ void Tab::decorate()
icon = &m_bmp_white_bullet;
tt = &m_tt_white_bullet;
}
if (label) {
label->SetForegroundColour(*color);
label->Refresh(true);
if (colored_label_clr) {
*colored_label_clr = *color;
continue;
}
@ -580,6 +581,9 @@ void Tab::decorate()
field->set_undo_to_sys_tooltip(sys_tt);
field->set_label_colour(color);
}
if (m_active_page)
m_active_page->refresh();
}
// Update UI according to changes
@ -664,6 +668,9 @@ void TabPrinter::msw_rescale()
for (auto page : pages)
page->msw_rescale();
if (m_reset_to_filament_color)
m_reset_to_filament_color->msw_rescale();
Layout();
}
@ -933,10 +940,9 @@ void Tab::msw_rescale()
btn->msw_rescale();
for (const auto bmp : m_scaled_bitmaps)
bmp->msw_rescale();
for (const auto ikon : m_blinking_ikons)
ikon.second->msw_rescale();
for (ScalableBitmap& bmp : m_mode_bitmap_cache)
bmp.msw_rescale();
if (m_detach_preset_btn)
m_detach_preset_btn->msw_rescale();
// rescale icons for tree_ctrl
for (ScalableBitmap& bmp : m_scaled_icons_list)
@ -958,14 +964,13 @@ void Tab::msw_rescale()
void Tab::sys_color_changed()
{
update_tab_ui();
m_presets_choice->msw_rescale();
// update buttons and cached bitmaps
for (const auto btn : m_scaled_buttons)
btn->msw_rescale();
for (const auto bmp : m_scaled_bitmaps)
bmp->msw_rescale();
// for (ScalableBitmap& bmp : m_mode_bitmap_cache)
// bmp.msw_rescale();
// update icons for tree_ctrl
for (ScalableBitmap& bmp : m_scaled_icons_list)
@ -992,14 +997,21 @@ void Tab::sys_color_changed()
Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const
{
return m_active_page ? m_active_page->get_field(opt_key, opt_index) : nullptr;
}
Field* field = nullptr;
for (auto page : m_pages) {
field = page->get_field(opt_key, opt_index);
if (field != nullptr)
return field;
std::pair<OG_CustomCtrl*, bool*> Tab::get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/)
{
if (!m_active_page)
return {nullptr, nullptr};
std::pair<OG_CustomCtrl*, bool*> ret = {nullptr, nullptr};
for (auto opt_group : m_active_page->m_optgroups) {
ret = opt_group->get_custom_ctrl_with_blinking_ptr(opt_key, opt_index);
if (ret.first && ret.second)
break;
}
return field;
return ret;
}
Field* Tab::get_field(const t_config_option_key& opt_key, Page** selected_page, int opt_index/* = -1*/)
@ -1141,25 +1153,19 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
Field* field = get_field(opt_key);
// focused selected field
if (field) {
if (field)
field->getWindow()->SetFocus();
m_highlighter.init(field->blinking_bitmap());
}
else if (category == "Single extruder MM setup")
{
else if (category == "Single extruder MM setup") {
// When we show and hide "Single extruder MM setup" page,
// related options are still in the search list
// So, let's hightlighte a "single_extruder_multi_material" option,
// as a "way" to show hidden page again
field = get_field("single_extruder_multi_material");
if (field) {
if (field)
field->getWindow()->SetFocus();
m_highlighter.init(field->blinking_bitmap());
}
}
else
m_highlighter.init(m_blinking_ikons[opt_key]);
m_highlighter.init(get_custom_ctrl_with_blinking_ptr(opt_key));
}
void Tab::apply_searcher()
@ -1219,7 +1225,6 @@ void Tab::build_preset_description_line(ConfigOptionsGroup* optgroup)
};
auto detach_preset_btn = [this](wxWindow* parent) {
//add_scaled_button(parent, &m_detach_preset_btn, "lock_open_sys", _(L("Detach from system preset")), wxBU_LEFT | wxBU_EXACTFIT);
m_detach_preset_btn = new ScalableButton(parent, wxID_ANY, "lock_open_sys", _L("Detach from system preset"),
wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT, true);
ScalableButton* btn = m_detach_preset_btn;
@ -1367,16 +1372,18 @@ void TabPrint::build()
load_initial_data();
auto page = add_options_page(L("Layers and perimeters"), "layers");
wxString category_path = "layers-and-perimeters_1748#";
auto optgroup = page->new_optgroup(L("Layer height"));
optgroup->append_single_option_line("layer_height");
optgroup->append_single_option_line("first_layer_height");
optgroup->append_single_option_line("layer_height", category_path + "layer-height");
optgroup->append_single_option_line("first_layer_height", category_path + "first-layer-height");
optgroup = page->new_optgroup(L("Vertical shells"));
optgroup->append_single_option_line("perimeters");
optgroup->append_single_option_line("spiral_vase");
optgroup->append_single_option_line("perimeters", category_path + "perimeters");
optgroup->append_single_option_line("spiral_vase", category_path + "spiral-vase");
Line line { "", "" };
line.full_width = 1;
line.label_path = category_path + "recommended-thin-wall-thickness";
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_recommended_thin_wall_thickness_description_line);
};
@ -1384,6 +1391,7 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Horizontal shells"));
line = { L("Solid layers"), "" };
line.label_path = category_path + "solid-layers-top-bottom";
line.append_option(optgroup->get_option("top_solid_layers"));
line.append_option(optgroup->get_option("bottom_solid_layers"));
optgroup->append_line(line);
@ -1399,22 +1407,23 @@ void TabPrint::build()
optgroup->append_line(line);
optgroup = page->new_optgroup(L("Quality (slower slicing)"));
optgroup->append_single_option_line("extra_perimeters");
optgroup->append_single_option_line("ensure_vertical_shell_thickness");
optgroup->append_single_option_line("avoid_crossing_perimeters");
optgroup->append_single_option_line("thin_walls");
optgroup->append_single_option_line("overhangs");
optgroup->append_single_option_line("extra_perimeters", category_path + "extra-perimeters-if-needed");
optgroup->append_single_option_line("ensure_vertical_shell_thickness", category_path + "ensure-vertical-shell-thickness");
optgroup->append_single_option_line("avoid_crossing_perimeters", category_path + "avoid-crossing-perimeters");
optgroup->append_single_option_line("thin_walls", category_path + "detect-thin-walls");
optgroup->append_single_option_line("overhangs", category_path + "detect-bridging-perimeters");
optgroup = page->new_optgroup(L("Advanced"));
optgroup->append_single_option_line("seam_position");
optgroup->append_single_option_line("external_perimeters_first");
optgroup->append_single_option_line("seam_position", category_path + "seam-position");
optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first");
page = add_options_page(L("Infill"), "infill");
category_path = "infill_42#";
optgroup = page->new_optgroup(L("Infill"));
optgroup->append_single_option_line("fill_density");
optgroup->append_single_option_line("fill_pattern");
optgroup->append_single_option_line("top_fill_pattern");
optgroup->append_single_option_line("bottom_fill_pattern");
optgroup->append_single_option_line("fill_density", category_path + "fill-density");
optgroup->append_single_option_line("fill_pattern", category_path + "fill-pattern");
optgroup->append_single_option_line("top_fill_pattern", category_path + "top-fill-pattern");
optgroup->append_single_option_line("bottom_fill_pattern", category_path + "bottom-fill-pattern");
optgroup = page->new_optgroup(L("Ironing"));
optgroup->append_single_option_line("ironing");
@ -1423,52 +1432,54 @@ void TabPrint::build()
optgroup->append_single_option_line("ironing_spacing");
optgroup = page->new_optgroup(L("Reducing printing time"));
optgroup->append_single_option_line("infill_every_layers");
optgroup->append_single_option_line("infill_only_where_needed");
optgroup->append_single_option_line("infill_every_layers", category_path + "combine-infill-every-x-layers");
optgroup->append_single_option_line("infill_only_where_needed", category_path + "only-infill-where-needed");
optgroup = page->new_optgroup(L("Advanced"));
optgroup->append_single_option_line("solid_infill_every_layers");
optgroup->append_single_option_line("fill_angle");
optgroup->append_single_option_line("solid_infill_below_area");
optgroup->append_single_option_line("solid_infill_every_layers", category_path + "solid-infill-every-x-layers");
optgroup->append_single_option_line("fill_angle", category_path + "fill-angle");
optgroup->append_single_option_line("solid_infill_below_area", category_path + "solid-infill-threshold-area");
optgroup->append_single_option_line("bridge_angle");
optgroup->append_single_option_line("only_retract_when_crossing_perimeters");
optgroup->append_single_option_line("infill_first");
page = add_options_page(L("Skirt and brim"), "skirt+brim");
category_path = "skirt-and-brim_133969#";
optgroup = page->new_optgroup(L("Skirt"));
optgroup->append_single_option_line("skirts");
optgroup->append_single_option_line("skirt_distance");
optgroup->append_single_option_line("skirt_height");
optgroup->append_single_option_line("draft_shield");
optgroup->append_single_option_line("min_skirt_length");
optgroup->append_single_option_line("skirts", category_path + "skirt");
optgroup->append_single_option_line("skirt_distance", category_path + "skirt");
optgroup->append_single_option_line("skirt_height", category_path + "skirt");
optgroup->append_single_option_line("draft_shield", category_path + "skirt");
optgroup->append_single_option_line("min_skirt_length", category_path + "skirt");
optgroup = page->new_optgroup(L("Brim"));
optgroup->append_single_option_line("brim_width");
optgroup->append_single_option_line("brim_width", category_path + "brim");
page = add_options_page(L("Support material"), "support");
category_path = "support-material_1698#";
optgroup = page->new_optgroup(L("Support material"));
optgroup->append_single_option_line("support_material");
optgroup->append_single_option_line("support_material_auto");
optgroup->append_single_option_line("support_material_threshold");
optgroup->append_single_option_line("support_material_enforce_layers");
optgroup->append_single_option_line("support_material", category_path + "generate-support-material");
optgroup->append_single_option_line("support_material_auto", category_path + "auto-generated-supports");
optgroup->append_single_option_line("support_material_threshold", category_path + "overhang-threshold");
optgroup->append_single_option_line("support_material_enforce_layers", category_path + "enforce-support-for-the-first");
optgroup = page->new_optgroup(L("Raft"));
optgroup->append_single_option_line("raft_layers");
optgroup->append_single_option_line("raft_layers", category_path + "raft-layers");
// # optgroup->append_single_option_line(get_option_("raft_contact_distance");
optgroup = page->new_optgroup(L("Options for support material and raft"));
optgroup->append_single_option_line("support_material_contact_distance");
optgroup->append_single_option_line("support_material_pattern");
optgroup->append_single_option_line("support_material_with_sheath");
optgroup->append_single_option_line("support_material_spacing");
optgroup->append_single_option_line("support_material_angle");
optgroup->append_single_option_line("support_material_interface_layers");
optgroup->append_single_option_line("support_material_interface_spacing");
optgroup->append_single_option_line("support_material_interface_contact_loops");
optgroup->append_single_option_line("support_material_buildplate_only");
optgroup->append_single_option_line("support_material_xy_spacing");
optgroup->append_single_option_line("dont_support_bridges");
optgroup->append_single_option_line("support_material_synchronize_layers");
optgroup->append_single_option_line("support_material_contact_distance", category_path + "contact-z-distance");
optgroup->append_single_option_line("support_material_pattern", category_path + "pattern");
optgroup->append_single_option_line("support_material_with_sheath", category_path + "with-sheath-around-the-support");
optgroup->append_single_option_line("support_material_spacing", category_path + "pattern-spacing-0-inf");
optgroup->append_single_option_line("support_material_angle", category_path + "pattern-angle");
optgroup->append_single_option_line("support_material_interface_layers", category_path + "interface-layers");
optgroup->append_single_option_line("support_material_interface_spacing", category_path + "interface-pattern-spacing");
optgroup->append_single_option_line("support_material_interface_contact_loops", category_path + "interface-loops");
optgroup->append_single_option_line("support_material_buildplate_only", category_path + "support-on-build-plate-only");
optgroup->append_single_option_line("support_material_xy_spacing", category_path + "xy-separation-between-an-object-and-its-support");
optgroup->append_single_option_line("dont_support_bridges", category_path + "dont-support-bridges");
optgroup->append_single_option_line("support_material_synchronize_layers", category_path + "synchronize-with-object-layers");
page = add_options_page(L("Speed"), "time");
optgroup = page->new_optgroup(L("Speed for print moves"));
@ -1498,8 +1509,8 @@ void TabPrint::build()
optgroup->append_single_option_line("default_acceleration");
optgroup = page->new_optgroup(L("Autospeed (advanced)"));
optgroup->append_single_option_line("max_print_speed");
optgroup->append_single_option_line("max_volumetric_speed");
optgroup->append_single_option_line("max_print_speed", "max-volumetric-speed_127176");
optgroup->append_single_option_line("max_volumetric_speed", "max-volumetric-speed_127176");
#ifdef HAS_PRESSURE_EQUALIZER
optgroup->append_single_option_line("max_volumetric_extrusion_rate_slope_positive");
optgroup->append_single_option_line("max_volumetric_extrusion_rate_slope_negative");
@ -1551,14 +1562,14 @@ void TabPrint::build()
optgroup->append_single_option_line("slice_closing_radius");
optgroup->append_single_option_line("resolution");
optgroup->append_single_option_line("xy_size_compensation");
optgroup->append_single_option_line("elefant_foot_compensation");
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");
optgroup = page->new_optgroup(L("Other"));
optgroup->append_single_option_line("clip_multipart_objects");
page = add_options_page(L("Output options"), "output+page_white");
optgroup = page->new_optgroup(L("Sequential printing"));
optgroup->append_single_option_line("complete_objects");
optgroup->append_single_option_line("complete_objects", "sequential-printing_124589");
line = { L("Extruder clearance (mm)"), "" };
line.append_option(optgroup->get_option("extruder_clearance_radius"));
line.append_option(optgroup->get_option("extruder_clearance_height"));
@ -1587,7 +1598,7 @@ void TabPrint::build()
page = add_options_page(L("Dependencies"), "wrench.png");
optgroup = page->new_optgroup(L("Profile dependencies"));
create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "compatible_printers", wxEmptyString, [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers);
});
@ -1787,6 +1798,7 @@ void TabFilament::build()
optgroup->append_line(line);
page = add_options_page(L("Cooling"), "cooling");
wxString category_path = "cooling_127569#";
optgroup = page->new_optgroup(L("Enable"));
optgroup->append_single_option_line("fan_always_on");
optgroup->append_single_option_line("cooling");
@ -1800,17 +1812,18 @@ void TabFilament::build()
optgroup = page->new_optgroup(L("Fan settings"));
line = { L("Fan speed"), "" };
line.label_path = category_path + "fan-settings";
line.append_option(optgroup->get_option("min_fan_speed"));
line.append_option(optgroup->get_option("max_fan_speed"));
optgroup->append_line(line);
optgroup->append_single_option_line("bridge_fan_speed");
optgroup->append_single_option_line("disable_fan_first_layers");
optgroup->append_single_option_line("bridge_fan_speed", category_path + "fan-settings");
optgroup->append_single_option_line("disable_fan_first_layers", category_path + "fan-settings");
optgroup = page->new_optgroup(L("Cooling thresholds"), 25);
optgroup->append_single_option_line("fan_below_layer_time");
optgroup->append_single_option_line("slowdown_below_layer_time");
optgroup->append_single_option_line("min_print_speed");
optgroup->append_single_option_line("fan_below_layer_time", category_path + "cooling-thresholds");
optgroup->append_single_option_line("slowdown_below_layer_time", category_path + "cooling-thresholds");
optgroup->append_single_option_line("min_print_speed", category_path + "cooling-thresholds");
page = add_options_page(L("Advanced"), "wrench");
optgroup = page->new_optgroup(L("Filament properties"));
@ -1821,7 +1834,7 @@ void TabFilament::build()
optgroup->append_single_option_line("filament_soluble");
optgroup = page->new_optgroup(L("Print speed override"));
optgroup->append_single_option_line("filament_max_volumetric_speed");
optgroup->append_single_option_line("filament_max_volumetric_speed", "max-volumetric-speed_127176");
line = { "", "" };
line.full_width = 1;
@ -1845,9 +1858,10 @@ void TabFilament::build()
optgroup->append_single_option_line("filament_cooling_initial_speed");
optgroup->append_single_option_line("filament_cooling_final_speed");
create_line_with_widget(optgroup.get(), "filament_ramming_parameters", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "filament_ramming_parameters", wxEmptyString, [this](wxWindow* parent) {
auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
ramming_dialog_btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
ramming_dialog_btn->SetSize(ramming_dialog_btn->GetBestSize());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(ramming_dialog_btn);
@ -1893,7 +1907,7 @@ void TabFilament::build()
page = add_options_page(L("Dependencies"), "wrench.png");
optgroup = page->new_optgroup(L("Profile dependencies"));
create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "compatible_printers", wxEmptyString, [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers);
});
@ -1901,7 +1915,7 @@ void TabFilament::build()
option.opt.full_width = true;
optgroup->append_single_option_line(option);
create_line_with_widget(optgroup.get(), "compatible_prints", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "compatible_prints", wxEmptyString, [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_prints);
});
@ -2057,7 +2071,7 @@ void TabPrinter::build_fff()
auto page = add_options_page(L("General"), "printer");
auto optgroup = page->new_optgroup(L("Size and coordinates"));
create_line_with_widget(optgroup.get(), "bed_shape", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "bed_shape", "custom-svg-and-png-bed-textures_124612", [this](wxWindow* parent) {
return create_bed_shape_widget(parent);
});
@ -2239,7 +2253,7 @@ void TabPrinter::build_sla()
auto page = add_options_page(L("General"), "printer");
auto optgroup = page->new_optgroup(L("Size and coordinates"));
create_line_with_widget(optgroup.get(), "bed_shape", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "bed_shape", "custom-svg-and-png-bed-textures_124612", [this](wxWindow* parent) {
return create_bed_shape_widget(parent);
});
optgroup->append_single_option_line("max_print_height");
@ -2490,7 +2504,7 @@ void TabPrinter::build_unregular_pages()
m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page);
auto optgroup = page->new_optgroup(L("Size"));
optgroup->append_single_option_line("nozzle_diameter", extruder_idx);
optgroup->append_single_option_line("nozzle_diameter", wxEmptyString, extruder_idx);
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
{
@ -2528,42 +2542,41 @@ void TabPrinter::build_unregular_pages()
};
optgroup = page->new_optgroup(L("Layer height limits"));
optgroup->append_single_option_line("min_layer_height", extruder_idx);
optgroup->append_single_option_line("max_layer_height", extruder_idx);
optgroup->append_single_option_line("min_layer_height", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("max_layer_height", wxEmptyString, extruder_idx);
optgroup = page->new_optgroup(L("Position (for multi-extruder printers)"));
optgroup->append_single_option_line("extruder_offset", extruder_idx);
optgroup->append_single_option_line("extruder_offset", wxEmptyString, extruder_idx);
optgroup = page->new_optgroup(L("Retraction"));
optgroup->append_single_option_line("retract_length", extruder_idx);
optgroup->append_single_option_line("retract_lift", extruder_idx);
optgroup->append_single_option_line("retract_length", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("retract_lift", wxEmptyString, extruder_idx);
Line line = { L("Only lift Z"), "" };
line.append_option(optgroup->get_option("retract_lift_above", extruder_idx));
line.append_option(optgroup->get_option("retract_lift_below", extruder_idx));
optgroup->append_line(line);
optgroup->append_single_option_line("retract_speed", extruder_idx);
optgroup->append_single_option_line("deretract_speed", extruder_idx);
optgroup->append_single_option_line("retract_restart_extra", extruder_idx);
optgroup->append_single_option_line("retract_before_travel", extruder_idx);
optgroup->append_single_option_line("retract_layer_change", extruder_idx);
optgroup->append_single_option_line("wipe", extruder_idx);
optgroup->append_single_option_line("retract_before_wipe", extruder_idx);
optgroup->append_single_option_line("retract_speed", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("deretract_speed", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("retract_restart_extra", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("retract_before_travel", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("retract_layer_change", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("wipe", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("retract_before_wipe", wxEmptyString, extruder_idx);
optgroup = page->new_optgroup(L("Retraction when tool is disabled (advanced settings for multi-extruder setups)"));
optgroup->append_single_option_line("retract_length_toolchange", extruder_idx);
optgroup->append_single_option_line("retract_restart_extra_toolchange", extruder_idx);
optgroup->append_single_option_line("retract_length_toolchange", wxEmptyString, extruder_idx);
optgroup->append_single_option_line("retract_restart_extra_toolchange", wxEmptyString, extruder_idx);
optgroup = page->new_optgroup(L("Preview"));
auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) {
//add_scaled_button(parent, &m_reset_to_filament_color, "undo",
// _(L("Reset to Filament Color")), wxBU_LEFT | wxBU_EXACTFIT);
m_reset_to_filament_color = new ScalableButton(parent, wxID_ANY, "undo", _L("Reset to Filament Color"),
wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT, true);
ScalableButton* btn = m_reset_to_filament_color;
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
btn->SetSize(btn->GetBestSize());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
@ -2582,7 +2595,7 @@ void TabPrinter::build_unregular_pages()
return sizer;
};
line = optgroup->create_single_option_line("extruder_colour", extruder_idx);
line = optgroup->create_single_option_line("extruder_colour", wxEmptyString, extruder_idx);
line.append_widget(reset_to_filament_color);
optgroup->append_line(line);
@ -2656,6 +2669,16 @@ void TabPrinter::update_pages()
rebuild_page_tree();
}
void TabPrinter::reload_config()
{
Tab::reload_config();
// "extruders_count" doesn't update from the update_config(),
// so update it implicitly
if (m_active_page && m_active_page->title() == "General")
m_active_page->set_value("extruders_count", int(m_extruders_count));
}
void TabPrinter::activate_selected_page(std::function<void()> throw_if_canceled)
{
Tab::activate_selected_page(throw_if_canceled);
@ -3207,8 +3230,6 @@ void Tab::clear_pages()
m_compatible_prints.checkbox = nullptr;
m_compatible_prints.btn = nullptr;
m_blinking_ikons.clear();
}
void Tab::update_description_lines()
@ -3491,13 +3512,15 @@ void Tab::update_ui_from_settings()
}
}
void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, widget_t widget)
void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const wxString& path, widget_t widget)
{
Line line = optgroup->create_single_option_line(opt_key);
line.widget = widget;
line.label_path = path;
m_colored_Label_colors[opt_key] = &m_default_text_clr;
line.full_Label_color = m_colored_Label_colors[opt_key];
m_colored_Labels[opt_key] = nullptr;
line.full_Label = &m_colored_Labels[opt_key];
optgroup->append_line(line);
}
@ -3506,14 +3529,12 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
{
deps.checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All")));
deps.checkbox->SetFont(Slic3r::GUI::wxGetApp().normal_font());
deps.btn = new ScalableButton(parent, wxID_ANY, "printer_white", from_u8((boost::format(" %s %s") % _utf8(L("Set")) % std::string(dots.ToUTF8())).str()),
deps.btn = new ScalableButton(parent, wxID_ANY, "printer", from_u8((boost::format(" %s %s") % _utf8(L("Set")) % std::string(dots.ToUTF8())).str()),
wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT, true);
deps.btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
BlinkingBitmap* bbmp = new BlinkingBitmap(parent);
deps.btn->SetSize(deps.btn->GetBestSize());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(bbmp, 0, wxALIGN_CENTER_VERTICAL);
sizer->Add((deps.checkbox), 0, wxALIGN_CENTER_VERTICAL);
sizer->Add((deps.btn), 0, wxALIGN_CENTER_VERTICAL);
@ -3574,25 +3595,18 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
}
}));
// fill m_blinking_ikons map with options
{
m_blinking_ikons[deps.key_list] = bbmp;
}
return sizer;
}
// Return a callback to create a TabPrinter widget to edit bed shape
wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
{
ScalableButton* btn = new ScalableButton(parent, wxID_ANY, "printer_white", " " + _(L("Set")) + " " + dots,
ScalableButton* btn = new ScalableButton(parent, wxID_ANY, "printer", " " + _(L("Set")) + " " + dots,
wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT, true);
btn->SetFont(wxGetApp().normal_font());
BlinkingBitmap* bbmp = new BlinkingBitmap(parent);
btn->SetSize(btn->GetBestSize());
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(bbmp, 0, wxALIGN_CENTER_VERTICAL);
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL);
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
@ -3624,12 +3638,6 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
searcher.add_key("bed_custom_model", gc.group, gc.category);
}
// fill m_blinking_ikons map with options
{
for (const std::string opt : {"bed_shape", "bed_custom_texture", "bed_custom_model"})
m_blinking_ikons[opt] = bbmp;
}
return sizer;
}
@ -3742,11 +3750,10 @@ void Tab::set_tooltips_text()
"Click to reset current value to the last saved preset."));
}
Page::Page(wxWindow* parent, const wxString& title, const int iconID, const std::vector<ScalableBitmap>& mode_bmp_cache) :
Page::Page(wxWindow* parent, const wxString& title, int iconID) :
m_parent(parent),
m_title(title),
m_iconID(iconID),
m_mode_bitmap_cache(mode_bmp_cache)
m_iconID(iconID)
{
m_vsizer = (wxBoxSizer*)parent->GetSizer();
m_item_color = &wxGetApp().get_label_clr_default();
@ -3801,6 +3808,12 @@ void Page::sys_color_changed()
group->sys_color_changed();
}
void Page::refresh()
{
for (auto group : m_optgroups)
group->refresh();
}
Field* Page::get_field(const t_config_option_key& opt_key, int opt_index /*= -1*/) const
{
Field* field = nullptr;
@ -3824,22 +3837,8 @@ bool Page::set_value(const t_config_option_key& opt_key, const boost::any& value
// package Slic3r::GUI::Tab::Page;
ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_label_width /*= -1*/)
{
auto extra_column = [this](wxWindow* parent, const Line& line)
{
std::string bmp_name;
const std::vector<Option>& options = line.get_options();
int mode_id = int(options[0].opt.mode);
const wxBitmap& bitmap = options.size() == 0 || options[0].opt.gui_type == "legend" ? wxNullBitmap :
m_mode_bitmap_cache[mode_id].bmp();
auto bmp = new wxStaticBitmap(parent, wxID_ANY, bitmap);
bmp->SetClientData((void*)&m_mode_bitmap_cache[mode_id]);
bmp->SetBackgroundStyle(wxBG_STYLE_PAINT);
return bmp;
};
//! config_ have to be "right"
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(/*this*/m_parent, title, m_config, true, extra_column);
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(m_parent, title, m_config, true);
optgroup->set_config_category(m_title.ToStdString());
if (noncommon_label_width >= 0)
optgroup->label_width = noncommon_label_width;
@ -3959,7 +3958,7 @@ void TabSLAMaterial::build()
page = add_options_page(L("Dependencies"), "wrench.png");
optgroup = page->new_optgroup(L("Profile dependencies"));
create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "compatible_printers", wxEmptyString, [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers);
});
@ -3967,7 +3966,7 @@ void TabSLAMaterial::build()
option.opt.full_width = true;
optgroup->append_single_option_line(option);
create_line_with_widget(optgroup.get(), "compatible_prints", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "compatible_prints", wxEmptyString, [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_prints);
});
@ -4090,7 +4089,7 @@ void TabSLAPrint::build()
page = add_options_page(L("Dependencies"), "wrench");
optgroup = page->new_optgroup(L("Profile dependencies"));
create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) {
create_line_with_widget(optgroup.get(), "compatible_printers", wxEmptyString, [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers);
});

View file

@ -40,6 +40,7 @@ namespace Slic3r {
namespace GUI {
class TabPresetComboBox;
class OG_CustomCtrl;
// Single Tab page containing a{ vsizer } of{ optgroups }
// package Slic3r::GUI::Tab::Page;
@ -52,16 +53,12 @@ class Page// : public wxScrolledWindow
wxBoxSizer* m_vsizer;
bool m_show = true;
public:
Page(wxWindow* parent, const wxString& title, const int iconID,
const std::vector<ScalableBitmap>& mode_bmp_cache);
Page(wxWindow* parent, const wxString& title, int iconID);
~Page() {}
bool m_is_modified_values{ false };
bool m_is_nonsys_values{ true };
// Delayed layout after resizing the main window.
const std::vector<ScalableBitmap>& m_mode_bitmap_cache;
public:
std::vector <ConfigOptionsGroupShp> m_optgroups;
DynamicPrintConfig* m_config;
@ -77,6 +74,7 @@ public:
void clear();
void msw_rescale();
void sys_color_changed();
void refresh();
Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const;
bool set_value(const t_config_option_key& opt_key, const boost::any& value);
ConfigOptionsGroupShp new_optgroup(const wxString& title, int noncommon_label_width = -1);
@ -170,7 +168,6 @@ protected:
std::vector<ScalableButton*> m_scaled_buttons = {};
std::vector<ScalableBitmap*> m_scaled_bitmaps = {};
std::vector<ScalableBitmap> m_scaled_icons_list = {};
std::vector<ScalableBitmap> m_mode_bitmap_cache = {};
// Colors for ui "decoration"
wxColour m_sys_label_clr;
@ -225,15 +222,15 @@ protected:
struct Highlighter
{
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY);
void init(BlinkingBitmap* bmp);
void init(std::pair<OG_CustomCtrl*, bool*>);
void blink();
void invalidate();
private:
BlinkingBitmap* bbmp {nullptr};
int blink_counter {0};
wxTimer timer;
OG_CustomCtrl* m_custom_ctrl {nullptr};
bool* m_show_blink_ptr{nullptr};
int m_blink_counter {0};
wxTimer m_timer;
}
m_highlighter;
@ -251,13 +248,9 @@ public:
ogStaticText* m_parent_preset_description_line = nullptr;
ScalableButton* m_detach_preset_btn = nullptr;
// map of option name -> wxStaticText (colored label, associated with option)
// map of option name -> wxColour (color of the colored label, associated with option)
// Used for options which don't have corresponded field
std::map<std::string, wxStaticText*> m_colored_Labels;
// map of option name -> BlinkingBitmap (blinking ikon, associated with option)
// Used for options which don't have corresponded field
std::map<std::string, BlinkingBitmap*> m_blinking_ikons;
std::map<std::string, wxColour*> m_colored_Label_colors;
// Counter for the updating (because of an update() function can have a recursive behavior):
// 1. increase value from the very beginning of an update() function
@ -333,6 +326,8 @@ public:
virtual void msw_rescale();
virtual void sys_color_changed();
Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const;
std::pair<OG_CustomCtrl*, bool*> get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index = -1);
Field* get_field(const t_config_option_key &opt_key, Page** selected_page, int opt_index = -1);
void toggle_option(const std::string& opt_key, bool toggle, int opt_index = -1);
wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString);
@ -352,7 +347,7 @@ public:
const std::map<wxString, std::string>& get_category_icon_map() { return m_category_icon; }
protected:
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, widget_t widget);
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const wxString& path, widget_t widget);
wxSizer* compatible_widget_create(wxWindow* parent, PresetDependencies &deps);
void compatible_widget_reload(PresetDependencies &deps);
void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false);
@ -454,6 +449,7 @@ public:
void build_print_host_upload_group(Page* page);
void build_fff();
void build_sla();
void reload_config() override;
void activate_selected_page(std::function<void()> throw_if_canceled) override;
void clear_pages() override;
void toggle_options() override;

View file

@ -348,6 +348,8 @@ public:
void activate();
void blink();
const wxBitmap& get_bmp() const { return bmp.bmp(); }
private:
ScalableBitmap bmp;
bool show {false};