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