From 8133aa1324c9dde4a4f0e33ae8afe4e1cad8c147 Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Mon, 20 May 2019 13:32:36 +0200
Subject: [PATCH] Fix wxSpinCtrl in settings on Mac OS, cf. #2237

---
 src/slic3r/GUI/Field.cpp | 46 +++++++++++++++++-----------------------
 src/slic3r/GUI/Field.hpp | 12 +++++++----
 2 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 30b95d82a..01fa9eedc 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -434,7 +434,6 @@ void CheckBox::msw_rescale()
     field->SetMinSize(wxSize(-1, int(1.5f*field->GetFont().GetPixelSize().y +0.5f)));
 }
 
-int undef_spin_val = -9999;		//! Probably, It's not necessary
 
 void SpinCtrl::BUILD() {
 	auto size = wxSize(wxDefaultSize);
@@ -472,12 +471,14 @@ void SpinCtrl::BUILD() {
 	temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
 	temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
 
-#ifndef __WXOSX__
-    // #ys_FIXME_KILL_FOCUS 
-    // wxEVT_KILL_FOCUS doesn't handled on OSX now (wxWidgets 3.1.1)
-    // So, we will update values on KILL_FOCUS & SPINCTRL events under MSW and GTK
-    // and on TEXT event under OSX
+// XXX: On OS X the wxSpinCtrl widget is made up of two subwidgets, unfortunatelly
+// the kill focus event is not propagated to the encompassing widget,
+// so we need to bind it on the inner text widget instead. (Ugh.)
+#ifdef __WXOSX__
+	temp->GetText()->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e)
+#else
 	temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e)
+#endif
 	{
         e.Skip();
         if (bEnterPressed) {
@@ -486,7 +487,7 @@ void SpinCtrl::BUILD() {
         }
 
         propagate_value();
-	}), temp->GetId());
+	}));
 
     temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) {  propagate_value();  }), temp->GetId()); 
     
@@ -496,7 +497,6 @@ void SpinCtrl::BUILD() {
         propagate_value();
         bEnterPressed = true;
     }), temp->GetId());
-#endif
 
 	temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
 	{
@@ -504,24 +504,17 @@ void SpinCtrl::BUILD() {
 // 		# when it was changed from the text control, so the on_change callback
 // 		# gets the old one, and on_kill_focus resets the control to the old value.
 // 		# As a workaround, we get the new value from $event->GetString and store
-// 		# here temporarily so that we can return it from $self->get_value
-		std::string value = e.GetString().utf8_str().data();
-        if (is_matched(value, "^\\-?\\d+$")) {
-            try {
-                tmp_value = std::stoi(value);
-            }
-            catch (const std::exception & /* e */) {
-                tmp_value = -9999;
-            }
-        }
-        else tmp_value = -9999;
-#ifdef __WXOSX__
-        propagate_value();
+// 		# here temporarily so that we can return it from get_value()
 
+		long value;
+		const bool parsed = e.GetString().ToLong(&value);
+		tmp_value = parsed && value <= INT_MAX ? (int)value : UNDEF_VALUE;
+
+#ifdef __WXOSX__
         // Forcibly set the input value for SpinControl, since the value 
-	    // inserted from the clipboard is not updated under OSX
-        if (tmp_value > -9999) {
-            wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>(window);
+	    // inserted from the keyboard or clipboard is not updated under OSX
+        if (tmp_value != UNDEF_VALUE) {
+            wxSpinCtrl* spin = static_cast<wxSpinCtrl*>(window);
             spin->SetValue(tmp_value);
 
             // But in SetValue() is executed m_text_ctrl->SelectAll(), so
@@ -539,10 +532,11 @@ void SpinCtrl::BUILD() {
 
 void SpinCtrl::propagate_value()
 {
-    if (tmp_value == -9999)
+    if (tmp_value == UNDEF_VALUE) {
         on_kill_focus();
-    else if (boost::any_cast<int>(m_value) != tmp_value)
+	} else {
         on_change_field();
+    }
 }
 
 void SpinCtrl::msw_rescale()
diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp
index ae449450a..990c40e6f 100644
--- a/src/slic3r/GUI/Field.hpp
+++ b/src/slic3r/GUI/Field.hpp
@@ -7,6 +7,7 @@
 #endif
 
 #include <memory>
+#include <cstdint>
 #include <functional>
 #include <boost/any.hpp>
 
@@ -331,9 +332,11 @@ public:
 
 class SpinCtrl : public Field {
 	using Field::Field;
+private:
+	static const int UNDEF_VALUE = INT_MIN;
 public:
-	SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(-9999) {}
-	SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(-9999) {}
+	SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(UNDEF_VALUE) {}
+	SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(UNDEF_VALUE) {}
 	~SpinCtrl() {}
 
 	int				tmp_value;
@@ -355,9 +358,10 @@ public:
 		dynamic_cast<wxSpinCtrl*>(window)->SetValue(tmp_value);
 		m_disable_change_event = false;
 	}
+
 	boost::any&		get_value() override {
-// 		return boost::any(tmp_value);
-		return m_value = tmp_value;
+		int value = static_cast<wxSpinCtrl*>(window)->GetValue();
+		return m_value = value;
 	}
 
     void            msw_rescale() override;