Update value inside TextCtrl & SpinCtrl after wxEVT_KILL_FOCES instead of wxEVT_TEXT (or wxEVT_TEXT_ENTER)

This commit is contained in:
YuSanka 2018-12-11 13:34:37 +01:00
parent c4e334f863
commit d7bc1410ee
8 changed files with 68 additions and 47 deletions

View file

@ -74,7 +74,7 @@ void Field::on_kill_focus(wxEvent& event)
event.Skip();
// call the registered function if it is available
if (m_on_kill_focus!=nullptr)
m_on_kill_focus();
m_on_kill_focus(m_opt_id);
}
void Field::on_change_field()
@ -125,9 +125,9 @@ void Field::get_value_by_opt_type(wxString& str)
case coPercents:
case coFloats:
case coFloat:{
if (m_opt.type == coPercent && str.Last() == '%')
if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%')
str.RemoveLast();
else if (str.Last() == '%') {
else if (!str.IsEmpty() && str.Last() == '%') {
wxString label = m_Label->GetLabel();
if (label.Last() == '\n') label.RemoveLast();
while (label.Last() == ' ') label.RemoveLast();
@ -162,7 +162,7 @@ void Field::get_value_by_opt_type(wxString& str)
}
}
bool TextCtrl::is_defined_input_value()
bool TextCtrl::is_defined_input_value() const
{
if (static_cast<wxTextCtrl*>(window)->GetValue().empty() && m_opt.type != coString && m_opt.type != coStrings)
return false;
@ -216,7 +216,7 @@ void TextCtrl::BUILD() {
break;
}
const long style = m_opt.multiline ? wxTE_MULTILINE : 0 | m_process_enter ? wxTE_PROCESS_ENTER : 0;
const long style = m_opt.multiline ? wxTE_MULTILINE : 0;
auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style);
temp->SetToolTip(get_tooltip_text(text_value));
@ -240,17 +240,13 @@ void TextCtrl::BUILD() {
e.Skip();
temp->GetToolTip()->Enable(true);
#endif // __WXGTK__
if (!is_defined_input_value())
// if (!is_defined_input_value())
if (is_defined_input_value())
on_change_field();
else
on_kill_focus(e);
}), temp->GetId());
if (m_process_enter) {
temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent& evt) {
if(is_defined_input_value())
on_change_field();
}), temp->GetId());
}
else {
/*
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt)
{
#ifdef __WXGTK__
@ -267,8 +263,7 @@ void TextCtrl::BUILD() {
temp->Bind(wxEVT_KEY_DOWN, &TextCtrl::change_field_value, this);
temp->Bind(wxEVT_KEY_UP, &TextCtrl::change_field_value, this);
#endif //__WXGTK__
}
*/
// select all text using Ctrl+A
temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
{
@ -371,7 +366,15 @@ void SpinCtrl::BUILD() {
0, min_val, max_val, default_value);
// temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { tmp_value = undef_spin_val; on_change_field(); }), temp->GetId());
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { on_kill_focus(e); }), temp->GetId());
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e)
{
if (tmp_value < 0)
on_kill_focus(e);
else {
e.Skip();
on_change_field();
}
}), temp->GetId());
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
{
// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
@ -382,7 +385,8 @@ void SpinCtrl::BUILD() {
std::string value = e.GetString().utf8_str().data();
if (is_matched(value, "^\\d+$"))
tmp_value = std::stoi(value);
on_change_field();
else tmp_value = -9999;
// on_change_field();
// # We don't reset tmp_value here because _on_change might put callbacks
// # in the CallAfter queue, and we want the tmp value to be available from
// # them as well.

View file

@ -29,8 +29,8 @@ namespace Slic3r { namespace GUI {
class Field;
using t_field = std::unique_ptr<Field>;
using t_kill_focus = std::function<void()>;
using t_change = std::function<void(t_config_option_key, const boost::any&)>;
using t_kill_focus = std::function<void(const std::string&)>;
using t_change = std::function<void(const t_config_option_key&, const boost::any&)>;
using t_back_to_init = std::function<void(const std::string&)>;
wxString double_to_string(double const value, const int max_precision = 4);
@ -139,10 +139,9 @@ public:
/// Factory method for generating new derived classes.
template<class T>
static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id, const bool process_enter = false)// interface for creating shared objects
static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id)// interface for creating shared objects
{
auto p = Slic3r::make_unique<T>(parent, opt, id);
p->m_process_enter = process_enter;
p->PostInitialize();
return std::move(p); //!p;
}
@ -223,9 +222,6 @@ protected:
// current value
boost::any m_value;
//this variable shows a mode of a call of the on_change function
bool m_process_enter { false };
friend class OptionsGroup;
};
@ -265,7 +261,7 @@ public:
}
boost::any& get_value() override;
bool is_defined_input_value();
bool is_defined_input_value() const ;
virtual void enable();
virtual void disable();

View file

