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