1 #ifndef slic3r_UnsavedChangesDialog_hpp_ 2 #define slic3r_UnsavedChangesDialog_hpp_ 3 4 #include <wx/dataview.h> 5 #include <map> 6 #include <vector> 7 8 #include "GUI_Utils.hpp" 9 #include "wxExtensions.hpp" 10 #include "libslic3r/Preset.hpp" 11 12 class ScalableButton; 13 class wxStaticText; 14 15 namespace Slic3r { 16 namespace GUI{ 17 18 // ---------------------------------------------------------------------------- 19 // ModelNode: a node inside UnsavedChangesModel 20 // ---------------------------------------------------------------------------- 21 22 class ModelNode; 23 using ModelNodePtrArray = std::vector<std::unique_ptr<ModelNode>>; 24 25 // On all of 3 different platforms Bitmap+Text icon column looks different 26 // because of Markup text is missed or not implemented. 27 // As a temporary workaround, we will use: 28 // MSW - DataViewBitmapText (our custom renderer wxBitmap + wxString, supported Markup text) 29 // OSX - -//-, but Markup text is not implemented right now 30 // GTK - wxDataViewIconText (wxWidgets for GTK renderer wxIcon + wxString, supported Markup text) 31 class ModelNode 32 { 33 wxWindow* m_parent_win{ nullptr }; 34 35 ModelNode* m_parent; 36 ModelNodePtrArray m_children; 37 wxBitmap m_empty_bmp; 38 Preset::Type m_preset_type {Preset::TYPE_INVALID}; 39 40 std::string m_icon_name; 41 // saved values for colors if they exist 42 wxString m_old_color; 43 wxString m_new_color; 44 45 // TODO/FIXME: 46 // the GTK version of wxDVC (in particular wxDataViewCtrlInternal::ItemAdded) 47 // needs to know in advance if a node is or _will be_ a container. 48 // Thus implementing: 49 // bool IsContainer() const 50 // { return m_children.size()>0; } 51 // doesn't work with wxGTK when UnsavedChangesModel::AddToClassical is called 52 // AND the classical node was removed (a new node temporary without children 53 // would be added to the control) 54 bool m_container {true}; 55 56 #ifdef __linux__ 57 wxIcon get_bitmap(const wxString& color); 58 #else 59 wxBitmap get_bitmap(const wxString& color); 60 #endif //__linux__ 61 62 public: 63 64 bool m_toggle {true}; 65 #ifdef __linux__ 66 wxIcon m_icon; 67 wxIcon m_old_color_bmp; 68 wxIcon m_new_color_bmp; 69 #else 70 wxBitmap m_icon; 71 wxBitmap m_old_color_bmp; 72 wxBitmap m_new_color_bmp; 73 #endif //__linux__ 74 wxString m_text; 75 wxString m_old_value; 76 wxString m_new_value; 77 78 // preset(root) node 79 ModelNode(Preset::Type preset_type, wxWindow* parent_win, const wxString& text, const std::string& icon_name); 80 81 // category node 82 ModelNode(ModelNode* parent, const wxString& text, const std::string& icon_name); 83 84 // group node 85 ModelNode(ModelNode* parent, const wxString& text); 86 87 // option node 88 ModelNode(ModelNode* parent, const wxString& text, const wxString& old_value, const wxString& new_value); 89 IsContainer() const90 bool IsContainer() const { return m_container; } IsToggled() const91 bool IsToggled() const { return m_toggle; } Toggle(bool toggle=true)92 void Toggle(bool toggle = true) { m_toggle = toggle; } IsRoot() const93 bool IsRoot() const { return m_parent == nullptr; } type() const94 Preset::Type type() const { return m_preset_type; } text() const95 const wxString& text() const { return m_text; } 96 GetParent()97 ModelNode* GetParent() { return m_parent; } GetChildren()98 ModelNodePtrArray& GetChildren() { return m_children; } GetNthChild(unsigned int n)99 ModelNode* GetNthChild(unsigned int n) { return m_children[n].get(); } GetChildCount() const100 unsigned int GetChildCount() const { return m_children.size(); } 101 Append(std::unique_ptr<ModelNode> child)102 void Append(std::unique_ptr<ModelNode> child) { m_children.emplace_back(std::move(child)); } 103 104 void UpdateEnabling(); 105 void UpdateIcons(); 106 }; 107 108 109 // ---------------------------------------------------------------------------- 110 // UnsavedChangesModel 111 // ---------------------------------------------------------------------------- 112 113 class UnsavedChangesModel : public wxDataViewModel 114 { 115 wxWindow* m_parent_win { nullptr }; 116 std::vector<ModelNode*> m_preset_nodes; 117 118 wxDataViewCtrl* m_ctrl{ nullptr }; 119 120 ModelNode *AddOption(ModelNode *group_node, 121 wxString option_name, 122 wxString old_value, 123 wxString new_value); 124 ModelNode *AddOptionWithGroup(ModelNode *category_node, 125 wxString group_name, 126 wxString option_name, 127 wxString old_value, 128 wxString new_value); 129 ModelNode *AddOptionWithGroupAndCategory(ModelNode *preset_node, 130 wxString category_name, 131 wxString group_name, 132 wxString option_name, 133 wxString old_value, 134 wxString new_value, 135 const std::string category_icon_name); 136 137 public: 138 enum { 139 colToggle, 140 colIconText, 141 colOldValue, 142 colNewValue, 143 colMax 144 }; 145 146 UnsavedChangesModel(wxWindow* parent); 147 ~UnsavedChangesModel(); 148 SetAssociatedControl(wxDataViewCtrl * ctrl)149 void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } 150 151 wxDataViewItem AddPreset(Preset::Type type, wxString preset_name, PrinterTechnology pt); 152 wxDataViewItem AddOption(Preset::Type type, wxString category_name, wxString group_name, wxString option_name, 153 wxString old_value, wxString new_value, const std::string category_icon_name); 154 155 void UpdateItemEnabling(wxDataViewItem item); 156 bool IsEnabledItem(const wxDataViewItem& item); 157 GetColumnCount() const158 unsigned int GetColumnCount() const override { return colMax; } 159 wxString GetColumnType(unsigned int col) const override; 160 void Rescale(); 161 162 wxDataViewItem GetParent(const wxDataViewItem& item) const override; 163 unsigned int GetChildren(const wxDataViewItem& parent, wxDataViewItemArray& array) const override; 164 165 void GetValue(wxVariant& variant, const wxDataViewItem& item, unsigned int col) const override; 166 bool SetValue(const wxVariant& variant, const wxDataViewItem& item, unsigned int col) override; 167 168 bool IsEnabled(const wxDataViewItem& item, unsigned int col) const override; 169 bool IsContainer(const wxDataViewItem& item) const override; 170 // Is the container just a header or an item with all columns 171 // In our case it is an item with all columns HasContainerColumns(const wxDataViewItem & WXUNUSED (item)) const172 bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } 173 }; 174 175 176 //------------------------------------------ 177 // UnsavedChangesDialog 178 //------------------------------------------ 179 class UnsavedChangesDialog : public DPIDialog 180 { 181 wxDataViewCtrl* m_tree { nullptr }; 182 UnsavedChangesModel* m_tree_model { nullptr }; 183 184 ScalableButton* m_save_btn { nullptr }; 185 ScalableButton* m_transfer_btn { nullptr }; 186 ScalableButton* m_discard_btn { nullptr }; 187 wxStaticText* m_action_line { nullptr }; 188 wxStaticText* m_info_line { nullptr }; 189 wxCheckBox* m_remember_choice { nullptr }; 190 191 bool m_empty_selection { false }; 192 bool m_has_long_strings { false }; 193 int m_save_btn_id { wxID_ANY }; 194 int m_move_btn_id { wxID_ANY }; 195 int m_continue_btn_id { wxID_ANY }; 196 197 std::string m_app_config_key; 198 199 enum class Action { 200 Undef, 201 Transfer, 202 Discard, 203 Save 204 }; 205 206 static constexpr char ActTransfer[] = "transfer"; 207 static constexpr char ActDiscard[] = "discard"; 208 static constexpr char ActSave[] = "save"; 209 210 // selected action after Dialog closing 211 Action m_exit_action {Action::Undef}; 212 213 struct ItemData 214 { 215 std::string opt_key; 216 wxString opt_name; 217 wxString old_val; 218 wxString new_val; 219 Preset::Type type; 220 bool is_long {false}; 221 }; 222 // tree items related to the options 223 std::map<wxDataViewItem, ItemData> m_items_map; 224 225 // preset names which are modified in SavePresetDialog and related types 226 std::vector<std::pair<std::string, Preset::Type>> names_and_types; 227 228 public: 229 UnsavedChangesDialog(const wxString& header); 230 UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset); ~UnsavedChangesDialog()231 ~UnsavedChangesDialog() {} 232 233 wxString get_short_string(wxString full_string); 234 235 void build(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header = ""); 236 void update(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header); 237 void update_tree(Preset::Type type, PresetCollection *presets); 238 void item_value_changed(wxDataViewEvent &event); 239 void context_menu(wxDataViewEvent &event); 240 void show_info_line(Action action, std::string preset_name = ""); 241 void update_config(Action action); 242 void close(Action action); 243 bool save(PresetCollection* dependent_presets); 244 save_preset() const245 bool save_preset() const { return m_exit_action == Action::Save; } transfer_changes() const246 bool transfer_changes() const { return m_exit_action == Action::Transfer; } discard() const247 bool discard() const { return m_exit_action == Action::Discard; } 248 249 // get full bundle of preset names and types for saving get_names_and_types()250 const std::vector<std::pair<std::string, Preset::Type>>& get_names_and_types() { return names_and_types; } 251 // short version of the previous function, for the case, when just one preset is modified get_preset_name()252 std::string get_preset_name() { return names_and_types[0].first; } 253 254 std::vector<std::string> get_unselected_options(Preset::Type type); 255 std::vector<std::string> get_selected_options(); 256 257 protected: 258 void on_dpi_changed(const wxRect& suggested_rect) override; 259 void on_sys_color_changed() override; 260 }; 261 262 263 //------------------------------------------ 264 // FullCompareDialog 265 //------------------------------------------ 266 class FullCompareDialog : public wxDialog 267 { 268 public: 269 FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value); ~FullCompareDialog()270 ~FullCompareDialog() {} 271 }; 272 273 } 274 } 275 276 #endif //slic3r_UnsavedChangesDialog_hpp_ 277