2020-01-23 15:07:31 +01:00
#ifndef slic3r_GUI_DoubleSlider_hpp_
#define slic3r_GUI_DoubleSlider_hpp_
#include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp"
#include <wx/window.h>
#include <wx/control.h>
#include <wx/dc.h>
#include <wx/slider.h>
#include <vector>
#include <set>
class wxMenu ;
namespace Slic3r {
2020-06-03 10:42:47 +02:00
using namespace CustomGCode ;
2020-01-23 15:07:31 +01:00
namespace DoubleSlider {
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
* So, let use same value as a permissible error for layer height.
*/
2020-04-22 12:49:52 +02:00
constexpr double epsilon () { return 0.0011 ; }
2020-01-23 15:07:31 +01:00
// custom message the slider sends to its parent to notify a tick-change:
wxDECLARE_EVENT ( wxCUSTOMEVT_TICKSCHANGED , wxEvent );
enum SelectedSlider {
ssUndef ,
ssLower ,
ssHigher
};
2020-02-05 22:55:18 +01:00
enum FocusedItem {
2020-02-04 14:53:17 +01:00
fiNone ,
fiRevertIcon ,
fiOneLayerIcon ,
fiCogIcon ,
fiColorBand ,
fiActionIcon ,
2020-08-18 12:39:46 +02:00
fiLowerThumb ,
fiHigherThumb ,
2021-03-18 18:51:08 +01:00
fiSmartWipeTower ,
2020-02-04 14:53:17 +01:00
fiTick
2020-01-23 15:07:31 +01:00
};
2020-01-27 12:40:12 +01:00
enum ConflictType
{
ctNone ,
ctModeConflict ,
2020-02-02 21:20:48 +01:00
ctMeaninglessColorChange ,
ctMeaninglessToolChange ,
2020-01-27 12:40:12 +01:00
ctRedundant
};
2020-02-05 22:55:18 +01:00
enum MouseAction
{
maNone ,
maAddMenu , // show "Add" context menu for NOTexist active tick
maEditMenu , // show "Edit" context menu for exist active tick
maCogIconMenu , // show context for "cog" icon
maForceColorEdit , // force color editing from colored band
maAddTick , // force tick adding
maDeleteTick , // force tick deleting
maCogIconClick , // LeftMouseClick on "cog" icon
maOneLayerIconClick , // LeftMouseClick on "one_layer" icon
maRevertIconClick , // LeftMouseClick on "revert" icon
};
2020-02-13 15:28:04 +01:00
enum DrawMode
{
dmRegular ,
dmSlaPrint ,
dmSequentialFffPrint ,
2020-05-15 09:22:51 +02:00
dmSequentialGCodeView ,
2020-02-13 15:28:04 +01:00
};
2020-11-11 18:12:32 +01:00
enum LabelType
{
ltHeightWithLayer ,
ltHeight ,
ltEstimatedTime ,
};
2020-01-23 15:07:31 +01:00
struct TickCode
{
bool operator < ( const TickCode & other ) const { return other . tick > this -> tick ; }
bool operator > ( const TickCode & other ) const { return other . tick < this -> tick ; }
int tick = 0 ;
2020-06-03 10:42:47 +02:00
Type type = ColorChange ;
2020-01-23 15:07:31 +01:00
int extruder = 0 ;
std :: string color ;
2020-06-03 10:42:47 +02:00
std :: string extra ;
2020-01-23 15:07:31 +01:00
};
class TickCodeInfo
{
std :: string custom_gcode ;
std :: string pause_print_msg ;
bool m_suppress_plus = false ;
bool m_suppress_minus = false ;
2020-02-03 21:27:53 +01:00
bool m_use_default_colors = false ;
int m_default_color_idx = 0 ;
2020-01-23 15:07:31 +01:00
2020-02-14 09:51:51 +01:00
std :: vector < std :: string >* m_colors { nullptr };
2020-06-03 10:42:47 +02:00
std :: string get_color_for_tick ( TickCode tick , Type type , const int extruder );
2020-01-23 15:07:31 +01:00
public :
2020-02-03 21:27:53 +01:00
std :: set < TickCode > ticks {};
2020-06-03 10:42:47 +02:00
Mode mode = Undef ;
2020-01-23 15:07:31 +01:00
bool empty () const { return ticks . empty (); }
void set_pause_print_msg ( const std :: string & message ) { pause_print_msg = message ; }
2020-06-03 10:42:47 +02:00
bool add_tick ( const int tick , Type type , int extruder , double print_z );
2020-01-23 15:07:31 +01:00
bool edit_tick ( std :: set < TickCode >:: iterator it , double print_z );
2020-06-03 10:42:47 +02:00
void switch_code ( Type type_from , Type type_to );
bool switch_code_for_tick ( std :: set < TickCode >:: iterator it , Type type_to , const int extruder );
void erase_all_ticks_with_code ( Type type );
2020-01-24 11:35:38 +01:00
2020-06-03 10:42:47 +02:00
bool has_tick_with_code ( Type type );
2021-02-23 18:46:05 +01:00
bool has_tick ( int tick );
2020-06-03 10:42:47 +02:00
ConflictType is_conflict_tick ( const TickCode & tick , Mode out_mode , int only_extruder , double print_z );
2020-01-27 12:40:12 +01:00
// Get used extruders for tick.
// Means all extruders(tools) which will be used during printing from current tick to the end
2020-06-03 10:42:47 +02:00
std :: set < int > get_used_extruders_for_tick ( int tick , int only_extruder , double print_z , Mode force_mode = Undef ) const ;
2020-01-23 15:07:31 +01:00
void suppress_plus ( bool suppress ) { m_suppress_plus = suppress ; }
void suppress_minus ( bool suppress ) { m_suppress_minus = suppress ; }
bool suppressed_plus () { return m_suppress_plus ; }
bool suppressed_minus () { return m_suppress_minus ; }
2020-02-03 21:27:53 +01:00
void set_default_colors ( bool default_colors_on ) { m_use_default_colors = default_colors_on ; }
2020-02-14 09:51:51 +01:00
void set_extruder_colors ( std :: vector < std :: string >* extruder_colors ) { m_colors = extruder_colors ; }
2020-01-23 15:07:31 +01:00
};
struct ExtrudersSequence
{
bool is_mm_intervals = true ;
double interval_by_mm = 3.0 ;
int interval_by_layers = 10 ;
std :: vector < size_t > extruders = { 0 };
bool operator == ( const ExtrudersSequence & other ) const
{
return ( other . is_mm_intervals == this -> is_mm_intervals ) &&
( other . interval_by_mm == this -> interval_by_mm ) &&
( other . interval_by_layers == this -> interval_by_layers ) &&
( other . extruders == this -> extruders ) ;
}
bool operator != ( const ExtrudersSequence & other ) const
{
return ( other . is_mm_intervals != this -> is_mm_intervals ) &&
( other . interval_by_mm != this -> interval_by_mm ) &&
( other . interval_by_layers != this -> interval_by_layers ) &&
( other . extruders != this -> extruders ) ;
}
void add_extruder ( size_t pos )
{
extruders . insert ( extruders . begin () + pos + 1 , size_t ( 0 ));
}
void delete_extruder ( size_t pos )
{
if ( extruders . size () == 1 )
return ; // last item can't be deleted
extruders . erase ( extruders . begin () + pos );
}
};
class Control : public wxControl
{
public :
Control (
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 );
~ Control () {}
void msw_rescale ();
2021-01-22 21:44:15 +01:00
void sys_color_changed ();
2020-01-23 15:07:31 +01:00
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 ]; }
double GetMaxValueD () { return m_values . empty () ? 0. : m_values [ m_max_value ]; }
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 ;
wxSize get_min_size () const ;
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
void SetLowerValue ( const int lower_val );
void SetHigherValue ( const int higher_val );
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 ; }
2020-11-16 21:33:07 +01:00
void SetSliderValues ( const std :: vector < double >& values );
2020-01-23 15:07:31 +01:00
void ChangeOneLayerLock ();
2021-02-16 10:07:05 +01:00
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
void SetSliderAlternateValues ( const std :: vector < double >& values ) { m_alternate_values = values ; }
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
2020-01-23 15:07:31 +01:00
2020-11-16 22:48:13 +01:00
Info GetTicksValues () const ;
void SetTicksValues ( const Info & custom_gcode_per_print_z );
2021-03-22 11:40:46 +01:00
void SetLayersTimes ( const std :: vector < float >& layers_times , float total_time );
2020-11-19 10:57:24 +01:00
void SetLayersTimes ( const std :: vector < double >& layers_times );
2020-01-23 15:07:31 +01:00
2020-02-13 15:28:04 +01:00
void SetDrawMode ( bool is_sla_print , bool is_sequential_print );
2020-05-15 09:22:51 +02:00
void SetDrawMode ( DrawMode mode ) { m_draw_mode = mode ; }
2020-01-23 15:07:31 +01:00
2020-06-03 10:42:47 +02:00
void SetManipulationMode ( Mode mode ) { m_mode = mode ; }
Mode GetManipulationMode () const { return m_mode ; }
2020-02-05 22:55:18 +01:00
void SetModeAndOnlyExtruder ( const bool is_one_extruder_printed_model , const int only_extruder );
2020-02-14 09:51:51 +01:00
void SetExtruderColors ( const std :: vector < std :: string >& extruder_colors );
2020-01-23 15:07:31 +01:00
2021-03-17 17:10:19 +01:00
bool IsNewPrint ();
2020-10-08 14:09:39 +02:00
void set_render_as_disabled ( bool value ) { m_render_as_disabled = value ; }
bool is_rendering_as_disabled () const { return m_render_as_disabled ; }
2020-01-23 15:07:31 +01:00
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 (); }
2020-05-15 09:22:51 +02:00
void OnPaint ( wxPaintEvent & ) { render (); }
2020-01-23 15:07:31 +01:00
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 ); }
2020-02-03 21:27:53 +01:00
void UseDefaultColors ( bool def_colors_on ) { m_ticks . set_default_colors ( def_colors_on ); }
2020-01-23 15:07:31 +01:00
void OnWheel ( wxMouseEvent & event );
void OnKeyDown ( wxKeyEvent & event );
void OnKeyUp ( wxKeyEvent & event );
void OnChar ( wxKeyEvent & event );
void OnRightDown ( wxMouseEvent & event );
void OnRightUp ( wxMouseEvent & event );
2020-06-03 10:42:47 +02:00
void add_code_as_tick ( Type type , int selected_extruder = - 1 );
2020-01-23 15:07:31 +01:00
// add default action for tick, when press "+"
void add_current_tick ( bool call_from_keyboard = false );
// delete current tick, when press "-"
void delete_current_tick ();
2020-02-04 17:44:06 +01:00
void edit_tick ( int tick = - 1 );
2020-02-05 22:55:18 +01:00
void switch_one_layer_mode ();
void discard_all_thicks ();
void move_current_thumb_to_pos ( wxPoint pos );
2020-01-23 15:07:31 +01:00
void edit_extruder_sequence ();
2020-05-15 17:57:47 +02:00
void jump_to_value ();
2020-10-17 14:01:45 +02:00
void enable_action_icon ( bool enable ) { m_enable_action_icon = enable ; }
2020-02-06 18:51:52 +01:00
void show_add_context_menu ();
void show_edit_context_menu ();
void show_cog_icon_context_menu ();
2021-02-23 18:46:05 +01:00
void auto_color_change ();
2020-01-23 15:07:31 +01:00
ExtrudersSequence m_extruders_sequence ;
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 );
2020-11-16 21:33:07 +01:00
void draw_ticks_pair ( wxDC & dc , wxCoord pos , wxCoord mid , int tick_len );
2020-01-23 15:07:31 +01:00
void draw_ticks ( wxDC & dc );
void draw_colored_band ( wxDC & dc );
2020-11-11 18:12:32 +01:00
void draw_ruler ( wxDC & dc );
2020-01-23 15:07:31 +01:00
void draw_one_layer_icon ( wxDC & dc );
void draw_revert_icon ( wxDC & dc );
void draw_cog_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 );
2020-02-06 18:51:52 +01:00
void draw_tick_on_mouse_position ( wxDC & dc );
2020-11-11 18:12:32 +01:00
void draw_tick_text ( wxDC & dc , const wxPoint & pos , int tick , LabelType label_type = ltHeight , bool right_side = true ) const ;
2020-01-23 15:07:31 +01:00
void draw_thumb_text ( wxDC & dc , const wxPoint & pos , const SelectedSlider & selection ) const ;
2020-05-21 13:07:55 +02:00
void update_thumb_rect ( const wxCoord begin_x , const wxCoord begin_y , const SelectedSlider & selection );
2020-11-03 15:44:59 +01:00
bool is_lower_thumb_editable ();
2020-02-14 16:44:49 +01:00
bool detect_selected_slider ( const wxPoint & pt );
2020-01-23 15:07:31 +01:00
void correct_lower_value ();
void correct_higher_value ();
void move_current_thumb ( const bool condition );
void enter_window ( wxMouseEvent & event , const bool enter );
2021-03-18 18:51:08 +01:00
bool is_wipe_tower_layer ( int tick ) const ;
2020-01-23 15:07:31 +01:00
private :
bool is_point_in_rect ( const wxPoint & pt , const wxRect & rect );
2020-01-24 11:35:38 +01:00
int get_tick_near_point ( const wxPoint & pt );
2020-01-23 15:07:31 +01:00
double get_scroll_step ();
2020-11-11 18:12:32 +01:00
wxString get_label ( int tick , LabelType label_type = ltHeightWithLayer ) const ;
2020-01-23 15:07:31 +01:00
void get_lower_and_higher_position ( int & lower_pos , int & higher_pos );
int get_value_from_position ( const wxCoord x , const wxCoord y );
2020-02-04 17:44:06 +01:00
int get_value_from_position ( const wxPoint pos ) { return get_value_from_position ( pos . x , pos . y ); }
2020-01-23 15:07:31 +01:00
wxCoord get_position_from_value ( const int value );
2020-05-27 11:50:29 +02:00
wxSize get_size () const ;
void get_size ( int * w , int * h ) const ;
2020-01-23 15:07:31 +01:00
double get_double_value ( const SelectedSlider & selection );
2021-02-23 18:46:05 +01:00
int get_tick_from_value ( double value );
2020-02-05 22:55:18 +01:00
wxString get_tooltip ( int tick = - 1 );
2020-06-03 10:42:47 +02:00
int get_edited_tick_for_position ( wxPoint pos , Type type = ColorChange );
2020-01-23 15:07:31 +01:00
std :: string get_color_for_tool_change_tick ( std :: set < TickCode >:: const_iterator it ) const ;
std :: string get_color_for_color_change_tick ( std :: set < TickCode >:: const_iterator it ) const ;
2020-02-04 17:44:06 +01:00
wxRect get_colored_band_rect ();
2020-01-23 15:07:31 +01:00
// Get active extruders for tick.
// Means one current extruder for not existing tick OR
// 2 extruders - for existing tick (extruder before ToolChangeCode and extruder of current existing tick)
// Use those values to disable selection of active extruders
std :: array < int , 2 > get_active_extruders_for_tick ( int tick ) const ;
2020-06-03 10:42:47 +02:00
void post_ticks_changed_event ( Type type = Custom );
bool check_ticks_changed_event ( Type type );
2020-01-23 15:07:31 +01:00
void append_change_extruder_menu_item ( wxMenu * , bool switch_current_code = false );
void append_add_color_change_menu_item ( wxMenu * , bool switch_current_code = false );
bool is_osx { false };
wxFont m_font ;
int m_min_value ;
int m_max_value ;
int m_lower_value ;
int m_higher_value ;
2020-10-08 14:09:39 +02:00
bool m_render_as_disabled { false };
2020-01-23 15:07:31 +01:00
ScalableBitmap m_bmp_thumb_higher ;
ScalableBitmap m_bmp_thumb_lower ;
ScalableBitmap m_bmp_add_tick_on ;
ScalableBitmap m_bmp_add_tick_off ;
ScalableBitmap m_bmp_del_tick_on ;
ScalableBitmap m_bmp_del_tick_off ;
ScalableBitmap m_bmp_one_layer_lock_on ;
ScalableBitmap m_bmp_one_layer_lock_off ;
ScalableBitmap m_bmp_one_layer_unlock_on ;
ScalableBitmap m_bmp_one_layer_unlock_off ;
ScalableBitmap m_bmp_revert ;
ScalableBitmap m_bmp_cog ;
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_force_mode_apply = true ;
2020-10-17 14:01:45 +02:00
bool m_enable_action_icon = true ;
2021-03-18 18:51:08 +01:00
bool m_is_smart_wipe_tower = false ; //This flag indicates that for current print is used "smart" wipe tower (Print Settings->Multiple Extruders->No sparse layer is enabled)
2020-02-05 22:55:18 +01:00
2020-02-13 15:28:04 +01:00
DrawMode m_draw_mode = dmRegular ;
2020-06-03 10:42:47 +02:00
Mode m_mode = SingleExtruder ;
2020-01-23 15:07:31 +01:00
int m_only_extruder = - 1 ;
2020-02-05 22:55:18 +01:00
MouseAction m_mouse = maNone ;
FocusedItem m_focus = fiNone ;
2020-02-06 18:51:52 +01:00
wxPoint m_moving_pos = wxDefaultPosition ;
2020-02-05 22:55:18 +01:00
2020-01-23 15:07:31 +01:00
wxRect m_rect_lower_thumb ;
wxRect m_rect_higher_thumb ;
wxRect m_rect_tick_action ;
wxRect m_rect_one_layer_icon ;
wxRect m_rect_revert_icon ;
wxRect m_rect_cog_icon ;
wxSize m_thumb_size ;
int m_tick_icon_dim ;
int m_lock_icon_dim ;
int m_revert_icon_dim ;
int m_cog_icon_dim ;
long m_style ;
2020-11-11 18:12:32 +01:00
long m_extra_style ;
2021-02-16 10:07:05 +01:00
float m_label_koef { 1.0 };
2020-01-23 15:07:31 +01:00
std :: vector < double > m_values ;
TickCodeInfo m_ticks ;
2020-11-19 10:57:24 +01:00
std :: vector < double > m_layers_times ;
2021-03-18 18:51:08 +01:00
std :: vector < double > m_layers_values ;
2020-02-14 09:51:51 +01:00
std :: vector < std :: string > m_extruder_colors ;
2021-03-17 17:10:19 +01:00
std :: string m_print_obj_idxs ;
2020-02-14 09:51:51 +01:00
2021-02-16 10:07:05 +01:00
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
std :: vector < double > m_alternate_values ;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
2020-01-23 15:07:31 +01:00
// 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 *> m_line_pens ;
std :: vector < wxPen *> m_segm_pens ;
2020-11-16 21:33:07 +01:00
struct Ruler {
double long_step ;
double short_step ;
int count { 1 }; // > 1 for sequential print
void update ( wxWindow * win , const std :: vector < double >& values , double scroll_step );
bool is_ok () { return long_step > 0 && short_step > 0 ; }
} m_ruler ;
2020-01-23 15:07:31 +01:00
};
} // DoubleSlider;
} // Slic3r
#endif // slic3r_GUI_DoubleSlider_hpp_