@ -453,7 +453,6 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
obj->SetText(wxString::Format("%d", m_objects_model->GetVolumeIdByItem(item)));
event.SetDataObject(obj);
event.SetDragFlags(/*wxDrag_AllowMove*/wxDrag_DefaultMove); // allows both copy and move;
printf("BeginDrag\n");
}
void ObjectList::OnDropPossible(wxDataViewEvent &event)
@ -464,7 +463,6 @@ void ObjectList::OnDropPossible(wxDataViewEvent &event)
if (event.GetDataFormat() != wxDF_UNICODETEXT || item.IsOk() &&
(m_objects_model->GetParent(item) == wxDataViewItem(0) || m_objects_model->GetItemType(item) != itVolume))
event.Veto();
printf("DropPossible\n");
}
void ObjectList::OnDrop(wxDataViewEvent &event)
@ -477,13 +475,14 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
event.Veto();
return;
}
printf("Drop\n");
wxTextDataObject obj;
obj.SetData(wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer());
printf("Drop\n");
int from_volume_id = std::stoi(obj.GetText().ToStdString());
int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
printf("from %d to %d\n", from_volume_id, to_volume_id);
#ifdef __WXGTK__
/* Under GTK, DnD moves an item between another two items.
@ -498,10 +497,12 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
int cnt = 0;
for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++)
std::swap(volumes[id], volumes[id + delta]);
printf("Volumes are swapped\n");
select_item(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id,
m_objects_model->GetParent(item)));
printf("ItemChildren are Reorganized\n");
m_parts_changed = true;
parts_changed(m_selected_object_id);

View file

@ -21,9 +21,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_og->set_name(_(L("Object Manipulation")));
m_og->label_width = 100;
m_og->set_grid_vgap(5);
m_og->set_process_enter(); // We need to update new values only after press ENTER
m_og->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) {
std::vector<std::string> axes{ "_x", "_y", "_z" };
if (opt_key == "scale_unit") {
@ -54,6 +53,24 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
change_scale_value(new_value);
};
m_og->m_fill_empty_value = [this](const std::string& opt_key)
{
if (opt_key == "scale_unit")
return;
std::string param;
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
if (param == "position") {
int axis = opt_key.back() == 'x' ? 0 :
opt_key.back() == 'y' ? 1 : 2;
m_og->set_value(opt_key, double_to_string(cache_position(axis)));
return;
}
m_og->set_value(opt_key, double_to_string(0.0));
};
ConfigOptionDef def;
// Objects(sub-objects) name

View file

@ -17,7 +17,7 @@ protected:
wxWindow* m_parent;
public:
OG_Settings(wxWindow* parent, const bool staticbox);
~OG_Settings() {}
virtual ~OG_Settings() {}
virtual bool IsShown();
virtual void Show(const bool show);

View file

@ -44,7 +44,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
case coPercents:
case coString:
case coStrings:
m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(parent(), opt, id, process_enter)));
m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(parent(), opt, id)));
break;
case coBool:
case coBools:
@ -67,16 +67,16 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
}
// Grab a reference to fields for convenience
const t_field& field = m_fields[id];
field->m_on_change = [this](std::string opt_id, boost::any value) {
field->m_on_change = [this](const std::string& opt_id, const boost::any& value) {
//! This function will be called from Field.
//! Call OptionGroup._on_change(...)
if (!m_disabled)
this->on_change_OG(opt_id, value);
};
field->m_on_kill_focus = [this]() {
field->m_on_kill_focus = [this](const std::string& opt_id) {
//! This function will be called from Field.
if (!m_disabled)
this->on_kill_focus();
this->on_kill_focus(opt_id);
};
field->m_parent = parent();
@ -378,6 +378,15 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config,
on_change_OG(opt_key, get_value(opt_key));
}
void ConfigOptionsGroup::on_kill_focus(const std::string& opt_key)
{
if (m_fill_empty_value) {
m_fill_empty_value(opt_key);
return;
}
reload_config();
}
void ConfigOptionsGroup::reload_config() {
for (t_opt_map::iterator it = m_opt_map.begin(); it != m_opt_map.end(); ++it) {
auto opt_id = it->first;

View file

@ -85,7 +85,8 @@ public:
size_t label_width {200};
wxSizer* sizer {nullptr};
column_t extra_column {nullptr};
t_change m_on_change {nullptr};
t_change m_on_change { nullptr };
t_kill_focus m_fill_empty_value { nullptr };
std::function<DynamicPrintConfig()> m_get_initial_config{ nullptr };
std::function<DynamicPrintConfig()> m_get_sys_config{ nullptr };
std::function<bool()> have_sys_config{ nullptr };
@ -94,8 +95,6 @@ public:
wxFont label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
int sidetext_width{ -1 };
bool process_enter { false };
/// Returns a copy of the pointer of the parent wxWindow.
/// Accessor function is because users are not allowed to change the parent
/// but defining it as const means a lot of const_casts to deal with wx functions.
@ -154,11 +153,6 @@ public:
m_show_modified_btns = show;
}
// The controls inside this option group will generate the event wxEVT_TEXT_ENTER
void set_process_enter() {
process_enter = true;
}
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
column_t extra_clmn = nullptr) :
m_parent(_parent), title(title),
@ -215,7 +209,7 @@ protected:
const t_field& build_field(const Option& opt, wxStaticText* label = nullptr);
void add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& field);
virtual void on_kill_focus () {};
virtual void on_kill_focus(const std::string& opt_key) {};
virtual void on_change_OG(const t_config_option_key& opt_id, const boost::any& value);
virtual void back_to_initial_value(const std::string& opt_key) {}
virtual void back_to_sys_value(const std::string& opt_key) {}
@ -251,7 +245,7 @@ public:
void back_to_initial_value(const std::string& opt_key) override;
void back_to_sys_value(const std::string& opt_key) override;
void back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key);
void on_kill_focus() override{ reload_config();}
void on_kill_focus(const std::string& opt_key) override;// { reload_config(); }
void reload_config();
// return value shows visibility : false => all options are hidden
void Hide();

View file

@ -270,7 +270,7 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str
auto panel = this;
#endif
PageShp page(new Page(panel, title, icon_idx));
page->SetScrollbars(1, 1, 1, 1);
page->SetScrollbars(1, 1, 1, 2);
page->Hide();
m_hsizer->Add(page.get(), 1, wxEXPAND | wxLEFT, 5);