From 1d10a2293a0eb675a723704ca7cec9b378c48bcb Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Sun, 21 Jan 2018 23:35:00 +0100
Subject: [PATCH] Example implementation of C++ to Perl callbacks using
 wxWidgets command events.

---
 lib/Slic3r/GUI/MainFrame.pm | 23 ++++++++++++++++++++---
 xs/src/slic3r/GUI/GUI.cpp   | 17 ++++++++++++-----
 xs/src/slic3r/GUI/GUI.hpp   |  2 +-
 xs/src/slic3r/GUI/Tab.cpp   | 26 +++++++++++++++++++++++---
 xs/src/slic3r/GUI/Tab.h     | 23 +++++++++++++++--------
 xs/xsp/GUI.xsp              |  4 ++--
 6 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm
index d75c0e6f8..e6bcf4ec2 100644
--- a/lib/Slic3r/GUI/MainFrame.pm
+++ b/lib/Slic3r/GUI/MainFrame.pm
@@ -11,13 +11,19 @@ use List::Util qw(min first);
 use Slic3r::Geometry qw(X Y);
 use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog
     :font :icon wxTheApp);
-use Wx::Event qw(EVT_CLOSE EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED);
+use Wx::Event qw(EVT_CLOSE EVT_COMMAND EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED);
 use base 'Wx::Frame';
 
 our $qs_last_input_file;
 our $qs_last_output_file;
 our $last_config;
 
+# Events to be sent from a C++ Tab implementation:
+# 1) To inform about a change of a configuration value.
+our $VALUE_CHANGE_EVENT    = Wx::NewEventType;
+# 2) To inform about a preset selection change or a "modified" status change.
+our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
+
 sub new {
     my ($class, %params) = @_;
     
@@ -151,8 +157,19 @@ sub _init_tabpanel {
         $panel->AddPage($tab, $tab->title);
     }
 
-#TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view.
-    Slic3r::GUI::create_preset_tabs(wxTheApp->{preset_bundle}, wxTheApp->{app_config});
+    #TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view.
+    # The following event is emited by the C++ Tab implementation on config value change.
+    EVT_COMMAND($self, -1, $VALUE_CHANGE_EVENT, sub {
+        my ($self, $event) = @_;
+        print "VALUE_CHANGE_EVENT: ", $event->GetString, "\n";
+    });
+    # The following event is emited by the C++ Tab implementation on preset selection,
+    # or when the preset's "modified" status changes.
+    EVT_COMMAND($self, -1, $PRESETS_CHANGED_EVENT, sub {
+        my ($self, $event) = @_;
+        print "PRESETS_CHANGED_EVENT: ", $event->GetString, "\n";
+    });
+    Slic3r::GUI::create_preset_tabs(wxTheApp->{preset_bundle}, wxTheApp->{app_config}, $VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
     
     if ($self->{plater}) {
         $self->{plater}->on_select_preset(sub {
diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 2953f6492..9118999ab 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -185,7 +185,7 @@ void add_debug_menu(wxMenuBar *menu)
 #endif
 }
 
-void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config)
+void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config, int event_value_change, int event_presets_changed)
 {	
 	add_created_tab(new TabPrint   (g_wxTabPanel, "Print"),    preset_bundle, app_config);
 	add_created_tab(new TabFilament(g_wxTabPanel, "Filament"), preset_bundle, app_config);
@@ -196,6 +196,13 @@ void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config)
 			panel->GetName().compare("Filament") == 0)
 			panel->OnActivate();
 	}), g_wxTabPanel->GetId() );
+	for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++ i) {
+		Tab *tab = dynamic_cast<Tab*>(g_wxTabPanel->GetPage(i));
+		if (! tab)
+			continue;
+		tab->set_event_value_change(wxEventType(event_value_change));
+		tab->set_event_presets_changed(wxEventType(event_presets_changed));
+	}
 }
 
 void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, boost::any value)
@@ -282,7 +289,7 @@ void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_con
 	panel->m_show_btn_incompatible_presets = app_config->get("show_incompatible_presets").empty();
 	panel->create_preset_tab(preset_bundle);
 	// Callback to be executed after any of the configuration fields(Perl class Slic3r::GUI::OptionsGroup::Field) change their value.
-	panel->m_on_value_change = [/*this*/](std::string opt_key, boost::any value){
+//	panel->m_on_value_change = [/*this*/](std::string opt_key, boost::any value){
 	//! plater & loaded - variables of MainFrame
 // 		if (plater) {
 // 			plater->on_config_change(m_config); //# propagate config change events to the plater
@@ -290,11 +297,11 @@ void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_con
 // 		}
 		// don't save while loading for the first time
 //		if (loaded && Slic3r::GUI::autosave) m_config->save(Slic3r::GUI::autosave) ;
-	};
+//	};
 
 	// Install a callback for the tab to update the platter and print controller presets, when
 	// a preset changes at Slic3r::GUI::Tab.
-	panel->m_on_presets_changed = [](){
+//	panel->m_on_presets_changed = [](){
 // 		if ($self->{plater}) {
 // 			# Update preset combo boxes(Print settings, Filament, Printer) from their respective tabs.
 // 			$self->{plater}->update_presets($tab_name, @_);
@@ -313,7 +320,7 @@ void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_con
 // 			}
 // 			$self->{plater}->on_config_change($tab->{presets}->get_current_preset->config);
 // 		}
-	};
+//	};
 
 	// Load the currently selected preset into the GUI, update the preset selection box.
 	panel->load_current_preset();
diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index f1b15f135..3d57b9977 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -35,7 +35,7 @@ void set_tab_panel(wxNotebook *tab_panel);
 
 void add_debug_menu(wxMenuBar *menu);
 // Create a new preset tab (print, filament and printer),
-void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config);
+void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config, int event_value_change, int event_presets_changed);
 // add it at the end of the tab panel.
 void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_config);
 // Change option value in config
diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp
index 3ebcf3405..b575e557c 100644
--- a/xs/src/slic3r/GUI/Tab.cpp
+++ b/xs/src/slic3r/GUI/Tab.cpp
@@ -269,14 +269,34 @@ void Tab::load_key_value(std::string opt_key, boost::any value)
 	update();
 }
 
+extern wxFrame *g_wxMainFrame;
+
+void Tab::on_value_change(std::string opt_key, boost::any value)
+{
+//	if (m_on_value_change != nullptr)
+//		m_on_value_change(opt_key, value);
+	if (m_event_value_change > 0) {
+		wxCommandEvent event(m_event_value_change);
+		event.SetString(opt_key);
+		g_wxMainFrame->ProcessWindowEvent(event);
+	}
+	update();
+};
+
 // Call a callback to update the selection of presets on the platter:
 // To update the content of the selection boxes,
 // to update the filament colors of the selection boxes,
 // to update the "dirty" flags of the selection boxes,
 // to uddate number of "filament" selection boxes when the number of extruders change.
-void Tab::on_presets_changed(/*std::vector<std::string> reload_dependent_tabs*/){
-	if (m_on_presets_changed != nullptr)
-		m_on_presets_changed(/*m_presets, reload_dependent_tabs*/);
+void Tab::on_presets_changed(/*std::vector<std::string> reload_dependent_tabs*/)
+{
+//	if (m_on_presets_changed != nullptr)
+//		m_on_presets_changed(/*m_presets, reload_dependent_tabs*/);
+	if (m_event_presets_changed > 0) {
+		wxCommandEvent event(m_event_presets_changed);
+		//event.SetString(opt_key);
+		g_wxMainFrame->ProcessWindowEvent(event);
+	}
 }
 
 void Tab::reload_compatible_printers_widget()
diff --git a/xs/src/slic3r/GUI/Tab.h b/xs/src/slic3r/GUI/Tab.h
index aa8008b51..14c84af08 100644
--- a/xs/src/slic3r/GUI/Tab.h
+++ b/xs/src/slic3r/GUI/Tab.h
@@ -98,14 +98,18 @@ protected:
 
 	std::vector<std::string>	m_reload_dependent_tabs = {};
 
+	// The two following two event IDs are generated at Plater.pm by calling Wx::NewEventType.
+	wxEventType			m_event_value_change = 0;
+	wxEventType 		m_event_presets_changed = 0;
+
 public:
 	PresetBundle*		m_preset_bundle;
 	bool				m_no_controller;
 	bool				m_show_btn_incompatible_presets;
 	PresetCollection*	m_presets;
 	DynamicPrintConfig*	m_config;
-	t_change			m_on_value_change{ nullptr };
-	std::function<void()>	m_on_presets_changed{ nullptr };
+//	t_change			m_on_value_change{ nullptr };
+//	std::function<void()>	m_on_presets_changed{ nullptr };
 
 public:
 	Tab() {}
@@ -116,13 +120,12 @@ public:
 
 	wxWindow*	parent() const { return m_parent; }
 	wxString	title()	 const { return m_title; }
+
+	// Set the events to the callbacks posted to the main frame window (currently implemented in Perl).
+	void 		set_event_value_change(wxEventType evt) { m_event_value_change = evt; }
+	void 		set_event_presets_changed(wxEventType evt) { m_event_presets_changed = evt; }
 	
 	void		create_preset_tab(PresetBundle *preset_bundle);
-	void		on_value_change(std::string opt_key, boost::any value){
-		if (m_on_value_change != nullptr)
-			m_on_value_change(opt_key, value);
-		update();
-	};
 	void		load_current_preset();
 	void		rebuild_page_tree();
 	void		select_preset(wxString preset_name = "");
@@ -130,7 +133,6 @@ public:
 	wxSizer*	compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn);
 
 	void		load_key_value(std::string opt_key, boost::any value);
-	void		on_presets_changed();
 	void		reload_compatible_printers_widget();
 
 	void		OnTreeSelChange(wxTreeEvent& event);
@@ -155,6 +157,11 @@ public:
 	Field*			get_field(t_config_option_key opt_key, int opt_index = -1) const;
 	bool			set_value(t_config_option_key opt_key, boost::any value);
 	wxSizer*		description_line_widget(wxWindow* parent, ogStaticText** StaticText);
+
+	void			on_value_change(std::string opt_key, boost::any value);
+
+protected:
+	void			on_presets_changed();
 };
 
 //Slic3r::GUI::Tab::Print;
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index eae1b73ea..b2f11f06f 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -35,5 +35,5 @@ void set_tab_panel(SV *ui)
 void add_debug_menu(SV *ui)
     %code%{ Slic3r::GUI::add_debug_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar")); %};
 
-void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config)
-    %code%{ Slic3r::GUI::create_preset_tabs(preset_bundle, app_config); %};
+void create_preset_tabs(PresetBundle *preset_bundle, AppConfig *app_config, int event_value_change, int event_presets_changed)
+    %code%{ Slic3r::GUI::create_preset_tabs(preset_bundle, app_config, event_value_change, event_presets_changed); %};