2017-12-13 13:45:10 +00:00
|
|
|
#ifndef SLIC3R_GUI_FIELD_HPP
|
|
|
|
#define SLIC3R_GUI_FIELD_HPP
|
|
|
|
|
|
|
|
#include <wx/wxprec.h>
|
|
|
|
#ifndef WX_PRECOMP
|
|
|
|
#include <wx/wx.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <functional>
|
|
|
|
#include <boost/any.hpp>
|
|
|
|
|
2017-12-18 12:58:51 +00:00
|
|
|
#include <wx/spinctrl.h>
|
2017-12-22 10:50:28 +00:00
|
|
|
#include <wx/clrpicker.h>
|
2017-12-18 12:58:51 +00:00
|
|
|
|
2017-12-13 13:45:10 +00:00
|
|
|
#include "../../libslic3r/libslic3r.h"
|
|
|
|
#include "../../libslic3r/Config.hpp"
|
|
|
|
|
|
|
|
//#include "slic3r_gui.hpp"
|
|
|
|
#include "GUI.hpp"
|
2018-03-06 08:44:53 +00:00
|
|
|
#include "Utils.hpp"
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-03-06 12:34:39 +00:00
|
|
|
#ifdef __WXMSW__
|
|
|
|
#define wxMSW true
|
|
|
|
#else
|
|
|
|
#define wxMSW false
|
|
|
|
#endif
|
|
|
|
|
2017-12-13 13:45:10 +00:00
|
|
|
namespace Slic3r { namespace GUI {
|
|
|
|
|
|
|
|
class Field;
|
|
|
|
using t_field = std::unique_ptr<Field>;
|
2018-01-31 13:59:44 +00:00
|
|
|
using t_kill_focus = std::function<void()>;
|
2018-01-05 14:11:33 +00:00
|
|
|
using t_change = std::function<void(t_config_option_key, boost::any)>;
|
2018-03-06 11:34:20 +00:00
|
|
|
using t_back_to_init = std::function<void(std::string)>;
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-02-19 08:15:15 +00:00
|
|
|
wxString double_to_string(double const value);
|
|
|
|
|
2017-12-26 22:04:54 +00:00
|
|
|
class Field {
|
2017-12-18 12:58:51 +00:00
|
|
|
protected:
|
2017-12-13 13:45:10 +00:00
|
|
|
// factory function to defer and enforce creation of derived type.
|
2018-03-06 11:34:20 +00:00
|
|
|
virtual void PostInitialize();
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Finish constructing the Field's wxWidget-related properties, including setting its own sizer, etc.
|
2018-01-31 15:46:17 +00:00
|
|
|
virtual void BUILD() = 0;
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Call the attached on_kill_focus method.
|
2018-01-31 13:59:44 +00:00
|
|
|
//! It's important to use wxEvent instead of wxFocusEvent,
|
|
|
|
//! in another case we can't unfocused control at all
|
2018-01-31 15:46:17 +00:00
|
|
|
void on_kill_focus(wxEvent& event);
|
2017-12-13 13:45:10 +00:00
|
|
|
/// Call the attached on_change method.
|
2018-01-31 15:46:17 +00:00
|
|
|
void on_change_field();
|
2018-03-06 11:34:20 +00:00
|
|
|
/// Call the attached m_back_to_initial_value method.
|
|
|
|
void on_back_to_initial_value();
|
2018-03-16 16:25:11 +00:00
|
|
|
/// Call the attached m_back_to_sys_value method.
|
|
|
|
void on_back_to_sys_value();
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2017-12-26 22:04:54 +00:00
|
|
|
public:
|
2017-12-13 13:45:10 +00:00
|
|
|
/// parent wx item, opportunity to refactor (probably not necessary - data duplication)
|
2018-01-05 14:11:33 +00:00
|
|
|
wxWindow* m_parent {nullptr};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Function object to store callback passed in from owning object.
|
2018-01-31 13:59:44 +00:00
|
|
|
t_kill_focus m_on_kill_focus {nullptr};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Function object to store callback passed in from owning object.
|
2018-01-05 14:11:33 +00:00
|
|
|
t_change m_on_change {nullptr};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-03-16 16:25:11 +00:00
|
|
|
/// Function object to store callback passed in from owning object.
|
2018-03-06 11:34:20 +00:00
|
|
|
t_back_to_init m_back_to_initial_value{ nullptr };
|
2018-03-16 16:25:11 +00:00
|
|
|
t_back_to_init m_back_to_sys_value{ nullptr };
|
2018-03-06 11:34:20 +00:00
|
|
|
|
2018-01-27 16:39:00 +00:00
|
|
|
// This is used to avoid recursive invocation of the field change/update by wxWidgets.
|
2018-01-05 14:11:33 +00:00
|
|
|
bool m_disable_change_event {false};
|
2018-03-07 14:05:41 +00:00
|
|
|
bool m_is_modified_value {false};
|
2018-03-16 16:25:11 +00:00
|
|
|
bool m_is_nonsys_value {true};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Copy of ConfigOption for deduction purposes
|
2018-01-05 14:11:33 +00:00
|
|
|
const ConfigOptionDef m_opt {ConfigOptionDef()};
|
|
|
|
const t_config_option_key m_opt_id;//! {""};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Sets a value for this control.
|
|
|
|
/// subclasses should overload with a specific version
|
|
|
|
/// Postcondition: Method does not fire the on_change event.
|
2018-03-15 17:06:26 +00:00
|
|
|
virtual void set_value(boost::any value, bool change_event) = 0;
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Gets a boost::any representing this control.
|
|
|
|
/// subclasses should overload with a specific version
|
2018-01-05 14:11:33 +00:00
|
|
|
virtual boost::any get_value() = 0;
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-01-05 14:11:33 +00:00
|
|
|
virtual void enable() = 0;
|
|
|
|
virtual void disable() = 0;
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-03-02 08:08:11 +00:00
|
|
|
wxStaticText* m_Label = nullptr;
|
2018-03-06 08:44:53 +00:00
|
|
|
wxButton* m_Undo_btn = nullptr;
|
2018-03-15 08:55:31 +00:00
|
|
|
wxButton* m_Undo_to_sys_btn = nullptr;
|
2018-03-02 08:08:11 +00:00
|
|
|
|
2017-12-13 13:45:10 +00:00
|
|
|
/// Fires the enable or disable function, based on the input.
|
2018-01-05 14:11:33 +00:00
|
|
|
inline void toggle(bool en) { en ? enable() : disable(); }
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-01-27 13:21:16 +00:00
|
|
|
virtual wxString get_tooltip_text(const wxString& default_string);
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-03-16 11:56:03 +00:00
|
|
|
// set icon to "UndoToSystemValue" button according to an inheritance of preset
|
|
|
|
void set_nonsys_btn_icon(const std::string& icon);
|
|
|
|
|
2018-01-05 14:11:33 +00:00
|
|
|
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) {};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// If you don't know what you are getting back, check both methods for nullptr.
|
2018-01-05 14:11:33 +00:00
|
|
|
virtual wxSizer* getSizer() { return nullptr; }
|
|
|
|
virtual wxWindow* getWindow() { return nullptr; }
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2017-12-18 12:58:51 +00:00
|
|
|
bool is_matched(std::string string, std::string pattern);
|
2018-03-02 08:08:11 +00:00
|
|
|
boost::any get_value_by_opt_type(wxString str);
|
2017-12-13 13:45:10 +00:00
|
|
|
|
|
|
|
/// Factory method for generating new derived classes.
|
|
|
|
template<class T>
|
|
|
|
static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) // interface for creating shared objects
|
|
|
|
{
|
2018-01-21 20:42:06 +00:00
|
|
|
auto p = Slic3r::make_unique<T>(parent, opt, id);
|
2017-12-13 13:45:10 +00:00
|
|
|
p->PostInitialize();
|
2017-12-18 12:58:51 +00:00
|
|
|
return std::move(p); //!p;
|
2017-12-13 13:45:10 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Convenience function, accepts a const reference to t_field and checks to see whether
|
|
|
|
/// or not both wx pointers are null.
|
|
|
|
inline bool is_bad_field(const t_field& obj) { return obj->getSizer() == nullptr && obj->getWindow() == nullptr; }
|
|
|
|
|
|
|
|
/// Covenience function to determine whether this field is a valid window field.
|
|
|
|
inline bool is_window_field(const t_field& obj) { return !is_bad_field(obj) && obj->getWindow() != nullptr; }
|
|
|
|
|
|
|
|
/// Covenience function to determine whether this field is a valid sizer field.
|
|
|
|
inline bool is_sizer_field(const t_field& obj) { return !is_bad_field(obj) && obj->getSizer() != nullptr; }
|
|
|
|
|
|
|
|
class TextCtrl : public Field {
|
|
|
|
using Field::Field;
|
|
|
|
public:
|
2017-12-18 12:58:51 +00:00
|
|
|
TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
|
|
|
TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
|
|
|
|
2017-12-13 13:45:10 +00:00
|
|
|
void BUILD();
|
|
|
|
wxWindow* window {nullptr};
|
|
|
|
|
2018-03-15 17:06:26 +00:00
|
|
|
virtual void set_value(std::string value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2017-12-13 13:45:10 +00:00
|
|
|
dynamic_cast<wxTextCtrl*>(window)->SetValue(wxString(value));
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-13 13:45:10 +00:00
|
|
|
}
|
2018-03-15 17:06:26 +00:00
|
|
|
virtual void set_value(boost::any value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2018-01-09 08:41:07 +00:00
|
|
|
dynamic_cast<wxTextCtrl*>(window)->SetValue(boost::any_cast<wxString>(value));
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-13 13:45:10 +00:00
|
|
|
}
|
|
|
|
|
2018-01-09 12:52:01 +00:00
|
|
|
boost::any get_value() override;
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2018-01-09 12:52:01 +00:00
|
|
|
virtual void enable();
|
|
|
|
virtual void disable();
|
2017-12-26 22:04:54 +00:00
|
|
|
virtual wxWindow* getWindow() { return window; }
|
2017-12-13 13:45:10 +00:00
|
|
|
};
|
|
|
|
|
2017-12-18 12:58:51 +00:00
|
|
|
class CheckBox : public Field {
|
|
|
|
using Field::Field;
|
|
|
|
public:
|
|
|
|
CheckBox(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
|
|
|
CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
|
|
|
|
|
|
|
wxWindow* window{ nullptr };
|
|
|
|
void BUILD() override;
|
|
|
|
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(const bool value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2017-12-18 12:58:51 +00:00
|
|
|
dynamic_cast<wxCheckBox*>(window)->SetValue(value);
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-18 12:58:51 +00:00
|
|
|
}
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(boost::any value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2017-12-18 12:58:51 +00:00
|
|
|
dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<bool>(value));
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-18 12:58:51 +00:00
|
|
|
}
|
2018-03-09 16:17:51 +00:00
|
|
|
boost::any get_value() override;
|
2017-12-18 12:58:51 +00:00
|
|
|
|
|
|
|
void enable() override { dynamic_cast<wxCheckBox*>(window)->Enable(); }
|
|
|
|
void disable() override { dynamic_cast<wxCheckBox*>(window)->Disable(); }
|
|
|
|
wxWindow* getWindow() override { return window; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class SpinCtrl : public Field {
|
|
|
|
using Field::Field;
|
|
|
|
public:
|
|
|
|
SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(-9999) {}
|
|
|
|
SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(-9999) {}
|
|
|
|
|
|
|
|
int tmp_value;
|
|
|
|
|
|
|
|
wxWindow* window{ nullptr };
|
|
|
|
void BUILD() override;
|
|
|
|
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(const std::string value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2017-12-18 12:58:51 +00:00
|
|
|
dynamic_cast<wxSpinCtrl*>(window)->SetValue(value);
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-18 12:58:51 +00:00
|
|
|
}
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(boost::any value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2018-04-05 10:12:35 +00:00
|
|
|
tmp_value = boost::any_cast<int>(value);
|
|
|
|
dynamic_cast<wxSpinCtrl*>(window)->SetValue(tmp_value/*boost::any_cast<int>(value)*/);
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-18 12:58:51 +00:00
|
|
|
}
|
|
|
|
boost::any get_value() override {
|
2018-04-04 18:37:37 +00:00
|
|
|
return boost::any(tmp_value);
|
2017-12-18 12:58:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void enable() override { dynamic_cast<wxSpinCtrl*>(window)->Enable(); }
|
|
|
|
void disable() override { dynamic_cast<wxSpinCtrl*>(window)->Disable(); }
|
|
|
|
wxWindow* getWindow() override { return window; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class Choice : public Field {
|
|
|
|
using Field::Field;
|
|
|
|
public:
|
|
|
|
Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
|
|
|
Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
|
|
|
|
|
|
|
wxWindow* window{ nullptr };
|
2017-12-26 22:04:54 +00:00
|
|
|
void BUILD() override;
|
2017-12-18 12:58:51 +00:00
|
|
|
|
|
|
|
void set_selection();
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(const std::string value, bool change_event = false);
|
|
|
|
void set_value(boost::any value, bool change_event = false);
|
2017-12-18 12:58:51 +00:00
|
|
|
void set_values(const std::vector<std::string> values);
|
2018-01-09 12:52:01 +00:00
|
|
|
boost::any get_value() override;
|
2017-12-18 12:58:51 +00:00
|
|
|
|
|
|
|
void enable() override { dynamic_cast<wxComboBox*>(window)->Enable(); };
|
|
|
|
void disable() override{ dynamic_cast<wxComboBox*>(window)->Disable(); };
|
|
|
|
wxWindow* getWindow() override { return window; }
|
|
|
|
};
|
2017-12-13 13:45:10 +00:00
|
|
|
|
2017-12-22 10:50:28 +00:00
|
|
|
class ColourPicker : public Field {
|
|
|
|
using Field::Field;
|
|
|
|
public:
|
|
|
|
ColourPicker(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
|
|
|
ColourPicker(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
|
|
|
|
|
|
|
wxWindow* window{ nullptr };
|
|
|
|
void BUILD() override;
|
|
|
|
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(const std::string value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2018-01-27 16:39:00 +00:00
|
|
|
dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(value);
|
|
|
|
m_disable_change_event = false;
|
2017-12-22 10:50:28 +00:00
|
|
|
}
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(boost::any value, bool change_event = false) {
|
|
|
|
m_disable_change_event = !change_event;
|
2018-02-13 15:05:53 +00:00
|
|
|
dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(boost::any_cast<wxString>(value));
|
2018-01-27 16:39:00 +00:00
|
|
|
m_disable_change_event = false;
|
2017-12-22 10:50:28 +00:00
|
|
|
}
|
2018-01-09 12:52:01 +00:00
|
|
|
|
2018-02-15 16:30:33 +00:00
|
|
|
boost::any get_value() override;
|
2017-12-22 10:50:28 +00:00
|
|
|
|
|
|
|
void enable() override { dynamic_cast<wxColourPickerCtrl*>(window)->Enable(); };
|
|
|
|
void disable() override{ dynamic_cast<wxColourPickerCtrl*>(window)->Disable(); };
|
|
|
|
wxWindow* getWindow() override { return window; }
|
|
|
|
};
|
|
|
|
|
2018-01-25 12:46:04 +00:00
|
|
|
class PointCtrl : public Field {
|
2017-12-22 10:50:28 +00:00
|
|
|
using Field::Field;
|
|
|
|
public:
|
2018-01-25 12:46:04 +00:00
|
|
|
PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
|
|
|
PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
2017-12-22 10:50:28 +00:00
|
|
|
|
|
|
|
wxSizer* sizer{ nullptr };
|
|
|
|
wxTextCtrl* x_textctrl;
|
|
|
|
wxTextCtrl* y_textctrl;
|
|
|
|
|
|
|
|
void BUILD() override;
|
|
|
|
|
2018-03-15 17:06:26 +00:00
|
|
|
void set_value(const Pointf value, bool change_event = false);
|
|
|
|
void set_value(boost::any value, bool change_event = false);
|
2017-12-26 22:04:54 +00:00
|
|
|
boost::any get_value() override;
|
2017-12-22 10:50:28 +00:00
|
|
|
|
2017-12-26 22:04:54 +00:00
|
|
|
void enable() override {
|
|
|
|
x_textctrl->Enable();
|
2017-12-22 10:50:28 +00:00
|
|
|
y_textctrl->Enable(); };
|
2017-12-26 22:04:54 +00:00
|
|
|
void disable() override{
|
|
|
|
x_textctrl->Disable();
|
2017-12-22 10:50:28 +00:00
|
|
|
y_textctrl->Disable(); };
|
|
|
|
wxSizer* getSizer() override { return sizer; }
|
|
|
|
};
|
|
|
|
|
2017-12-18 12:58:51 +00:00
|
|
|
} // GUI
|
|
|
|
} // Slic3r
|
|
|
|
|
2018-03-12 15:04:32 +00:00
|
|
|
#endif /* SLIC3R_GUI_FIELD_HPP */
|