2020-07-30 14:16:56 +00:00
|
|
|
#ifndef slic3r_UnsavedChangesDialog_hpp_
|
|
|
|
#define slic3r_UnsavedChangesDialog_hpp_
|
|
|
|
|
|
|
|
#include <wx/dataview.h>
|
2020-08-10 09:24:31 +00:00
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
2020-07-30 14:16:56 +00:00
|
|
|
|
|
|
|
#include "GUI_Utils.hpp"
|
|
|
|
#include "wxExtensions.hpp"
|
|
|
|
#include "libslic3r/Preset.hpp"
|
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
class ScalableButton;
|
|
|
|
class wxStaticText;
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
namespace Slic3r {
|
2020-07-30 14:16:56 +00:00
|
|
|
namespace GUI{
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ModelNode: a node inside UnsavedChangesModel
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class ModelNode;
|
|
|
|
WX_DEFINE_ARRAY_PTR(ModelNode*, ModelNodePtrArray);
|
|
|
|
|
2020-08-10 07:45:32 +00:00
|
|
|
// 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)
|
2020-07-30 14:16:56 +00:00
|
|
|
class ModelNode
|
|
|
|
{
|
2020-08-12 11:36:26 +00:00
|
|
|
wxWindow* m_parent_win{ nullptr };
|
2020-08-05 17:25:04 +00:00
|
|
|
|
2020-07-30 14:16:56 +00:00
|
|
|
ModelNode* m_parent;
|
|
|
|
ModelNodePtrArray m_children;
|
|
|
|
wxBitmap m_empty_bmp;
|
|
|
|
Preset::Type m_preset_type {Preset::TYPE_INVALID};
|
|
|
|
|
2020-08-12 11:36:26 +00:00
|
|
|
std::string m_icon_name;
|
2020-08-05 17:25:04 +00:00
|
|
|
// saved values for colors if they exist
|
|
|
|
wxString m_old_color;
|
|
|
|
wxString m_new_color;
|
|
|
|
|
2020-07-30 14:16:56 +00:00
|
|
|
// 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.GetCount()>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};
|
|
|
|
|
2020-08-10 09:24:31 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
wxIcon get_bitmap(const wxString& color);
|
|
|
|
#else
|
2020-08-05 17:25:04 +00:00
|
|
|
wxBitmap get_bitmap(const wxString& color);
|
2020-08-10 09:24:31 +00:00
|
|
|
#endif //__linux__
|
2020-08-05 17:25:04 +00:00
|
|
|
|
2020-07-30 14:16:56 +00:00
|
|
|
public:
|
|
|
|
|
|
|
|
bool m_toggle {true};
|
2020-08-10 07:45:32 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
wxIcon m_icon;
|
2020-08-10 09:24:31 +00:00
|
|
|
wxIcon m_old_color_bmp;
|
|
|
|
wxIcon m_new_color_bmp;
|
2020-08-10 07:45:32 +00:00
|
|
|
#else
|
2020-08-05 17:25:04 +00:00
|
|
|
wxBitmap m_icon;
|
|
|
|
wxBitmap m_old_color_bmp;
|
|
|
|
wxBitmap m_new_color_bmp;
|
2020-08-10 09:24:31 +00:00
|
|
|
#endif //__linux__
|
2020-07-30 14:16:56 +00:00
|
|
|
wxString m_text;
|
|
|
|
wxString m_old_value;
|
|
|
|
wxString m_new_value;
|
|
|
|
|
|
|
|
// preset(root) node
|
2020-08-12 11:36:26 +00:00
|
|
|
ModelNode(Preset::Type preset_type, const wxString& text, wxWindow* parent_win);
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
// category node
|
2020-07-30 14:16:56 +00:00
|
|
|
ModelNode(ModelNode* parent, const wxString& text, const std::string& icon_name);
|
|
|
|
|
|
|
|
// group node
|
2020-08-05 17:25:04 +00:00
|
|
|
ModelNode(ModelNode* parent, const wxString& text);
|
|
|
|
|
|
|
|
// option node
|
|
|
|
ModelNode(ModelNode* parent, const wxString& text, const wxString& old_value, const wxString& new_value);
|
2020-07-30 14:16:56 +00:00
|
|
|
|
|
|
|
~ModelNode() {
|
|
|
|
// free all our children nodes
|
|
|
|
size_t count = m_children.GetCount();
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
ModelNode* child = m_children[i];
|
|
|
|
delete child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsContainer() const { return m_container; }
|
2020-08-05 17:25:04 +00:00
|
|
|
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; }
|
2020-07-30 14:16:56 +00:00
|
|
|
|
|
|
|
ModelNode* GetParent() { return m_parent; }
|
|
|
|
ModelNodePtrArray& GetChildren() { return m_children; }
|
|
|
|
ModelNode* GetNthChild(unsigned int n) { return m_children.Item(n); }
|
|
|
|
unsigned int GetChildCount() const { return m_children.GetCount(); }
|
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
void Insert(ModelNode* child, unsigned int n) { m_children.Insert(child, n); }
|
|
|
|
void Append(ModelNode* child) { m_children.Add(child); }
|
|
|
|
|
|
|
|
void UpdateEnabling();
|
2020-08-12 11:36:26 +00:00
|
|
|
void UpdateIcons();
|
2020-07-30 14:16:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// UnsavedChangesModel
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class UnsavedChangesModel : public wxDataViewModel
|
|
|
|
{
|
2020-08-12 11:36:26 +00:00
|
|
|
wxWindow* m_parent_win { nullptr };
|
2020-08-05 17:25:04 +00:00
|
|
|
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);
|
2020-07-30 14:16:56 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
enum {
|
2020-08-06 13:54:12 +00:00
|
|
|
colToggle,
|
2020-08-07 08:21:20 +00:00
|
|
|
colIconText,
|
2020-07-30 14:16:56 +00:00
|
|
|
colOldValue,
|
|
|
|
colNewValue,
|
|
|
|
colMax
|
|
|
|
};
|
|
|
|
|
|
|
|
UnsavedChangesModel(wxWindow* parent);
|
|
|
|
~UnsavedChangesModel();
|
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
wxDataViewItem AddPreset(Preset::Type type, wxString preset_name);
|
|
|
|
wxDataViewItem AddOption(Preset::Type type, wxString category_name, wxString group_name, wxString option_name,
|
|
|
|
wxString old_value, wxString new_value);
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
void UpdateItemEnabling(wxDataViewItem item);
|
2020-08-10 09:24:31 +00:00
|
|
|
bool IsEnabledItem(const wxDataViewItem& item);
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
unsigned int GetColumnCount() const override { return colMax; }
|
|
|
|
wxString GetColumnType(unsigned int col) const override;
|
2020-08-12 11:36:26 +00:00
|
|
|
void Rescale();
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-05 17:25:04 +00:00
|
|
|
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; }
|
2020-07-30 14:16:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
// UnsavedChangesDialog
|
|
|
|
//------------------------------------------
|
|
|
|
class UnsavedChangesDialog : public DPIDialog
|
|
|
|
{
|
2020-08-05 17:25:04 +00:00
|
|
|
wxDataViewCtrl* m_tree { nullptr };
|
|
|
|
UnsavedChangesModel* m_tree_model { nullptr };
|
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
ScalableButton* m_save_btn { nullptr };
|
|
|
|
ScalableButton* m_move_btn { nullptr };
|
|
|
|
ScalableButton* m_continue_btn { nullptr };
|
2020-08-13 13:45:16 +00:00
|
|
|
wxStaticText* m_action_line { nullptr };
|
2020-08-10 17:07:45 +00:00
|
|
|
wxStaticText* m_info_line { nullptr };
|
|
|
|
|
2020-08-10 09:24:31 +00:00
|
|
|
bool m_empty_selection { false };
|
2020-08-10 17:07:45 +00:00
|
|
|
bool m_has_long_strings { false };
|
2020-08-10 09:24:31 +00:00
|
|
|
int m_save_btn_id { wxID_ANY };
|
|
|
|
int m_move_btn_id { wxID_ANY };
|
|
|
|
int m_continue_btn_id { wxID_ANY };
|
2020-08-05 17:25:04 +00:00
|
|
|
|
|
|
|
enum class Action {
|
2020-08-10 09:24:31 +00:00
|
|
|
Undef,
|
2020-08-05 17:25:04 +00:00
|
|
|
Save,
|
|
|
|
Move,
|
|
|
|
Continue
|
2020-08-10 17:07:45 +00:00
|
|
|
};
|
2020-08-10 09:24:31 +00:00
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
// selected action after Dialog closing
|
|
|
|
Action m_exit_action {Action::Undef};
|
2020-08-10 09:24:31 +00:00
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
// Action during mouse motion
|
|
|
|
Action m_motion_action {Action::Undef};
|
|
|
|
|
|
|
|
struct ItemData
|
|
|
|
{
|
|
|
|
std::string opt_key;
|
|
|
|
wxString opt_name;
|
|
|
|
wxString old_val;
|
|
|
|
wxString new_val;
|
|
|
|
bool is_long {false};
|
|
|
|
};
|
|
|
|
// tree items related to the options
|
|
|
|
std::map<wxDataViewItem, ItemData> m_items_map;
|
2020-07-30 14:16:56 +00:00
|
|
|
|
|
|
|
public:
|
2020-08-13 13:45:16 +00:00
|
|
|
UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset);
|
2020-07-30 14:16:56 +00:00
|
|
|
~UnsavedChangesDialog() {}
|
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
wxString get_short_string(wxString full_string);
|
|
|
|
|
2020-08-13 13:45:16 +00:00
|
|
|
void update(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset);
|
2020-08-05 17:25:04 +00:00
|
|
|
void item_value_changed(wxDataViewEvent &event);
|
2020-08-10 17:07:45 +00:00
|
|
|
void context_menu(wxDataViewEvent &event);
|
|
|
|
void show_info_line(Action action, std::string preset_name = "");
|
2020-08-05 17:25:04 +00:00
|
|
|
void close(Action action);
|
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
bool save_preset() const { return m_exit_action == Action::Save; }
|
|
|
|
bool move_preset() const { return m_exit_action == Action::Move; }
|
|
|
|
bool just_continue() const { return m_exit_action == Action::Continue; }
|
2020-07-30 14:16:56 +00:00
|
|
|
|
2020-08-12 15:33:22 +00:00
|
|
|
std::vector<std::string> get_unselected_options();
|
2020-08-10 09:24:31 +00:00
|
|
|
std::vector<std::string> get_selected_options();
|
|
|
|
|
2020-07-30 14:16:56 +00:00
|
|
|
protected:
|
|
|
|
void on_dpi_changed(const wxRect& suggested_rect) override;
|
|
|
|
void on_sys_color_changed() override;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2020-08-10 17:07:45 +00:00
|
|
|
//------------------------------------------
|
|
|
|
// FullCompareDialog
|
|
|
|
//------------------------------------------
|
|
|
|
class FullCompareDialog : public wxDialog
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value);
|
|
|
|
~FullCompareDialog() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2020-07-30 14:16:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif //slic3r_UnsavedChangesDialog_hpp_
|