UnsavedChangesDialog improvements:
* support markup text and colored icons for cells + Extended BitmapTextRenderer for using of markup text
This commit is contained in:
parent
3cf2914a9e
commit
1674d2af29
@ -9,6 +9,12 @@
|
||||
|
||||
#include <wx/bmpcbox.h>
|
||||
#include <wx/dc.h>
|
||||
#include "wx/generic/private/markuptext.h"
|
||||
#include "wx/generic/private/rowheightcache.h"
|
||||
#include "wx/generic/private/widthcalc.h"
|
||||
#if wxUSE_ACCESSIBILITY
|
||||
#include "wx/private/markupparser.h"
|
||||
#endif // wxUSE_ACCESSIBILITY
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
@ -1575,9 +1581,44 @@ wxDataViewRenderer(wxT("PrusaDataViewBitmapText"), mode, align)
|
||||
}
|
||||
#endif // ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||
|
||||
BitmapTextRenderer::~BitmapTextRenderer()
|
||||
{
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
if (m_markupText)
|
||||
delete m_markupText;
|
||||
#endif // SUPPORTS_MARKUP
|
||||
}
|
||||
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
void BitmapTextRenderer::EnableMarkup(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (!m_markupText)
|
||||
{
|
||||
m_markupText = new wxItemMarkupText(wxString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_markupText)
|
||||
{
|
||||
delete m_markupText;
|
||||
m_markupText = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // SUPPORTS_MARKUP
|
||||
|
||||
bool BitmapTextRenderer::SetValue(const wxVariant &value)
|
||||
{
|
||||
m_value << value;
|
||||
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
if (m_markupText)
|
||||
m_markupText->SetMarkup(m_value.GetText());
|
||||
#endif // SUPPORTS_MARKUP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1589,6 +1630,11 @@ bool BitmapTextRenderer::GetValue(wxVariant& WXUNUSED(value)) const
|
||||
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
|
||||
wxString BitmapTextRenderer::GetAccessibleDescription() const
|
||||
{
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
if (m_markupText)
|
||||
return wxMarkupParser::Strip(m_text);
|
||||
#endif // SUPPORTS_MARKUP
|
||||
|
||||
return m_value.GetText();
|
||||
}
|
||||
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||
@ -1609,7 +1655,17 @@ bool BitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state)
|
||||
xoffset = icon_sz.x + 4;
|
||||
}
|
||||
|
||||
RenderText(m_value.GetText(), xoffset, rect, dc, state);
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
if (m_markupText)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
rect.x += xoffset;
|
||||
m_markupText->Render(GetView(), *dc, rect, flags, GetEllipsizeMode());
|
||||
}
|
||||
else
|
||||
#endif // SUPPORTS_MARKUP
|
||||
RenderText(m_value.GetText(), xoffset, rect, dc, state);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1618,7 +1674,23 @@ wxSize BitmapTextRenderer::GetSize() const
|
||||
{
|
||||
if (!m_value.GetText().empty())
|
||||
{
|
||||
wxSize size = GetTextExtent(m_value.GetText());
|
||||
wxSize size;
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
if (m_markupText)
|
||||
{
|
||||
wxDataViewCtrl* const view = GetView();
|
||||
wxClientDC dc(view);
|
||||
if (GetAttr().HasFont())
|
||||
dc.SetFont(GetAttr().GetEffectiveFont(view->GetFont()));
|
||||
|
||||
size = m_markupText->Measure(dc);
|
||||
}
|
||||
else
|
||||
#endif // SUPPORTS_MARKUP
|
||||
size = GetTextExtent(m_value.GetText());
|
||||
|
||||
int lines = m_value.GetText().Freq('\n') + 1;
|
||||
size.SetHeight(size.GetHeight() * lines);
|
||||
|
||||
if (m_value.GetBitmap().IsOk())
|
||||
size.x += m_value.GetBitmap().GetWidth() + 4;
|
||||
|
@ -2,9 +2,10 @@
|
||||
#define slic3r_GUI_ObjectDataViewModel_hpp_
|
||||
|
||||
#include <wx/dataview.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class ModelVolumeType : int;
|
||||
@ -83,9 +84,19 @@ public:
|
||||
) :
|
||||
wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align),
|
||||
m_parent(parent)
|
||||
{}
|
||||
{
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
m_markupText = nullptr;
|
||||
#endif // SUPPORTS_MARKUP
|
||||
}
|
||||
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||
|
||||
~BitmapTextRenderer();
|
||||
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
void EnableMarkup(bool enable = true);
|
||||
#endif // SUPPORTS_MARKUP
|
||||
|
||||
bool SetValue(const wxVariant& value);
|
||||
bool GetValue(wxVariant& value) const;
|
||||
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
|
||||
@ -114,6 +125,10 @@ private:
|
||||
DataViewBitmapText m_value;
|
||||
bool m_was_unusable_symbol{ false };
|
||||
wxWindow* m_parent{ nullptr };
|
||||
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
class wxItemMarkupText* m_markupText;
|
||||
#endif // SUPPORTS_MARKUP
|
||||
};
|
||||
|
||||
|
||||
|
@ -321,6 +321,14 @@ const Option& OptionsSearcher::get_option(size_t pos_in_filter) const
|
||||
return options[found[pos_in_filter].option_idx];
|
||||
}
|
||||
|
||||
const Option& OptionsSearcher::get_option(const std::string& opt_key) const
|
||||
{
|
||||
auto it = std::upper_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key) }));
|
||||
assert(it != options.end());
|
||||
|
||||
return options[it - options.begin()];
|
||||
}
|
||||
|
||||
void OptionsSearcher::add_key(const std::string& opt_key, const wxString& group, const wxString& category)
|
||||
{
|
||||
groups_and_categories[opt_key] = GroupAndCategory{group, category};
|
||||
|
@ -37,8 +37,8 @@ struct GroupAndCategory {
|
||||
};
|
||||
|
||||
struct Option {
|
||||
bool operator<(const Option& other) const { return other.label > this->label; }
|
||||
bool operator>(const Option& other) const { return other.label < this->label; }
|
||||
// bool operator<(const Option& other) const { return other.label > this->label; }
|
||||
bool operator<(const Option& other) const { return other.opt_key > this->opt_key; }
|
||||
|
||||
// Fuzzy matching works at a character level. Thus matching with wide characters is a safer bet than with short characters,
|
||||
// though for some languages (Chinese?) it may not work correctly.
|
||||
@ -116,12 +116,18 @@ public:
|
||||
|
||||
const FoundOption& operator[](const size_t pos) const noexcept { return found[pos]; }
|
||||
const Option& get_option(size_t pos_in_filter) const;
|
||||
const Option& get_option(const std::string& opt_key) const;
|
||||
|
||||
const std::vector<FoundOption>& found_options() { return found; }
|
||||
const GroupAndCategory& get_group_and_category (const std::string& opt_key) { return groups_and_categories[opt_key]; }
|
||||
std::string& search_string() { return search_line; }
|
||||
|
||||
void set_printer_technology(PrinterTechnology pt) { printer_technology = pt; }
|
||||
|
||||
void sort_options_by_opt_key() {
|
||||
std::sort(options.begin(), options.end(), [](const Option& o1, const Option& o2) {
|
||||
return o1.opt_key < o2.opt_key; });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -3133,8 +3133,16 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
|
||||
bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr*/, const std::string& new_printer_name /*= ""*/)
|
||||
{
|
||||
UnsavedChangesDialog dlg(m_type);
|
||||
dlg.ShowModal();
|
||||
|
||||
if (dlg.ShowModal() == wxID_CANCEL)
|
||||
return false;
|
||||
if (dlg.just_continue())
|
||||
return true;
|
||||
if (dlg.save_preset())
|
||||
// save selected changes
|
||||
return false;
|
||||
if (dlg.move_preset())
|
||||
// move selected changes
|
||||
return false;
|
||||
|
||||
if (presets == nullptr) presets = m_presets;
|
||||
// Display a dialog showing the dirty options in a human readable form.
|
||||
|
@ -13,11 +13,12 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "Tab.hpp"
|
||||
#include "ObjectDataViewModel.hpp"
|
||||
|
||||
#define FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||
#include "fts_fuzzy_match.h"
|
||||
|
||||
#include "imgui/imconfig.h"
|
||||
#include "BitmapCache.hpp"
|
||||
|
||||
using boost::optional;
|
||||
|
||||
@ -29,12 +30,39 @@ namespace GUI {
|
||||
// ModelNode: a node inside UnsavedChangesModel
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const std::map<Preset::Type, std::string> type_icon_names = {
|
||||
{Preset::TYPE_PRINT, "cog" },
|
||||
{Preset::TYPE_SLA_PRINT, "cog" },
|
||||
{Preset::TYPE_FILAMENT, "spool" },
|
||||
{Preset::TYPE_SLA_MATERIAL, "resin" },
|
||||
{Preset::TYPE_PRINTER, "sla_printer" },
|
||||
};
|
||||
|
||||
static std::string black = "#000000";
|
||||
static std::string grey = "#808080";
|
||||
static std::string orange = "#ed6b21";
|
||||
|
||||
static void color_string(wxString& str, const std::string& color)
|
||||
{
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
str = from_u8((boost::format("<span color=\"%1%\">%2%</span>") % color % into_u8(str)).str());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void make_string_bold(wxString& str)
|
||||
{
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
str = from_u8((boost::format("<b>%1%</b>") % into_u8(str)).str());
|
||||
#endif
|
||||
}
|
||||
|
||||
// preset(root) node
|
||||
ModelNode::ModelNode(const wxString& text, Preset::Type preset_type) :
|
||||
ModelNode::ModelNode(Preset::Type preset_type, const wxString& text) :
|
||||
m_parent(nullptr),
|
||||
m_preset_type(preset_type),
|
||||
m_text(text)
|
||||
{
|
||||
m_icon = create_scaled_bitmap(type_icon_names.at(preset_type));
|
||||
}
|
||||
|
||||
// group node
|
||||
@ -42,38 +70,230 @@ ModelNode::ModelNode(ModelNode* parent, const wxString& text, const std::string&
|
||||
m_parent(parent),
|
||||
m_text(text)
|
||||
{
|
||||
m_icon = create_scaled_bitmap(icon_name);
|
||||
}
|
||||
|
||||
// group node
|
||||
ModelNode::ModelNode(ModelNode* parent, const wxString& text, bool is_option) :
|
||||
// category node
|
||||
ModelNode::ModelNode(ModelNode* parent, const wxString& text) :
|
||||
m_parent(parent),
|
||||
m_text(text),
|
||||
m_container(!is_option)
|
||||
m_text(text)
|
||||
{
|
||||
}
|
||||
|
||||
wxBitmap ModelNode::get_bitmap(const wxString& color)
|
||||
{
|
||||
/* It's supposed that standard size of an icon is 48px*16px for 100% scaled display.
|
||||
* So set sizes for solid_colored icons used for filament preset
|
||||
* and scale them in respect to em_unit value
|
||||
*/
|
||||
const double em = em_unit(m_parent_win);
|
||||
const int icon_width = lround(6.4 * em);
|
||||
const int icon_height = lround(1.6 * em);
|
||||
|
||||
BitmapCache bmp_cache;
|
||||
unsigned char rgb[3];
|
||||
BitmapCache::parse_color(into_u8(color), rgb);
|
||||
// there is no need to scale created solid bitmap
|
||||
return bmp_cache.mksolid(icon_width, icon_height, rgb, true);
|
||||
}
|
||||
|
||||
// option node
|
||||
ModelNode::ModelNode(ModelNode* parent, const wxString& text, const wxString& old_value, const wxString& new_value) :
|
||||
m_parent(parent),
|
||||
m_old_color(old_value.StartsWith("#") ? old_value : ""),
|
||||
m_new_color(new_value.StartsWith("#") ? new_value : ""),
|
||||
m_container(false),
|
||||
m_text(text),
|
||||
m_old_value(old_value),
|
||||
m_new_value(new_value)
|
||||
{
|
||||
// check if old/new_value is color
|
||||
if (m_old_color.IsEmpty()) {
|
||||
if (!m_new_color.IsEmpty())
|
||||
m_old_value = _L("Undef");
|
||||
}
|
||||
else {
|
||||
m_old_color_bmp = get_bitmap(m_old_color);
|
||||
m_old_value.Clear();
|
||||
}
|
||||
|
||||
if (m_new_color.IsEmpty()) {
|
||||
if (!m_old_color.IsEmpty())
|
||||
m_new_value = _L("Undef");
|
||||
}
|
||||
else {
|
||||
m_new_color_bmp = get_bitmap(m_new_color);
|
||||
m_new_value.Clear();
|
||||
}
|
||||
|
||||
// "color" strings
|
||||
color_string(m_old_value, black);
|
||||
color_string(m_new_value, orange);
|
||||
}
|
||||
|
||||
void ModelNode::UpdateEnabling()
|
||||
{
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
auto change_text_color = [](wxString& str, const std::string& clr_from, const std::string& clr_to)
|
||||
{
|
||||
std::string old_val = into_u8(str);
|
||||
boost::replace_all(old_val, clr_from, clr_to);
|
||||
str = from_u8(old_val);
|
||||
};
|
||||
|
||||
if (!m_toggle) {
|
||||
change_text_color(m_text, black, grey);
|
||||
change_text_color(m_old_value, black, grey);
|
||||
change_text_color(m_new_value, orange,grey);
|
||||
}
|
||||
else {
|
||||
change_text_color(m_text, grey, black);
|
||||
change_text_color(m_old_value, grey, black);
|
||||
change_text_color(m_new_value, grey, orange);
|
||||
}
|
||||
#endif
|
||||
// update icons for the colors
|
||||
if (!m_old_color.IsEmpty())
|
||||
m_old_color_bmp = get_bitmap(m_toggle? m_old_color : grey);
|
||||
if (!m_new_color.IsEmpty())
|
||||
m_new_color_bmp = get_bitmap(m_toggle? m_new_color : grey);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// UnsavedChangesModel
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
UnsavedChangesModel::UnsavedChangesModel(wxWindow* parent)
|
||||
UnsavedChangesModel::UnsavedChangesModel(wxWindow* parent) :
|
||||
m_parent_win(parent)
|
||||
{
|
||||
int icon_id = 0;
|
||||
for (const std::string& icon : { "cog", "printer", "sla_printer", "spool", "resin" })
|
||||
m_icon[icon_id++] = ScalableBitmap(parent, icon);
|
||||
|
||||
m_root = new ModelNode("Preset", Preset::TYPE_INVALID);
|
||||
}
|
||||
|
||||
UnsavedChangesModel::~UnsavedChangesModel()
|
||||
{
|
||||
delete m_root;
|
||||
for (ModelNode* preset_node : m_preset_nodes)
|
||||
delete preset_node;
|
||||
}
|
||||
|
||||
wxDataViewItem UnsavedChangesModel::AddPreset(Preset::Type type, wxString preset_name)
|
||||
{
|
||||
// "color" strings
|
||||
color_string(preset_name, black);
|
||||
make_string_bold(preset_name);
|
||||
|
||||
auto preset = new ModelNode(type, preset_name);
|
||||
m_preset_nodes.emplace_back(preset);
|
||||
|
||||
wxDataViewItem child((void*)preset);
|
||||
wxDataViewItem parent(nullptr);
|
||||
|
||||
ItemAdded(parent, child);
|
||||
return child;
|
||||
}
|
||||
|
||||
ModelNode* UnsavedChangesModel::AddOption(ModelNode* group_node, wxString option_name, wxString old_value, wxString new_value)
|
||||
{
|
||||
ModelNode* option = new ModelNode(group_node, option_name, old_value, new_value);
|
||||
group_node->Append(option);
|
||||
ItemAdded(wxDataViewItem((void*)group_node), wxDataViewItem((void*)option));
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
ModelNode* UnsavedChangesModel::AddOptionWithGroup(ModelNode* category_node, wxString group_name, wxString option_name, wxString old_value, wxString new_value)
|
||||
{
|
||||
ModelNode* group_node = new ModelNode(category_node, group_name);
|
||||
category_node->Append(group_node);
|
||||
wxDataViewItem group_item = wxDataViewItem((void*)group_node);
|
||||
ItemAdded(wxDataViewItem((void*)category_node), group_item);
|
||||
m_ctrl->Expand(group_item);
|
||||
|
||||
return AddOption(group_node, option_name, old_value, new_value);
|
||||
}
|
||||
|
||||
ModelNode* UnsavedChangesModel::AddOptionWithGroupAndCategory(ModelNode* preset_node, wxString category_name, wxString group_name, wxString option_name, wxString old_value, wxString new_value)
|
||||
{
|
||||
ModelNode* category_node = new ModelNode(preset_node, category_name, "cog");
|
||||
preset_node->Append(category_node);
|
||||
ItemAdded(wxDataViewItem((void*)preset_node), wxDataViewItem((void*)category_node));
|
||||
|
||||
return AddOptionWithGroup(category_node, group_name, option_name, old_value, new_value);
|
||||
}
|
||||
|
||||
wxDataViewItem UnsavedChangesModel::AddOption(Preset::Type type, wxString category_name, wxString group_name, wxString option_name,
|
||||
wxString old_value, wxString new_value)
|
||||
{
|
||||
// "color" strings
|
||||
color_string(category_name, black);
|
||||
color_string(group_name, black);
|
||||
color_string(option_name, black);
|
||||
|
||||
// "make" strings bold
|
||||
make_string_bold(category_name);
|
||||
make_string_bold(group_name);
|
||||
|
||||
// add items
|
||||
for (ModelNode* preset : m_preset_nodes)
|
||||
if (preset->type() == type)
|
||||
{
|
||||
for (ModelNode* category : preset->GetChildren())
|
||||
if (category->text() == category_name)
|
||||
{
|
||||
for (ModelNode* group : category->GetChildren())
|
||||
if (group->text() == group_name)
|
||||
return wxDataViewItem((void*)AddOption(group, option_name, old_value, new_value));
|
||||
|
||||
return wxDataViewItem((void*)AddOptionWithGroup(category, group_name, option_name, old_value, new_value));
|
||||
}
|
||||
|
||||
return wxDataViewItem((void*)AddOptionWithGroupAndCategory(preset, category_name, group_name, option_name, old_value, new_value));
|
||||
}
|
||||
|
||||
return wxDataViewItem(nullptr);
|
||||
}
|
||||
|
||||
static void update_children(ModelNode* parent)
|
||||
{
|
||||
if (parent->IsContainer()) {
|
||||
bool toggle = parent->IsToggled();
|
||||
for (ModelNode* child : parent->GetChildren()) {
|
||||
child->Toggle(toggle);
|
||||
child->UpdateEnabling();
|
||||
update_children(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_parents(ModelNode* node)
|
||||
{
|
||||
ModelNode* parent = node->GetParent();
|
||||
if (parent) {
|
||||
bool toggle = false;
|
||||
for (ModelNode* child : parent->GetChildren()) {
|
||||
if (child->IsToggled()) {
|
||||
toggle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parent->Toggle(toggle);
|
||||
parent->UpdateEnabling();
|
||||
update_parents(parent);
|
||||
}
|
||||
}
|
||||
|
||||
void UnsavedChangesModel::UpdateItemEnabling(wxDataViewItem item)
|
||||
{
|
||||
assert(item.IsOk());
|
||||
ModelNode* node = (ModelNode*)item.GetID();
|
||||
node->UpdateEnabling();
|
||||
|
||||
update_children(node);
|
||||
update_parents(node);
|
||||
}
|
||||
|
||||
void UnsavedChangesModel::GetValue(wxVariant& variant, const wxDataViewItem& item, unsigned int col) const
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
assert(item.IsOk());
|
||||
|
||||
ModelNode* node = (ModelNode*)item.GetID();
|
||||
switch (col)
|
||||
@ -81,20 +301,14 @@ void UnsavedChangesModel::GetValue(wxVariant& variant, const wxDataViewItem& ite
|
||||
case colToggle:
|
||||
variant = node->m_toggle;
|
||||
break;
|
||||
case colTypeIcon:
|
||||
variant << node->m_type_icon;
|
||||
break;
|
||||
case colGroupIcon:
|
||||
variant << node->m_group_icon;
|
||||
break;
|
||||
case colMarkedText:
|
||||
variant =node->m_text;
|
||||
case colIconText:
|
||||
variant << DataViewBitmapText(node->m_text, node->m_icon);
|
||||
break;
|
||||
case colOldValue:
|
||||
variant =node->m_text;
|
||||
variant << DataViewBitmapText(node->m_old_value, node->m_old_color_bmp);
|
||||
break;
|
||||
case colNewValue:
|
||||
variant =node->m_text;
|
||||
variant << DataViewBitmapText(node->m_new_value, node->m_new_color_bmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -109,24 +323,27 @@ bool UnsavedChangesModel::SetValue(const wxVariant& variant, const wxDataViewIte
|
||||
ModelNode* node = (ModelNode*)item.GetID();
|
||||
switch (col)
|
||||
{
|
||||
case colIconText: {
|
||||
DataViewBitmapText data;
|
||||
data << variant;
|
||||
node->m_icon = data.GetBitmap();
|
||||
node->m_text = data.GetText();
|
||||
return true; }
|
||||
case colToggle:
|
||||
node->m_toggle = variant.GetBool();
|
||||
return true;
|
||||
case colTypeIcon:
|
||||
node->m_type_icon << variant;
|
||||
return true;
|
||||
case colGroupIcon:
|
||||
node->m_group_icon << variant;
|
||||
return true;
|
||||
case colMarkedText:
|
||||
node->m_text = variant.GetString();
|
||||
return true;
|
||||
case colOldValue:
|
||||
node->m_text = variant.GetString();
|
||||
return true;
|
||||
case colNewValue:
|
||||
node->m_text = variant.GetString();
|
||||
return true;
|
||||
case colOldValue: {
|
||||
DataViewBitmapText data;
|
||||
data << variant;
|
||||
node->m_old_color_bmp = data.GetBitmap();
|
||||
node->m_old_value = data.GetText();
|
||||
return true; }
|
||||
case colNewValue: {
|
||||
DataViewBitmapText data;
|
||||
data << variant;
|
||||
node->m_new_color_bmp = data.GetBitmap();
|
||||
node->m_new_value = data.GetText();
|
||||
return true; }
|
||||
default:
|
||||
wxLogError("UnsavedChangesModel::SetValue: wrong column");
|
||||
}
|
||||
@ -136,11 +353,11 @@ bool UnsavedChangesModel::SetValue(const wxVariant& variant, const wxDataViewIte
|
||||
bool UnsavedChangesModel::IsEnabled(const wxDataViewItem& item, unsigned int col) const
|
||||
{
|
||||
assert(item.IsOk());
|
||||
|
||||
ModelNode* node = (ModelNode*)item.GetID();
|
||||
if (col == colToggle)
|
||||
return true;
|
||||
|
||||
// disable unchecked nodes
|
||||
return !node->IsToggle();
|
||||
return ((ModelNode*)item.GetID())->IsToggled();
|
||||
}
|
||||
|
||||
wxDataViewItem UnsavedChangesModel::GetParent(const wxDataViewItem& item) const
|
||||
@ -152,7 +369,7 @@ wxDataViewItem UnsavedChangesModel::GetParent(const wxDataViewItem& item) const
|
||||
ModelNode* node = (ModelNode*)item.GetID();
|
||||
|
||||
// "MyMusic" also has no parent
|
||||
if (node == m_root)
|
||||
if (node->IsRoot())
|
||||
return wxDataViewItem(nullptr);
|
||||
|
||||
return wxDataViewItem((void*)node->GetParent());
|
||||
@ -172,8 +389,9 @@ unsigned int UnsavedChangesModel::GetChildren(const wxDataViewItem& parent, wxDa
|
||||
{
|
||||
ModelNode* node = (ModelNode*)parent.GetID();
|
||||
if (!node) {
|
||||
array.Add(wxDataViewItem((void*)m_root));
|
||||
return 1;
|
||||
for (auto preset_node : m_preset_nodes)
|
||||
array.Add(wxDataViewItem((void*)preset_node));
|
||||
return m_preset_nodes.size();
|
||||
}
|
||||
|
||||
if (node->GetChildCount() == 0)
|
||||
@ -191,13 +409,16 @@ unsigned int UnsavedChangesModel::GetChildren(const wxDataViewItem& parent, wxDa
|
||||
|
||||
wxString UnsavedChangesModel::GetColumnType(unsigned int col) const
|
||||
{
|
||||
if (col == colToggle)
|
||||
switch (col)
|
||||
{
|
||||
case colToggle:
|
||||
return "bool";
|
||||
|
||||
if (col < colMarkedText)
|
||||
return "wxBitmap";
|
||||
|
||||
return "string";
|
||||
case colIconText:
|
||||
case colOldValue:
|
||||
case colNewValue:
|
||||
default:
|
||||
return "DataViewBitmapText";//"string";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -214,43 +435,215 @@ UnsavedChangesDialog::UnsavedChangesDialog(Preset::Type type)
|
||||
int border = 10;
|
||||
int em = em_unit();
|
||||
|
||||
changes_tree = new wxDataViewCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(em * 80, em * 60), wxBORDER_SIMPLE);
|
||||
changes_tree_model = new UnsavedChangesModel(this);
|
||||
changes_tree->AssociateModel(changes_tree_model);
|
||||
m_tree = new wxDataViewCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(em * 80, em * 30), wxBORDER_SIMPLE | wxDV_VARIABLE_LINE_HEIGHT);
|
||||
m_tree_model = new UnsavedChangesModel(this);
|
||||
m_tree->AssociateModel(m_tree_model);
|
||||
m_tree_model->SetAssociatedControl(m_tree);
|
||||
|
||||
changes_tree->AppendToggleColumn(L"\u2610", UnsavedChangesModel::colToggle);//2610,11,12 //2714
|
||||
changes_tree->AppendBitmapColumn("", UnsavedChangesModel::colTypeIcon);
|
||||
changes_tree->AppendBitmapColumn("", UnsavedChangesModel::colGroupIcon);
|
||||
|
||||
wxDataViewTextRenderer* const markupRenderer = new wxDataViewTextRenderer();
|
||||
m_tree->AppendToggleColumn(/*L"\u2714"*/"", UnsavedChangesModel::colToggle, wxDATAVIEW_CELL_ACTIVATABLE, 6 * em, wxALIGN_NOT);//2610,11,12 //2714
|
||||
|
||||
BitmapTextRenderer* renderer = new BitmapTextRenderer(m_tree);
|
||||
#ifdef SUPPORTS_MARKUP
|
||||
markupRenderer->EnableMarkup();
|
||||
renderer->EnableMarkup();
|
||||
#endif
|
||||
m_tree->AppendColumn(new wxDataViewColumn("", renderer, UnsavedChangesModel::colIconText, 30 * em, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE));
|
||||
m_tree->AppendColumn(new wxDataViewColumn("Old value", renderer, UnsavedChangesModel::colOldValue, 20 * em, wxALIGN_TOP));
|
||||
m_tree->AppendColumn(new wxDataViewColumn("New value", renderer, UnsavedChangesModel::colNewValue, 20 * em, wxALIGN_TOP));
|
||||
|
||||
changes_tree->AppendColumn(new wxDataViewColumn("", markupRenderer, UnsavedChangesModel::colMarkedText, wxCOL_WIDTH_AUTOSIZE, wxALIGN_LEFT));
|
||||
changes_tree->AppendColumn(new wxDataViewColumn("Old value", markupRenderer, UnsavedChangesModel::colOldValue, wxCOL_WIDTH_AUTOSIZE, wxALIGN_LEFT));
|
||||
changes_tree->AppendColumn(new wxDataViewColumn("New value", markupRenderer, UnsavedChangesModel::colNewValue, wxCOL_WIDTH_AUTOSIZE, wxALIGN_LEFT));
|
||||
m_tree->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &UnsavedChangesDialog::item_value_changed, this);
|
||||
|
||||
wxStdDialogButtonSizer* cancel_btn = this->CreateStdDialogButtonSizer(wxCANCEL);
|
||||
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCANCEL);
|
||||
|
||||
Tab* tab = wxGetApp().get_tab(type);
|
||||
assert(tab);
|
||||
|
||||
PresetCollection* presets = tab->get_presets();
|
||||
|
||||
wxString label= from_u8((boost::format(_u8L("Save selected to preset:%1%"))% ("\"" + presets->get_selected_preset().name + "\"")).str());
|
||||
auto save_btn = new wxButton(this, m_save_btn_id = NewControlId(), label);
|
||||
save_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { close(Action::Save); });
|
||||
buttons->Insert(0, save_btn, 0, wxLEFT, 5);
|
||||
|
||||
label = from_u8((boost::format(_u8L("Move selected to preset:%1%"))% ("\"NewSelectedPreset\"")).str());
|
||||
auto move_btn = new wxButton(this, m_move_btn_id = NewControlId(), label);
|
||||
move_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { close(Action::Move); });
|
||||
buttons->Insert(1, move_btn, 0, wxLEFT, 5);
|
||||
|
||||
auto continue_btn = new wxButton(this, m_continue_btn_id = NewControlId(), _L("Continue without changes"));
|
||||
continue_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { close(Action::Continue); });
|
||||
buttons->Insert(2, continue_btn, 0, wxLEFT, 5);
|
||||
|
||||
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
topSizer->Add(new wxStaticText(this, wxID_ANY, _L("There is unsaved changes for the current preset") + ":"), 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(changes_tree, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(cancel_btn, 0, wxEXPAND | wxALL, border);
|
||||
topSizer->Add(new wxStaticText(this, wxID_ANY, _L("There is unsaved changes for") + (": \"" + tab->title() + "\"")), 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(m_tree, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(buttons, 0, wxEXPAND | wxALL, border);
|
||||
|
||||
update(type);
|
||||
|
||||
SetSizer(topSizer);
|
||||
topSizer->SetSizeHints(this);
|
||||
}
|
||||
|
||||
void UnsavedChangesDialog::item_value_changed(wxDataViewEvent& event)
|
||||
{
|
||||
if (event.GetColumn() != UnsavedChangesModel::colToggle)
|
||||
return;
|
||||
|
||||
wxDataViewItem item = event.GetItem();
|
||||
|
||||
m_tree_model->UpdateItemEnabling(item);
|
||||
m_tree->Refresh();
|
||||
}
|
||||
|
||||
void UnsavedChangesDialog::close(Action action)
|
||||
{
|
||||
m_action = action;
|
||||
this->EndModal(wxID_CLOSE);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config)
|
||||
{
|
||||
const std::vector<std::string>& names = config.def()->options.at(opt_key).enum_labels;//ConfigOptionEnum<T>::get_enum_names();
|
||||
T val = config.option<ConfigOptionEnum<T>>(opt_key)->value;
|
||||
return from_u8(_u8L(names[static_cast<int>(val)]));
|
||||
}
|
||||
|
||||
static wxString get_string_value(const std::string& opt_key, const DynamicPrintConfig& config)
|
||||
{
|
||||
wxString out;
|
||||
|
||||
// FIXME controll, if opt_key has index
|
||||
int opt_idx = 0;
|
||||
|
||||
ConfigOptionType type = config.def()->options.at(opt_key).type;
|
||||
|
||||
switch (type) {
|
||||
case coInt:
|
||||
return from_u8((boost::format("%1%") % config.opt_int(opt_key)).str());
|
||||
case coInts: {
|
||||
const ConfigOptionInts* opt = config.opt<ConfigOptionInts>(opt_key);
|
||||
if (opt)
|
||||
return from_u8((boost::format("%1%") % opt->get_at(opt_idx)).str());
|
||||
break;
|
||||
}
|
||||
case coBool:
|
||||
return config.opt_bool(opt_key) ? "true" : "false";
|
||||
case coBools: {
|
||||
const ConfigOptionBools* opt = config.opt<ConfigOptionBools>(opt_key);
|
||||
if (opt)
|
||||
return opt->get_at(opt_idx) ? "true" : "false";
|
||||
break;
|
||||
}
|
||||
case coPercent:
|
||||
return from_u8((boost::format("%1%%%") % int(config.optptr(opt_key)->getFloat())).str());
|
||||
case coPercents: {
|
||||
const ConfigOptionPercents* opt = config.opt<ConfigOptionPercents>(opt_key);
|
||||
if (opt)
|
||||
return from_u8((boost::format("%1%%%") % int(opt->get_at(opt_idx))).str());
|
||||
break;
|
||||
}
|
||||
case coFloat:
|
||||
return double_to_string(config.opt_float(opt_key));
|
||||
case coFloats: {
|
||||
const ConfigOptionFloats* opt = config.opt<ConfigOptionFloats>(opt_key);
|
||||
if (opt)
|
||||
return double_to_string(opt->get_at(opt_idx));
|
||||
break;
|
||||
}
|
||||
case coString:
|
||||
return from_u8(config.opt_string(opt_key));
|
||||
case coStrings: {
|
||||
const ConfigOptionStrings* strings = config.opt<ConfigOptionStrings>(opt_key);
|
||||
if (strings) {
|
||||
if (opt_key == "compatible_printers" || opt_key == "compatible_prints") {
|
||||
if (strings->empty())
|
||||
return _L("All");
|
||||
for (size_t id = 0; id < strings->size(); id++)
|
||||
out += from_u8(strings->get_at(id)) + "\n";
|
||||
out.RemoveLast(1);
|
||||
return out;
|
||||
}
|
||||
if (!strings->empty())
|
||||
return from_u8(strings->get_at(opt_idx));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case coFloatOrPercent: {
|
||||
const ConfigOptionFloatOrPercent* opt = config.opt<ConfigOptionFloatOrPercent>(opt_key);
|
||||
if (opt)
|
||||
out = double_to_string(opt->value) + (opt->percent ? "%" : "");
|
||||
return out;
|
||||
}
|
||||
case coEnum: {
|
||||
if (opt_key == "top_fill_pattern" ||
|
||||
opt_key == "bottom_fill_pattern" ||
|
||||
opt_key == "fill_pattern")
|
||||
return get_string_from_enum<InfillPattern>(opt_key, config);
|
||||
if (opt_key == "gcode_flavor")
|
||||
return get_string_from_enum<GCodeFlavor>(opt_key, config);
|
||||
if (opt_key == "ironing_type")
|
||||
return get_string_from_enum<IroningType>(opt_key, config);
|
||||
if (opt_key == "support_material_pattern")
|
||||
return get_string_from_enum<SupportMaterialPattern>(opt_key, config);
|
||||
if (opt_key == "seam_position")
|
||||
return get_string_from_enum<SeamPosition>(opt_key, config);
|
||||
if (opt_key == "display_orientation")
|
||||
return get_string_from_enum<SLADisplayOrientation>(opt_key, config);
|
||||
if (opt_key == "support_pillar_connection_mode")
|
||||
return get_string_from_enum<SLAPillarConnectionMode>(opt_key, config);
|
||||
break;
|
||||
}
|
||||
case coPoints: {
|
||||
/*
|
||||
if (opt_key == "bed_shape") {
|
||||
config.option<ConfigOptionPoints>(opt_key)->values = boost::any_cast<std::vector<Vec2d>>(value);
|
||||
break;
|
||||
}
|
||||
ConfigOptionPoints* vec_new = new ConfigOptionPoints{ boost::any_cast<Vec2d>(value) };
|
||||
config.option<ConfigOptionPoints>(opt_key)->set_at(vec_new, opt_index, 0);
|
||||
*/
|
||||
return "Points";
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void UnsavedChangesDialog::update(Preset::Type type)
|
||||
{
|
||||
Tab* tab = wxGetApp().get_tab(type);
|
||||
assert(tab);
|
||||
|
||||
PresetCollection* presets = tab->get_presets();
|
||||
// Display a dialog showing the dirty options in a human readable form.
|
||||
const DynamicPrintConfig& old_config = presets->get_selected_preset().config;
|
||||
const DynamicPrintConfig& new_config = presets->get_edited_preset().config;
|
||||
|
||||
m_tree_model->AddPreset(type, from_u8(presets->get_edited_preset().name));
|
||||
|
||||
Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher();
|
||||
searcher.sort_options_by_opt_key();
|
||||
|
||||
// Collect dirty options.
|
||||
for (const std::string& opt_key : presets->current_dirty_options()) {
|
||||
const Search::Option& option = searcher.get_option(opt_key);
|
||||
|
||||
m_tree_model->AddOption(type, option.category_local, option.group_local, option.label_local,
|
||||
get_string_value(opt_key, old_config), get_string_value(opt_key, new_config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
const int& em = em_unit();
|
||||
|
||||
msw_buttons_rescale(this, em, { wxID_CANCEL });
|
||||
msw_buttons_rescale(this, em, { wxID_CANCEL, m_save_btn_id, m_move_btn_id, m_continue_btn_id });
|
||||
|
||||
const wxSize& size = wxSize(80 * em, 60 * em);
|
||||
const wxSize& size = wxSize(80 * em, 30 * em);
|
||||
SetMinSize(size);
|
||||
|
||||
Fit();
|
||||
@ -260,7 +653,7 @@ void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
void UnsavedChangesDialog::on_sys_color_changed()
|
||||
{
|
||||
// msw_rescale updates just icons, so use it
|
||||
// changes_tree_model->msw_rescale();
|
||||
// m_tree_model->msw_rescale();
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
@ -31,11 +31,17 @@ WX_DEFINE_ARRAY_PTR(ModelNode*, ModelNodePtrArray);
|
||||
|
||||
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};
|
||||
|
||||
// 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.
|
||||
@ -47,23 +53,29 @@ class ModelNode
|
||||
// would be added to the control)
|
||||
bool m_container {true};
|
||||
|
||||
wxBitmap get_bitmap(const wxString& color);
|
||||
|
||||
public:
|
||||
|
||||
bool m_toggle {true};
|
||||
wxBitmap m_type_icon;
|
||||
wxBitmap m_group_icon;
|
||||
wxBitmap m_icon;
|
||||
wxBitmap m_old_color_bmp;
|
||||
wxBitmap m_new_color_bmp;
|
||||
wxString m_text;
|
||||
wxString m_old_value;
|
||||
wxString m_new_value;
|
||||
|
||||
// preset(root) node
|
||||
ModelNode(const wxString& text, Preset::Type preset_type);
|
||||
ModelNode(Preset::Type preset_type, const wxString& text);
|
||||
|
||||
// group node
|
||||
// category node
|
||||
ModelNode(ModelNode* parent, const wxString& text, const std::string& icon_name);
|
||||
|
||||
// group node
|
||||
ModelNode(ModelNode* parent, const wxString& text, bool is_option);
|
||||
ModelNode(ModelNode* parent, const wxString& text);
|
||||
|
||||
// option node
|
||||
ModelNode(ModelNode* parent, const wxString& text, const wxString& old_value, const wxString& new_value);
|
||||
|
||||
~ModelNode() {
|
||||
// free all our children nodes
|
||||
@ -75,15 +87,21 @@ public:
|
||||
}
|
||||
|
||||
bool IsContainer() const { return m_container; }
|
||||
bool IsToggle() const { return m_toggle; }
|
||||
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.Item(n); }
|
||||
unsigned int GetChildCount() const { return m_children.GetCount(); }
|
||||
|
||||
void Insert(ModelNode* child, unsigned int n) { m_children.Insert(child, n); }
|
||||
void Append(ModelNode* child) { m_children.Add(child); }
|
||||
void Insert(ModelNode* child, unsigned int n) { m_children.Insert(child, n); }
|
||||
void Append(ModelNode* child) { m_children.Add(child); }
|
||||
|
||||
void UpdateEnabling();
|
||||
};
|
||||
|
||||
|
||||
@ -93,15 +111,31 @@ public:
|
||||
|
||||
class UnsavedChangesModel : public wxDataViewModel
|
||||
{
|
||||
ModelNode* m_root;
|
||||
ScalableBitmap m_icon[5];
|
||||
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);
|
||||
|
||||
public:
|
||||
enum {
|
||||
colToggle,
|
||||
colTypeIcon,
|
||||
colGroupIcon,
|
||||
colMarkedText,
|
||||
colIconText,
|
||||
colOldValue,
|
||||
colNewValue,
|
||||
colMax
|
||||
@ -110,18 +144,28 @@ public:
|
||||
UnsavedChangesModel(wxWindow* parent);
|
||||
~UnsavedChangesModel();
|
||||
|
||||
virtual unsigned int GetColumnCount() const override { return colMax; }
|
||||
virtual wxString GetColumnType(unsigned int col) const override;
|
||||
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
|
||||
|
||||
virtual wxDataViewItem GetParent(const wxDataViewItem& item) const override;
|
||||
virtual unsigned int GetChildren(const wxDataViewItem& parent, wxDataViewItemArray& array) const override;
|
||||
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);
|
||||
|
||||
virtual void GetValue(wxVariant& variant, const wxDataViewItem& item, unsigned int col) const override;
|
||||
virtual bool SetValue(const wxVariant& variant, const wxDataViewItem& item, unsigned int col) override;
|
||||
void UpdateItemEnabling(wxDataViewItem item);
|
||||
|
||||
virtual bool IsEnabled(const wxDataViewItem& item, unsigned int col) const override;
|
||||
virtual bool IsContainer(const wxDataViewItem& item) const override;
|
||||
unsigned int GetColumnCount() const override { return colMax; }
|
||||
wxString GetColumnType(unsigned int col) const override;
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
|
||||
@ -130,14 +174,30 @@ public:
|
||||
//------------------------------------------
|
||||
class UnsavedChangesDialog : public DPIDialog
|
||||
{
|
||||
wxDataViewCtrl* changes_tree{ nullptr };
|
||||
UnsavedChangesModel* changes_tree_model{ nullptr };
|
||||
wxDataViewCtrl* m_tree { nullptr };
|
||||
UnsavedChangesModel* m_tree_model { nullptr };
|
||||
|
||||
int m_save_btn_id { wxID_ANY };
|
||||
int m_move_btn_id { wxID_ANY };
|
||||
int m_continue_btn_id { wxID_ANY };
|
||||
|
||||
enum class Action {
|
||||
Save,
|
||||
Move,
|
||||
Continue
|
||||
} m_action;
|
||||
|
||||
public:
|
||||
UnsavedChangesDialog(Preset::Type type);
|
||||
~UnsavedChangesDialog() {}
|
||||
|
||||
void ProcessSelection(wxDataViewItem selection);
|
||||
void update(Preset::Type type);
|
||||
void item_value_changed(wxDataViewEvent &event);
|
||||
void close(Action action);
|
||||
|
||||
bool save_preset() const { return m_action == Action::Save; }
|
||||
bool move_preset() const { return m_action == Action::Move; }
|
||||
bool just_continue() const { return m_action == Action::Continue; }
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
Loading…
Reference in New Issue
Block a user