1 #ifndef slic3r_GUI_DoubleSlider_hpp_
2 #define slic3r_GUI_DoubleSlider_hpp_
3 
4 #include "libslic3r/CustomGCode.hpp"
5 #include "wxExtensions.hpp"
6 
7 #include <wx/window.h>
8 #include <wx/control.h>
9 #include <wx/dc.h>
10 #include <wx/slider.h>
11 
12 #include <vector>
13 #include <set>
14 
15 class wxMenu;
16 
17 namespace Slic3r {
18 
19 using namespace CustomGCode;
20 
21 namespace DoubleSlider {
22 
23 /* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
24  * So, let use same value as a permissible error for layer height.
25  */
epsilon()26 constexpr double epsilon() { return 0.0011; }
27 
28 // custom message the slider sends to its parent to notify a tick-change:
29 wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
30 
31 enum SelectedSlider {
32     ssUndef,
33     ssLower,
34     ssHigher
35 };
36 
37 enum FocusedItem {
38     fiNone,
39     fiRevertIcon,
40     fiOneLayerIcon,
41     fiCogIcon,
42     fiColorBand,
43     fiActionIcon,
44     fiLowerThumb,
45     fiHigherThumb,
46     fiTick
47 };
48 
49 enum ConflictType
50 {
51     ctNone,
52     ctModeConflict,
53     ctMeaninglessColorChange,
54     ctMeaninglessToolChange,
55     ctRedundant
56 };
57 
58 enum MouseAction
59 {
60     maNone,
61     maAddMenu,                  // show "Add"  context menu for NOTexist active tick
62     maEditMenu,                 // show "Edit" context menu for exist active tick
63     maCogIconMenu,              // show context for "cog" icon
64     maForceColorEdit,           // force color editing from colored band
65     maAddTick,                  // force tick adding
66     maDeleteTick,               // force tick deleting
67     maCogIconClick,             // LeftMouseClick on "cog" icon
68     maOneLayerIconClick,        // LeftMouseClick on "one_layer" icon
69     maRevertIconClick,          // LeftMouseClick on "revert" icon
70 };
71 
72 enum DrawMode
73 {
74     dmRegular,
75     dmSlaPrint,
76     dmSequentialFffPrint,
77     dmSequentialGCodeView,
78 };
79 
80 enum LabelType
81 {
82     ltHeightWithLayer,
83     ltHeight,
84     ltEstimatedTime,
85 };
86 
87 struct TickCode
88 {
operator <Slic3r::DoubleSlider::TickCode89     bool operator<(const TickCode& other) const { return other.tick > this->tick; }
operator >Slic3r::DoubleSlider::TickCode90     bool operator>(const TickCode& other) const { return other.tick < this->tick; }
91 
92     int         tick = 0;
93     Type        type = ColorChange;
94     int         extruder = 0;
95     std::string color;
96     std::string extra;
97 };
98 
99 class TickCodeInfo
100 {
101     std::string custom_gcode;
102     std::string pause_print_msg;
103     bool        m_suppress_plus     = false;
104     bool        m_suppress_minus    = false;
105     bool        m_use_default_colors= false;
106     int         m_default_color_idx = 0;
107 
108     std::vector<std::string>* m_colors {nullptr};
109 
110     std::string get_color_for_tick(TickCode tick, Type type, const int extruder);
111 
112 public:
113     std::set<TickCode>  ticks {};
114     Mode                mode = Undef;
115 
empty() const116     bool empty() const { return ticks.empty(); }
set_pause_print_msg(const std::string & message)117     void set_pause_print_msg(const std::string& message) { pause_print_msg = message; }
118 
119     bool add_tick(const int tick, Type type, int extruder, double print_z);
120     bool edit_tick(std::set<TickCode>::iterator it, double print_z);
121     void switch_code(Type type_from, Type type_to);
122     bool switch_code_for_tick(std::set<TickCode>::iterator it, Type type_to, const int extruder);
123     void erase_all_ticks_with_code(Type type);
124 
125     bool            has_tick_with_code(Type type);
126     ConflictType    is_conflict_tick(const TickCode& tick, Mode out_mode, int only_extruder, double print_z);
127 
128     // Get used extruders for tick.
129     // Means all extruders(tools) which will be used during printing from current tick to the end
130     std::set<int>   get_used_extruders_for_tick(int tick, int only_extruder, double print_z, Mode force_mode = Undef) const;
131 
suppress_plus(bool suppress)132     void suppress_plus (bool suppress) { m_suppress_plus = suppress; }
suppress_minus(bool suppress)133     void suppress_minus(bool suppress) { m_suppress_minus = suppress; }
suppressed_plus()134     bool suppressed_plus () { return m_suppress_plus; }
suppressed_minus()135     bool suppressed_minus() { return m_suppress_minus; }
set_default_colors(bool default_colors_on)136     void set_default_colors(bool default_colors_on)  { m_use_default_colors = default_colors_on; }
137 
set_extruder_colors(std::vector<std::string> * extruder_colors)138     void set_extruder_colors(std::vector<std::string>* extruder_colors) { m_colors = extruder_colors; }
139 };
140 
141 
142 struct ExtrudersSequence
143 {
144     bool            is_mm_intervals     = true;
145     double          interval_by_mm      = 3.0;
146     int             interval_by_layers  = 10;
147     std::vector<size_t>  extruders      = { 0 };
148 
operator ==Slic3r::DoubleSlider::ExtrudersSequence149     bool operator==(const ExtrudersSequence& other) const
150     {
151         return  (other.is_mm_intervals      == this->is_mm_intervals    ) &&
152                 (other.interval_by_mm       == this->interval_by_mm     ) &&
153                 (other.interval_by_layers   == this->interval_by_layers ) &&
154                 (other.extruders            == this->extruders          ) ;
155     }
operator !=Slic3r::DoubleSlider::ExtrudersSequence156     bool operator!=(const ExtrudersSequence& other) const
157     {
158         return  (other.is_mm_intervals      != this->is_mm_intervals    ) &&
159                 (other.interval_by_mm       != this->interval_by_mm     ) &&
160                 (other.interval_by_layers   != this->interval_by_layers ) &&
161                 (other.extruders            != this->extruders          ) ;
162     }
163 
add_extruderSlic3r::DoubleSlider::ExtrudersSequence164     void add_extruder(size_t pos)
165     {
166         extruders.insert(extruders.begin() + pos+1, size_t(0));
167     }
168 
delete_extruderSlic3r::DoubleSlider::ExtrudersSequence169     void delete_extruder(size_t pos)
170     {
171         if (extruders.size() == 1)
172             return;// last item can't be deleted
173         extruders.erase(extruders.begin() + pos);
174     }
175 };
176 
177 class Control : public wxControl
178 {
179 public:
180     Control(
181         wxWindow *parent,
182         wxWindowID id,
183         int lowerValue,
184         int higherValue,
185         int minValue,
186         int maxValue,
187         const wxPoint& pos = wxDefaultPosition,
188         const wxSize& size = wxDefaultSize,
189         long style = wxSL_VERTICAL,
190         const wxValidator& val = wxDefaultValidator,
191         const wxString& name = wxEmptyString);
~Control()192     ~Control() {}
193 
194     void    msw_rescale();
195     void    sys_color_changed();
196 
GetMinValue() const197     int     GetMinValue() const { return m_min_value; }
GetMaxValue() const198     int     GetMaxValue() const { return m_max_value; }
GetMinValueD()199     double  GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value]; }
GetMaxValueD()200     double  GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value]; }
GetLowerValue() const201     int     GetLowerValue()  const { return m_lower_value; }
GetHigherValue() const202     int     GetHigherValue() const { return m_higher_value; }
203     int     GetActiveValue() const;
GetLowerValueD()204     double  GetLowerValueD()  { return get_double_value(ssLower); }
GetHigherValueD()205     double  GetHigherValueD() { return get_double_value(ssHigher); }
206     wxSize  DoGetBestSize() const override;
207     wxSize  get_min_size()  const ;
208 
209     // Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
210     void    SetLowerValue (const int lower_val);
211     void    SetHigherValue(const int higher_val);
212     void    SetSelectionSpan(const int lower_val, const int higher_val);
213 
214     void    SetMaxValue(const int max_value);
SetKoefForLabels(const double koef)215     void    SetKoefForLabels(const double koef)                { m_label_koef = koef; }
216     void    SetSliderValues(const std::vector<double>& values);
217     void    ChangeOneLayerLock();
218 
219     Info    GetTicksValues() const;
220     void    SetTicksValues(const Info &custom_gcode_per_print_z);
221     void    SetLayersTimes(const std::vector<float>& layers_times);
222     void    SetLayersTimes(const std::vector<double>& layers_times);
223 
224     void    SetDrawMode(bool is_sla_print, bool is_sequential_print);
SetDrawMode(DrawMode mode)225     void    SetDrawMode(DrawMode mode) { m_draw_mode = mode; }
226 
SetManipulationMode(Mode mode)227     void    SetManipulationMode(Mode mode)  { m_mode = mode; }
GetManipulationMode() const228     Mode    GetManipulationMode() const     { return m_mode; }
229     void    SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
230     void    SetExtruderColors(const std::vector<std::string>& extruder_colors);
231 
set_render_as_disabled(bool value)232     void set_render_as_disabled(bool value) { m_render_as_disabled = value; }
is_rendering_as_disabled() const233     bool is_rendering_as_disabled() const { return m_render_as_disabled; }
234 
is_horizontal() const235     bool is_horizontal() const      { return m_style == wxSL_HORIZONTAL; }
is_one_layer() const236     bool is_one_layer() const       { return m_is_one_layer; }
is_lower_at_min() const237     bool is_lower_at_min() const    { return m_lower_value == m_min_value; }
is_higher_at_max() const238     bool is_higher_at_max() const   { return m_higher_value == m_max_value; }
is_full_span() const239     bool is_full_span() const       { return this->is_lower_at_min() && this->is_higher_at_max(); }
240 
OnPaint(wxPaintEvent &)241     void OnPaint(wxPaintEvent& ) { render(); }
242     void OnLeftDown(wxMouseEvent& event);
243     void OnMotion(wxMouseEvent& event);
244     void OnLeftUp(wxMouseEvent& event);
OnEnterWin(wxMouseEvent & event)245     void OnEnterWin(wxMouseEvent& event) { enter_window(event, true); }
OnLeaveWin(wxMouseEvent & event)246     void OnLeaveWin(wxMouseEvent& event) { enter_window(event, false); }
UseDefaultColors(bool def_colors_on)247     void UseDefaultColors(bool def_colors_on)   { m_ticks.set_default_colors(def_colors_on); }
248     void OnWheel(wxMouseEvent& event);
249     void OnKeyDown(wxKeyEvent &event);
250     void OnKeyUp(wxKeyEvent &event);
251     void OnChar(wxKeyEvent &event);
252     void OnRightDown(wxMouseEvent& event);
253     void OnRightUp(wxMouseEvent& event);
254 
255     void add_code_as_tick(Type type, int selected_extruder = -1);
256     // add default action for tick, when press "+"
257     void add_current_tick(bool call_from_keyboard = false);
258     // delete current tick, when press "-"
259     void delete_current_tick();
260     void edit_tick(int tick = -1);
261     void switch_one_layer_mode();
262     void discard_all_thicks();
263     void move_current_thumb_to_pos(wxPoint pos);
264     void edit_extruder_sequence();
265     void jump_to_value();
enable_action_icon(bool enable)266     void enable_action_icon(bool enable) { m_enable_action_icon = enable; }
267     void show_add_context_menu();
268     void show_edit_context_menu();
269     void show_cog_icon_context_menu();
270 
271     ExtrudersSequence m_extruders_sequence;
272 
273 protected:
274 
275     void    render();
276     void    draw_focus_rect();
277     void    draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end);
278     void    draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos);
279     void    draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection);
280     void    draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos);
281     void    draw_ticks_pair(wxDC& dc, wxCoord pos, wxCoord mid, int tick_len);
282     void    draw_ticks(wxDC& dc);
283     void    draw_colored_band(wxDC& dc);
284     void    draw_ruler(wxDC& dc);
285     void    draw_one_layer_icon(wxDC& dc);
286     void    draw_revert_icon(wxDC& dc);
287     void    draw_cog_icon(wxDC &dc);
288     void    draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
289     void    draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
290     void    draw_tick_on_mouse_position(wxDC &dc);
291     void    draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, LabelType label_type = ltHeight, bool right_side = true) const;
292     void    draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
293 
294     void    update_thumb_rect(const wxCoord begin_x, const wxCoord begin_y, const SelectedSlider& selection);
295     bool    is_lower_thumb_editable();
296     bool    detect_selected_slider(const wxPoint& pt);
297     void    correct_lower_value();
298     void    correct_higher_value();
299     void    move_current_thumb(const bool condition);
300     void    enter_window(wxMouseEvent& event, const bool enter);
301 
302 private:
303 
304     bool    is_point_in_rect(const wxPoint& pt, const wxRect& rect);
305     int     get_tick_near_point(const wxPoint& pt);
306 
307     double      get_scroll_step();
308     wxString    get_label(int tick, LabelType label_type = ltHeightWithLayer) const;
309     void        get_lower_and_higher_position(int& lower_pos, int& higher_pos);
310     int         get_value_from_position(const wxCoord x, const wxCoord y);
get_value_from_position(const wxPoint pos)311     int         get_value_from_position(const wxPoint pos) { return get_value_from_position(pos.x, pos.y); }
312     wxCoord     get_position_from_value(const int value);
313     wxSize      get_size() const;
314     void        get_size(int* w, int* h) const;
315     double      get_double_value(const SelectedSlider& selection);
316     wxString    get_tooltip(int tick = -1);
317     int         get_edited_tick_for_position(wxPoint pos, Type type = ColorChange);
318 
319     std::string get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const;
320     std::string get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const;
321     wxRect      get_colored_band_rect();
322 
323     // Get active extruders for tick.
324     // Means one current extruder for not existing tick OR
325     // 2 extruders - for existing tick (extruder before ToolChangeCode and extruder of current existing tick)
326     // Use those values to disable selection of active extruders
327     std::array<int, 2> get_active_extruders_for_tick(int tick) const;
328 
329     void    post_ticks_changed_event(Type type = Custom);
330     bool    check_ticks_changed_event(Type type);
331 
332     void    append_change_extruder_menu_item (wxMenu*, bool switch_current_code = false);
333     void    append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false);
334 
335     bool        is_osx { false };
336     wxFont      m_font;
337     int         m_min_value;
338     int         m_max_value;
339     int         m_lower_value;
340     int         m_higher_value;
341 
342     bool        m_render_as_disabled{ false };
343 
344     ScalableBitmap    m_bmp_thumb_higher;
345     ScalableBitmap    m_bmp_thumb_lower;
346     ScalableBitmap    m_bmp_add_tick_on;
347     ScalableBitmap    m_bmp_add_tick_off;
348     ScalableBitmap    m_bmp_del_tick_on;
349     ScalableBitmap    m_bmp_del_tick_off;
350     ScalableBitmap    m_bmp_one_layer_lock_on;
351     ScalableBitmap    m_bmp_one_layer_lock_off;
352     ScalableBitmap    m_bmp_one_layer_unlock_on;
353     ScalableBitmap    m_bmp_one_layer_unlock_off;
354     ScalableBitmap    m_bmp_revert;
355     ScalableBitmap    m_bmp_cog;
356     SelectedSlider    m_selection;
357     bool        m_is_left_down = false;
358     bool        m_is_right_down = false;
359     bool        m_is_one_layer = false;
360     bool        m_is_focused = false;
361     bool        m_force_mode_apply = true;
362     bool        m_enable_action_icon = true;
363 
364     DrawMode    m_draw_mode = dmRegular;
365 
366     Mode        m_mode = SingleExtruder;
367     int         m_only_extruder = -1;
368 
369     MouseAction m_mouse = maNone;
370     FocusedItem m_focus = fiNone;
371     wxPoint     m_moving_pos = wxDefaultPosition;
372 
373     wxRect      m_rect_lower_thumb;
374     wxRect      m_rect_higher_thumb;
375     wxRect      m_rect_tick_action;
376     wxRect      m_rect_one_layer_icon;
377     wxRect      m_rect_revert_icon;
378     wxRect      m_rect_cog_icon;
379     wxSize      m_thumb_size;
380     int         m_tick_icon_dim;
381     int         m_lock_icon_dim;
382     int         m_revert_icon_dim;
383     int         m_cog_icon_dim;
384     long        m_style;
385     long        m_extra_style;
386     float       m_label_koef = 1.0;
387 
388     std::vector<double> m_values;
389     TickCodeInfo        m_ticks;
390     std::vector<double> m_layers_times;
391 
392     std::vector<std::string>    m_extruder_colors;
393 
394 // control's view variables
395     wxCoord SLIDER_MARGIN; // margin around slider
396 
397     wxPen   DARK_ORANGE_PEN;
398     wxPen   ORANGE_PEN;
399     wxPen   LIGHT_ORANGE_PEN;
400 
401     wxPen   DARK_GREY_PEN;
402     wxPen   GREY_PEN;
403     wxPen   LIGHT_GREY_PEN;
404 
405     std::vector<wxPen*> m_line_pens;
406     std::vector<wxPen*> m_segm_pens;
407 
408     struct Ruler {
409         double long_step;
410         double short_step;
411         int count { 1 }; // > 1 for sequential print
412 
413         void update(wxWindow* win, const std::vector<double>& values, double scroll_step);
is_okSlic3r::DoubleSlider::Control::Ruler414         bool is_ok() { return long_step > 0 && short_step > 0; }
415     } m_ruler;
416 };
417 
418 } // DoubleSlider;
419 
420 } // Slic3r
421 
422 
423 
424 #endif // slic3r_GUI_DoubleSlider_hpp_
425