PrusaSlicer-NonPlainar/src/slic3r/GUI/wxExtensions.hpp
2019-01-25 17:21:45 +01:00

952 lines
31 KiB
C++

#ifndef slic3r_GUI_wxExtensions_hpp_
#define slic3r_GUI_wxExtensions_hpp_
#include <wx/checklst.h>
#include <wx/combo.h>
#include <wx/dataview.h>
#include <wx/dc.h>
#include <wx/collpane.h>
#include <wx/wupdlock.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/menu.h>
#include <vector>
#include <set>
#include <functional>
wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, const wxBitmap& icon, wxEvtHandler* event_handler = nullptr);
wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr);
wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = "");
class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup
{
static const unsigned int DefaultWidth;
static const unsigned int DefaultHeight;
static const unsigned int DefaultItemHeight;
wxString m_text;
// Events sent on mouseclick are quite complex. Function OnListBoxSelection is supposed to pass the event to the checkbox, which works fine on
// Win. On OSX and Linux the events are generated differently - clicking on the checkbox square generates the event twice (and the square
// therefore seems not to respond).
// This enum is meant to save current state of affairs, i.e., if the event forwarding is ok to do or not. It is only used on Linux
// and OSX by some #ifdefs. It also stores information whether OnListBoxSelection is supposed to change the checkbox status,
// or if it changed status on its own already (which happens when the square is clicked). More comments in OnCheckListBox(...)
// There indeed is a better solution, maybe making a custom event used for the event passing to distinguish the original and passed message
// and blocking one of them on OSX and Linux. Feel free to refactor, but carefully test on all platforms.
enum class OnCheckListBoxFunction{
FreeToProceed,
RefuseToProceed,
WasRefusedLastTime
} m_check_box_events_status = OnCheckListBoxFunction::FreeToProceed;
public:
virtual bool Create(wxWindow* parent);
virtual wxWindow* GetControl();
virtual void SetStringValue(const wxString& value);
virtual wxString GetStringValue() const;
virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
virtual void OnKeyEvent(wxKeyEvent& evt);
void OnCheckListBox(wxCommandEvent& evt);
void OnListBoxSelection(wxCommandEvent& evt);
};
// *** wxDataViewTreeCtrlComboBox ***
class wxDataViewTreeCtrlComboPopup: public wxDataViewTreeCtrl, public wxComboPopup
{
static const unsigned int DefaultWidth;
static const unsigned int DefaultHeight;
static const unsigned int DefaultItemHeight;
wxString m_text;
int m_cnt_open_items{0};
public:
virtual bool Create(wxWindow* parent);
virtual wxWindow* GetControl() { return this; }
virtual void SetStringValue(const wxString& value) { m_text = value; }
virtual wxString GetStringValue() const { return m_text; }
// virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
virtual void OnKeyEvent(wxKeyEvent& evt);
void OnDataViewTreeCtrlSelection(wxCommandEvent& evt);
void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; }
};
// *** PrusaCollapsiblePane ***
// ----------------------------------------------------------------------------
class PrusaCollapsiblePane : public wxCollapsiblePane
{
public:
PrusaCollapsiblePane() {}
PrusaCollapsiblePane(wxWindow *parent,
wxWindowID winid,
const wxString& label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxCP_DEFAULT_STYLE,
const wxValidator& val = wxDefaultValidator,
const wxString& name = wxCollapsiblePaneNameStr)
{
Create(parent, winid, label, pos, size, style, val, name);
}
~PrusaCollapsiblePane() {}
void OnStateChange(const wxSize& sz); //override/hide of OnStateChange from wxCollapsiblePane
virtual bool Show(bool show = true) override {
wxCollapsiblePane::Show(show);
OnStateChange(GetBestSize());
return true;
}
};
// *** PrusaCollapsiblePaneMSW *** used only #ifdef __WXMSW__
// ----------------------------------------------------------------------------
#ifdef __WXMSW__
class PrusaCollapsiblePaneMSW : public PrusaCollapsiblePane//wxCollapsiblePane
{
wxButton* m_pDisclosureTriangleButton = nullptr;
wxBitmap m_bmp_close;
wxBitmap m_bmp_open;
wxString m_strLabel;
public:
PrusaCollapsiblePaneMSW() {}
PrusaCollapsiblePaneMSW( wxWindow *parent,
wxWindowID winid,
const wxString& label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxCP_DEFAULT_STYLE,
const wxValidator& val = wxDefaultValidator,
const wxString& name = wxCollapsiblePaneNameStr)
{
Create(parent, winid, label, pos, size, style, val, name);
}
~PrusaCollapsiblePaneMSW() {}
bool Create(wxWindow *parent,
wxWindowID id,
const wxString& label,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& val,
const wxString& name);
void UpdateBtnBmp();
void SetLabel(const wxString &label) override;
bool Layout() override;
void Collapse(bool collapse) override;
};
#endif //__WXMSW__
// *****************************************************************************
// ----------------------------------------------------------------------------
// PrusaDataViewBitmapText: helper class used by PrusaBitmapTextRenderer
// ----------------------------------------------------------------------------
class PrusaDataViewBitmapText : public wxObject
{
public:
PrusaDataViewBitmapText(const wxString &text = wxEmptyString,
const wxBitmap& bmp = wxNullBitmap) :
m_text(text), m_bmp(bmp)
{ }
PrusaDataViewBitmapText(const PrusaDataViewBitmapText &other)
: wxObject(),
m_text(other.m_text),
m_bmp(other.m_bmp)
{ }
void SetText(const wxString &text) { m_text = text; }
wxString GetText() const { return m_text; }
void SetBitmap(const wxBitmap &bmp) { m_bmp = bmp; }
const wxBitmap &GetBitmap() const { return m_bmp; }
bool IsSameAs(const PrusaDataViewBitmapText& other) const {
return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp);
}
bool operator==(const PrusaDataViewBitmapText& other) const {
return IsSameAs(other);
}
bool operator!=(const PrusaDataViewBitmapText& other) const {
return !IsSameAs(other);
}
private:
wxString m_text;
wxBitmap m_bmp;
wxDECLARE_DYNAMIC_CLASS(PrusaDataViewBitmapText);
};
DECLARE_VARIANT_OBJECT(PrusaDataViewBitmapText)
// ----------------------------------------------------------------------------
// PrusaObjectDataViewModelNode: a node inside PrusaObjectDataViewModel
// ----------------------------------------------------------------------------
enum ItemType {
itUndef = 0,
itObject = 1,
itVolume = 2,
itInstanceRoot = 4,
itInstance = 8,
itSettings = 16
};
class PrusaObjectDataViewModelNode;
WX_DEFINE_ARRAY_PTR(PrusaObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
class PrusaObjectDataViewModelNode
{
PrusaObjectDataViewModelNode* m_parent;
MyObjectTreeModelNodePtrArray m_children;
wxBitmap m_empty_bmp;
size_t m_volumes_cnt = 0;
std::vector< std::string > m_opt_categories;
public:
PrusaObjectDataViewModelNode(const wxString &name,
const wxString& extruder) {
m_parent = NULL;
m_name = name;
m_type = itObject;
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
m_extruder = extruder;
set_object_action_icon();
}
PrusaObjectDataViewModelNode( PrusaObjectDataViewModelNode* parent,
const wxString& sub_obj_name,
const wxBitmap& bmp,
const wxString& extruder,
const int idx = -1 ) {
m_parent = parent;
m_name = sub_obj_name;
m_bmp = bmp;
m_type = itVolume;
m_idx = idx;
m_extruder = extruder;
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
set_part_action_icon();
}
PrusaObjectDataViewModelNode( PrusaObjectDataViewModelNode* parent, const ItemType type) :
m_parent(parent),
m_type(type),
m_extruder(wxEmptyString)
{
if (type == itSettings) {
m_name = "Settings to modified";
}
else if (type == itInstanceRoot) {
m_name = "Instances";
#ifdef __WXGTK__
m_container = true;
#endif //__WXGTK__
}
else if (type == itInstance) {
m_idx = parent->GetChildCount();
m_name = wxString::Format("Instance_%d", m_idx+1);
set_part_action_icon();
}
}
~PrusaObjectDataViewModelNode()
{
// free all our children nodes
size_t count = m_children.GetCount();
for (size_t i = 0; i < count; i++)
{
PrusaObjectDataViewModelNode *child = m_children[i];
delete child;
}
}
wxString m_name;
wxBitmap& m_bmp = m_empty_bmp;
ItemType m_type;
int m_idx = -1;
bool m_container = false;
wxString m_extruder = "default";
wxBitmap m_action_icon;
bool IsContainer() const
{
return m_container;
}
PrusaObjectDataViewModelNode* GetParent()
{
return m_parent;
}
MyObjectTreeModelNodePtrArray& GetChildren()
{
return m_children;
}
PrusaObjectDataViewModelNode* GetNthChild(unsigned int n)
{
return m_children.Item(n);
}
void Insert(PrusaObjectDataViewModelNode* child, unsigned int n)
{
if (!m_container)
m_container = true;
m_children.Insert(child, n);
}
void Append(PrusaObjectDataViewModelNode* child)
{
if (!m_container)
m_container = true;
m_children.Add(child);
}
void RemoveAllChildren()
{
if (GetChildCount() == 0)
return;
for (int id = int(GetChildCount()) - 1; id >= 0; --id)
{
if (m_children.Item(id)->GetChildCount() > 0)
m_children[id]->RemoveAllChildren();
auto node = m_children[id];
m_children.RemoveAt(id);
delete node;
}
}
size_t GetChildCount() const
{
return m_children.GetCount();
}
bool SetValue(const wxVariant &variant, unsigned int col)
{
switch (col)
{
case 0:{
PrusaDataViewBitmapText data;
data << variant;
m_bmp = data.GetBitmap();
m_name = data.GetText();
return true;}
case 1:
m_extruder = variant.GetString();
return true;
case 2:
m_action_icon << variant;
return true;
default:
printf("MyObjectTreeModel::SetValue: wrong column");
}
return false;
}
void SetBitmap(const wxBitmap &icon)
{
m_bmp = icon;
}
ItemType GetType() const {
return m_type;
}
void SetIdx(const int& idx) {
m_idx = idx;
// update name if this node is instance
if (m_type == itInstance)
m_name = wxString::Format("Instance_%d", m_idx + 1);
}
int GetIdx() const {
return m_idx;
}
// use this function only for childrens
void AssignAllVal(PrusaObjectDataViewModelNode& from_node)
{
// ! Don't overwrite other values because of equality of this values for all children --
m_name = from_node.m_name;
m_bmp = from_node.m_bmp;
m_idx = from_node.m_idx;
m_extruder = from_node.m_extruder;
m_type = from_node.m_type;
}
bool SwapChildrens(int frst_id, int scnd_id) {
if (GetChildCount() < 2 ||
frst_id < 0 || frst_id >= GetChildCount() ||
scnd_id < 0 || scnd_id >= GetChildCount())
return false;
PrusaObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);
PrusaObjectDataViewModelNode new_frst = *GetNthChild(scnd_id);
new_scnd.m_idx = m_children.Item(scnd_id)->m_idx;
new_frst.m_idx = m_children.Item(frst_id)->m_idx;
m_children.Item(frst_id)->AssignAllVal(new_frst);
m_children.Item(scnd_id)->AssignAllVal(new_scnd);
return true;
}
// Set action icons for node
void set_object_action_icon();
void set_part_action_icon();
bool update_settings_digest(const std::vector<std::string>& categories);
private:
friend class PrusaObjectDataViewModel;
};
// ----------------------------------------------------------------------------
// PrusaObjectDataViewModel
// ----------------------------------------------------------------------------
// custom message the model sends to associated control to notify a last volume deleted from the object:
wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
class PrusaObjectDataViewModel :public wxDataViewModel
{
std::vector<PrusaObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
wxDataViewCtrl* m_ctrl{ nullptr };
public:
PrusaObjectDataViewModel();
~PrusaObjectDataViewModel();
wxDataViewItem Add(const wxString &name, const int extruder);
wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item,
const wxString &name,
const int volume_type,
const int extruder = 0,
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
wxDataViewItem Delete(const wxDataViewItem &item);
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
void DeleteAll();
void DeleteChildren(wxDataViewItem& parent);
void DeleteVolumeChildren(wxDataViewItem& parent);
void DeleteSettings(const wxDataViewItem& parent);
wxDataViewItem GetItemById(int obj_idx);
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
int GetIdByItem(const wxDataViewItem& item) const;
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetObjectIdByItem(const wxDataViewItem& item) const;
int GetVolumeIdByItem(const wxDataViewItem& item) const;
int GetInstanceIdByItem(const wxDataViewItem& item) const;
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
int GetRowByItem(const wxDataViewItem& item) const;
bool IsEmpty() { return m_objects.empty(); }
// helper method for wxLog
wxString GetName(const wxDataViewItem &item) const;
wxBitmap& GetBitmap(const wxDataViewItem &item) const;
// helper methods to change the model
virtual unsigned int GetColumnCount() const override { return 3;}
virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); }
virtual void GetValue(wxVariant &variant,
const wxDataViewItem &item, unsigned int col) const override;
virtual bool SetValue(const wxVariant &variant,
const wxDataViewItem &item, unsigned int col) override;
bool SetValue(const wxVariant &variant, const int item_idx, unsigned int col);
// wxDataViewItem MoveChildUp(const wxDataViewItem &item);
// wxDataViewItem MoveChildDown(const wxDataViewItem &item);
// For parent move child from cur_volume_id place to new_volume_id
// Remaining items will moved up/down accordingly
wxDataViewItem ReorganizeChildren(int cur_volume_id,
int new_volume_id,
const wxDataViewItem &parent);
virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override;
virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
// get object item
wxDataViewItem GetTopParent(const wxDataViewItem &item) const;
virtual bool IsContainer(const wxDataViewItem &item) const override;
virtual unsigned int GetChildren(const wxDataViewItem &parent,
wxDataViewItemArray &array) const override;
// Is the container just a header or an item with all columns
// In our case it is an item with all columns
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
ItemType GetItemType(const wxDataViewItem &item) const ;
wxDataViewItem GetItemByType(const wxDataViewItem &parent_item, ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector<std::string>& categories);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetVolumeType(const wxDataViewItem &item, const int type);
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
};
// ----------------------------------------------------------------------------
// PrusaBitmapTextRenderer
// ----------------------------------------------------------------------------
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
class PrusaBitmapTextRenderer : public wxDataViewRenderer
#else
class PrusaBitmapTextRenderer : public wxDataViewCustomRenderer
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
{
public:
PrusaBitmapTextRenderer(wxDataViewCellMode mode =
#ifdef __WXOSX__
wxDATAVIEW_CELL_INERT
#else
wxDATAVIEW_CELL_EDITABLE
#endif
,int align = wxDVR_DEFAULT_ALIGNMENT
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
);
#else
) : wxDataViewCustomRenderer(wxT("PrusaDataViewBitmapText"), mode, align) {}
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
bool SetValue(const wxVariant &value);
bool GetValue(wxVariant &value) const;
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
virtual wxString GetAccessibleDescription() const override;
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
virtual bool Render(wxRect cell, wxDC *dc, int state);
virtual wxSize GetSize() const;
bool HasEditorCtrl() const override
{
#ifdef __WXOSX__
return false;
#else
return true;
#endif
}
wxWindow* CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override;
bool GetValueFromEditorCtrl( wxWindow* ctrl,
wxVariant& value) override;
bool WasCanceled() const { return m_was_unusable_symbol; }
private:
PrusaDataViewBitmapText m_value;
bool m_was_unusable_symbol {false};
};
// ----------------------------------------------------------------------------
// MyCustomRenderer
// ----------------------------------------------------------------------------
class MyCustomRenderer : public wxDataViewCustomRenderer
{
public:
// This renderer can be either activatable or editable, for demonstration
// purposes. In real programs, you should select whether the user should be
// able to activate or edit the cell and it doesn't make sense to switch
// between the two -- but this is just an example, so it doesn't stop us.
explicit MyCustomRenderer(wxDataViewCellMode mode)
: wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
{ }
virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/
{
dc->SetBrush(*wxLIGHT_GREY_BRUSH);
dc->SetPen(*wxTRANSPARENT_PEN);
rect.Deflate(2);
dc->DrawRoundedRectangle(rect, 5);
RenderText(m_value,
0, // no offset
wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
dc,
state);
return true;
}
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem &WXUNUSED(item),
unsigned int WXUNUSED(col),
const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/
{
wxString position;
if (mouseEvent)
position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
else
position = "from keyboard";
// wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
return false;
}
virtual wxSize GetSize() const override/*wxOVERRIDE*/
{
return wxSize(60, 20);
}
virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/
{
m_value = value.GetString();
return true;
}
virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; }
virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; }
virtual wxWindow*
CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override/*wxOVERRIDE*/
{
wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
labelRect.GetPosition(),
labelRect.GetSize(),
wxTE_PROCESS_ENTER);
text->SetInsertionPointEnd();
return text;
}
virtual bool
GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/
{
wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
if (!text)
return false;
value = text->GetValue();
return true;
}
private:
wxString m_value;
};
// ----------------------------------------------------------------------------
// PrusaDoubleSlider
// ----------------------------------------------------------------------------
// custom message the slider sends to its parent to notify a tick-change:
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
enum SelectedSlider {
ssUndef,
ssLower,
ssHigher
};
enum TicksAction{
taOnIcon,
taAdd,
taDel
};
class PrusaDoubleSlider : public wxControl
{
public:
PrusaDoubleSlider(
wxWindow *parent,
wxWindowID id,
int lowerValue,
int higherValue,
int minValue,
int maxValue,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxSL_VERTICAL,
const wxValidator& val = wxDefaultValidator,
const wxString& name = wxEmptyString);
~PrusaDoubleSlider() {}
int GetMinValue() const { return m_min_value; }
int GetMaxValue() const { return m_max_value; }
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value].second; }
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value].second; }
int GetLowerValue() const { return m_lower_value; }
int GetHigherValue() const { return m_higher_value; }
int GetActiveValue() const;
double GetLowerValueD() { return get_double_value(ssLower); }
double GetHigherValueD() { return get_double_value(ssHigher); }
wxSize DoGetBestSize() const override;
void SetLowerValue(const int lower_val);
void SetHigherValue(const int higher_val);
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
void SetSelectionSpan(const int lower_val, const int higher_val);
void SetMaxValue(const int max_value);
void SetKoefForLabels(const double koef) {
m_label_koef = koef;
}
void SetSliderValues(const std::vector<std::pair<int, double>>& values) {
m_values = values;
}
void ChangeOneLayerLock();
std::vector<double> GetTicksValues() const;
void SetTicksValues(const std::vector<double>& heights);
void EnableTickManipulation(bool enable = true) {
m_is_enabled_tick_manipulation = enable;
}
void DisableTickManipulation() {
EnableTickManipulation(false);
}
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
bool is_one_layer() const { return m_is_one_layer; }
bool is_lower_at_min() const { return m_lower_value == m_min_value; }
bool is_higher_at_max() const { return m_higher_value == m_max_value; }
bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); }
void OnPaint(wxPaintEvent& ) { render();}
void OnLeftDown(wxMouseEvent& event);
void OnMotion(wxMouseEvent& event);
void OnLeftUp(wxMouseEvent& event);
void OnEnterWin(wxMouseEvent& event) { enter_window(event, true); }
void OnLeaveWin(wxMouseEvent& event) { enter_window(event, false); }
void OnWheel(wxMouseEvent& event);
void OnKeyDown(wxKeyEvent &event);
void OnKeyUp(wxKeyEvent &event);
void OnRightDown(wxMouseEvent& event);
void OnRightUp(wxMouseEvent& event);
protected:
void render();
void draw_focus_rect();
void draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end);
void draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos);
void draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection);
void draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos);
void draw_ticks(wxDC& dc);
void draw_colored_band(wxDC& dc);
void draw_one_layer_icon(wxDC& dc);
void draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
void draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
void update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
void detect_selected_slider(const wxPoint& pt, const bool is_mouse_wheel = false);
void correct_lower_value();
void correct_higher_value();
void move_current_thumb(const bool condition);
void action_tick(const TicksAction action);
void enter_window(wxMouseEvent& event, const bool enter);
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
int is_point_near_tick(const wxPoint& pt);
double get_scroll_step();
wxString get_label(const SelectedSlider& selection) const;
void get_lower_and_higher_position(int& lower_pos, int& higher_pos);
int get_value_from_position(const wxCoord x, const wxCoord y);
wxCoord get_position_from_value(const int value);
wxSize get_size();
void get_size(int *w, int *h);
double get_double_value(const SelectedSlider& selection);
private:
int m_min_value;
int m_max_value;
int m_lower_value;
int m_higher_value;
wxBitmap m_bmp_thumb_higher;
wxBitmap m_bmp_thumb_lower;
wxBitmap m_bmp_add_tick_on;
wxBitmap m_bmp_add_tick_off;
wxBitmap m_bmp_del_tick_on;
wxBitmap m_bmp_del_tick_off;
wxBitmap m_bmp_one_layer_lock_on;
wxBitmap m_bmp_one_layer_lock_off;
wxBitmap m_bmp_one_layer_unlock_on;
wxBitmap m_bmp_one_layer_unlock_off;
SelectedSlider m_selection;
bool m_is_left_down = false;
bool m_is_right_down = false;
bool m_is_one_layer = false;
bool m_is_focused = false;
bool m_is_action_icon_focesed = false;
bool m_is_one_layer_icon_focesed = false;
bool m_is_enabled_tick_manipulation = true;
wxRect m_rect_lower_thumb;
wxRect m_rect_higher_thumb;
wxRect m_rect_tick_action;
wxRect m_rect_one_layer_icon;
wxSize m_thumb_size;
int m_tick_icon_dim;
int m_lock_icon_dim;
long m_style;
float m_label_koef = 1.0;
// control's view variables
wxCoord SLIDER_MARGIN; // margin around slider
wxPen DARK_ORANGE_PEN;
wxPen ORANGE_PEN;
wxPen LIGHT_ORANGE_PEN;
wxPen DARK_GREY_PEN;
wxPen GREY_PEN;
wxPen LIGHT_GREY_PEN;
std::vector<wxPen*> line_pens;
std::vector<wxPen*> segm_pens;
std::set<int> m_ticks;
std::vector<std::pair<int,double>> m_values;
};
// ----------------------------------------------------------------------------
// PrusaLockButton
// ----------------------------------------------------------------------------
class PrusaLockButton : public wxButton
{
public:
PrusaLockButton(
wxWindow *parent,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
~PrusaLockButton() {}
void OnButton(wxCommandEvent& event);
void OnEnterBtn(wxMouseEvent& event) { enter_button(true); event.Skip(); }
void OnLeaveBtn(wxMouseEvent& event) { enter_button(false); event.Skip(); }
bool IsLocked() const { return m_is_pushed; }
void SetLock(bool lock);
protected:
void enter_button(const bool enter);
private:
bool m_is_pushed = false;
wxBitmap m_bmp_lock_on;
wxBitmap m_bmp_lock_off;
wxBitmap m_bmp_unlock_on;
wxBitmap m_bmp_unlock_off;
};
// ----------------------------------------------------------------------------
// PrusaModeButton
// ----------------------------------------------------------------------------
class PrusaModeButton : public wxButton
{
public:
PrusaModeButton(
wxWindow *parent,
wxWindowID id,
const wxString& mode = wxEmptyString,
const wxBitmap& bmp_on = wxNullBitmap,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
~PrusaModeButton() {}
void OnButton(wxCommandEvent& event);
void OnEnterBtn(wxMouseEvent& event) { focus_button(true); event.Skip(); }
void OnLeaveBtn(wxMouseEvent& event) { focus_button(m_is_selected); event.Skip(); }
void SetState(const bool state);
protected:
void focus_button(const bool focus);
private:
bool m_is_selected = false;
wxBitmap m_bmp_on;
wxBitmap m_bmp_off;
};
// ----------------------------------------------------------------------------
// PrusaModeSizer
// ----------------------------------------------------------------------------
class PrusaModeSizer : public wxFlexGridSizer
{
public:
PrusaModeSizer( wxWindow *parent);
~PrusaModeSizer() {}
void SetMode(const /*ConfigOptionMode*/int mode);
private:
std::vector<PrusaModeButton*> mode_btns;
};
// ----------------------------------------------------------------------------
// PrusaMenu
// ----------------------------------------------------------------------------
class PrusaMenu : public wxMenu
{
public:
PrusaMenu(const wxString& title, long style = 0)
: wxMenu(title, style) {}
PrusaMenu(long style = 0)
: wxMenu(style) {}
~PrusaMenu() {}
void DestroySeparators();
wxMenuItem* m_separator_frst { nullptr }; // use like separator before settings item
wxMenuItem* m_separator_scnd { nullptr }; // use like separator between settings items
};
// ******************************* EXPERIMENTS **********************************************
// ******************************************************************************************
#endif // slic3r_GUI_wxExtensions_hpp_