From c18b28e27ca4acf68482f981620632d86b1ac356 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 16 Apr 2018 11:03:08 +0200
Subject: [PATCH] Implemented caching of often rendered bitmaps on the Tab UI.

---
 xs/src/slic3r/GUI/Field.cpp        |  8 ++---
 xs/src/slic3r/GUI/Field.hpp        | 32 +++++++++++++++++--
 xs/src/slic3r/GUI/OptionsGroup.cpp |  4 +--
 xs/src/slic3r/GUI/OptionsGroup.hpp |  2 +-
 xs/src/slic3r/GUI/Tab.cpp          | 50 +++++++++++++++---------------
 xs/src/slic3r/GUI/Tab.hpp          | 19 +++++++++---
 6 files changed, 76 insertions(+), 39 deletions(-)

diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp
index c68b2304c..a32943da0 100644
--- a/xs/src/slic3r/GUI/Field.cpp
+++ b/xs/src/slic3r/GUI/Field.cpp
@@ -26,16 +26,16 @@ namespace Slic3r { namespace GUI {
 			m_Undo_btn->SetBackgroundColour(color);
 			m_Undo_to_sys_btn->SetBackgroundColour(color);
 		}
-		m_Undo_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
+//		m_Undo_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
 		m_Undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_initial_value(); }));
 		m_Undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_sys_value(); }));
 
 		BUILD();
 	}
 
-	void Field::set_nonsys_btn_icon(const std::string& icon){
-		m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(icon)), wxBITMAP_TYPE_PNG));
-	}
+//	void Field::set_nonsys_btn_icon(const wxBitmap& icon){
+//		m_Undo_to_sys_btn->SetBitmap(icon);
+//	}
 
 	void Field::on_kill_focus(wxEvent& event) {
         // Without this, there will be nasty focus bugs on Windows.
diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp
index cdc7c0d81..2b2646b7c 100644
--- a/xs/src/slic3r/GUI/Field.hpp
+++ b/xs/src/slic3r/GUI/Field.hpp
@@ -91,8 +91,6 @@ public:
     virtual void		disable() = 0;
 
 	wxStaticText*		m_Label = nullptr;
-	wxButton*			m_Undo_btn = nullptr;
-	wxButton*			m_Undo_to_sys_btn = nullptr;
 
     /// Fires the enable or disable function, based on the input.
     inline void			toggle(bool en) { en ? enable() : disable(); }
@@ -100,7 +98,7 @@ public:
 	virtual wxString	get_tooltip_text(const wxString& default_string);
 
     // set icon to "UndoToSystemValue" button according to an inheritance of preset
-	void				set_nonsys_btn_icon(const std::string& icon);
+//	void				set_nonsys_btn_icon(const wxBitmap& icon);
 
     Field(const ConfigOptionDef& opt, const t_config_option_key& id) : m_opt(opt), m_opt_id(id) {};
     Field(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : m_parent(parent), m_opt(opt), m_opt_id(id) {};
@@ -120,6 +118,34 @@ public:
         p->PostInitialize();
 		return std::move(p); //!p;
     }
+
+    bool 	set_undo_bitmap(const wxBitmap *bmp) {
+    	if (m_undo_bitmap != bmp) {
+    		m_undo_bitmap = bmp;
+    		m_Undo_btn->SetBitmap(*bmp);
+    		return true;
+    	}
+    	return false;
+    }
+
+    bool 	set_undo_to_sys_bitmap(const wxBitmap *bmp) {
+    	if (m_undo_to_sys_bitmap != bmp) {
+    		m_undo_to_sys_bitmap = bmp;
+    		m_Undo_to_sys_btn->SetBitmap(*bmp);
+    		return true;
+    	}
+    	return false;
+    }
+
+protected:
+	wxButton*			m_Undo_btn = nullptr;
+	// Bitmap for m_Undo_btn. The wxButton will be updated only if the new wxBitmap pointer differs from the currently rendered one.
+	const wxBitmap*		m_undo_bitmap = nullptr;
+	wxButton*			m_Undo_to_sys_btn = nullptr;
+	// Bitmap for m_Undo_to_sys_btn. The wxButton will be updated only if the new wxBitmap pointer differs from the currently rendered one.
+	const wxBitmap*		m_undo_to_sys_bitmap = nullptr;
+
+	friend class OptionsGroup;
 };
 
 /// Convenience function, accepts a const reference to t_field and checks to see whether 
diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp
index 168ffcdc9..c71dd5ba6 100644
--- a/xs/src/slic3r/GUI/OptionsGroup.cpp
+++ b/xs/src/slic3r/GUI/OptionsGroup.cpp
@@ -90,8 +90,8 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
 		field->m_Undo_btn->Hide();
 		field->m_Undo_to_sys_btn->Hide();
 	}
-	if (nonsys_btn_icon != nullptr)
-		field->set_nonsys_btn_icon(nonsys_btn_icon());
+//	if (nonsys_btn_icon != nullptr)
+//		field->set_nonsys_btn_icon(*nonsys_btn_icon);
     
 	// assign function objects for callbacks, etc.
     return field;
diff --git a/xs/src/slic3r/GUI/OptionsGroup.hpp b/xs/src/slic3r/GUI/OptionsGroup.hpp
index dd6d48f46..92ebb4488 100644
--- a/xs/src/slic3r/GUI/OptionsGroup.hpp
+++ b/xs/src/slic3r/GUI/OptionsGroup.hpp
@@ -86,7 +86,7 @@ public:
     wxFont			sidetext_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
     wxFont			label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
 
-	std::function<std::string()>	nonsys_btn_icon{ nullptr };
+//	std::function<const wxBitmap&()>	nonsys_btn_icon{ nullptr };
 
     /// Returns a copy of the pointer of the parent wxWindow.
     /// Accessor function is because users are not allowed to change the parent
diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp
index cc4b18c7c..f2511708b 100644
--- a/xs/src/slic3r/GUI/Tab.cpp
+++ b/xs/src/slic3r/GUI/Tab.cpp
@@ -88,9 +88,9 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
 	if (wxMSW) m_btn_delete_preset->SetBackgroundColour(color);
 
 	m_show_incompatible_presets = false;
-	m_bmp_show_incompatible_presets = new wxBitmap(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG);
-	m_bmp_hide_incompatible_presets = new wxBitmap(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG);
-	m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, *m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
+	m_bmp_show_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG);
+	m_bmp_hide_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG);
+	m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
 	if (wxMSW) m_btn_hide_incompatible_presets->SetBackgroundColour(color);
 
 	m_btn_save_preset->SetToolTip(_(L("Save current ")) + m_title);
@@ -103,9 +103,16 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
 		m_undo_btn->SetBackgroundColour(color);
 		m_undo_to_sys_btn->SetBackgroundColour(color);
 	}
-	m_undo_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
+	// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
+	m_bmp_value_lock  	  .LoadFile(from_u8(var("sys_lock.png")),     wxBITMAP_TYPE_PNG);
+	m_bmp_value_unlock	  .LoadFile(from_u8(var("sys_unlock.png")),   wxBITMAP_TYPE_PNG);
+	m_bmp_non_system = &m_bmp_white_bullet;
+	// Bitmaps to be shown on the "Undo user changes" button next to each input field.
+	m_bmp_value_revert	  .LoadFile(from_u8(var("action_undo.png")),  wxBITMAP_TYPE_PNG);
+	m_bmp_white_bullet	  .LoadFile(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG);
+	m_undo_btn->SetBitmap(m_bmp_white_bullet);
 	m_undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_initial_value(); }));
-	m_undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
+	m_undo_to_sys_btn->SetBitmap(m_bmp_white_bullet);
 	m_undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_sys_value(); }));
 
 	m_hsizer = new wxBoxSizer(wxHORIZONTAL);
@@ -204,8 +211,7 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
 void Tab::load_initial_data()
 {
 	m_config = &m_presets->get_edited_preset().config;
-	m_nonsys_btn_icon = m_presets->get_selected_preset_parent() == nullptr ?
-						"bullet_white.png" : "sys_unlock.png";
+	m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet;
 }
 
 PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages/* = false*/)
@@ -334,12 +340,12 @@ void Tab::update_changed_ui()
 	{
 		bool is_nonsys_value = false;
 		bool is_modified_value = true;
-		std::string sys_icon = "sys_lock.png";
-		std::string icon = "action_undo.png";
+		const wxBitmap *sys_icon = &m_bmp_value_lock;
+		const wxBitmap *icon     = &m_bmp_value_revert;
 		wxColour color = get_sys_label_clr();
 		if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) {
 			is_nonsys_value = true;
-			sys_icon = m_nonsys_btn_icon;
+			sys_icon = m_bmp_non_system;
 			if(find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
 				color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
 			else
@@ -348,7 +354,7 @@ void Tab::update_changed_ui()
 		if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
 		{
 			is_modified_value = false;
-			icon = "bullet_white.png";
+			icon = &m_bmp_white_bullet;
 		}
 		if (opt_key == "bed_shape" || opt_key == "compatible_printers") {
 			if (m_colored_Label != nullptr)	{
@@ -362,8 +368,8 @@ void Tab::update_changed_ui()
 		if (field == nullptr) continue;
 		field->m_is_nonsys_value = is_nonsys_value;
 		field->m_is_modified_value = is_modified_value;
-		field->m_Undo_btn->SetBitmap(wxBitmap(from_u8(var(icon)), wxBITMAP_TYPE_PNG));
-		field->m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(sys_icon)), wxBITMAP_TYPE_PNG));
+		field->set_undo_bitmap(icon);
+		field->set_undo_to_sys_bitmap(sys_icon);
 		if (field->m_Label != nullptr){
 			field->m_Label->SetForegroundColour(color);
 			field->m_Label->Refresh(true);
@@ -420,7 +426,7 @@ void Tab::update_sys_ui_after_sel_preset()
 	for (const auto opt_key : m_full_options_list){
 		Field* field = get_field(opt_key);
 		if (field != nullptr){
-			field->m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(m_nonsys_btn_icon)), wxBITMAP_TYPE_PNG));
+			field->set_undo_to_sys_bitmap(m_bmp_non_system);
 			field->m_is_nonsys_value = true;
 			if (field->m_Label != nullptr){
 				field->m_Label->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
@@ -493,11 +499,8 @@ void Tab::update_changed_tree_ui()
 
 void Tab::update_undo_buttons()
 {
-	const std::string& undo_icon = !m_is_modified_values ? "bullet_white.png" : "action_undo.png";
-	const std::string& undo_to_sys_icon = m_is_nonsys_values ? m_nonsys_btn_icon : "sys_lock.png";
-
-	m_undo_btn->SetBitmap(wxBitmap(from_u8(var(undo_icon)), wxBITMAP_TYPE_PNG));
-	m_undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(undo_to_sys_icon)), wxBITMAP_TYPE_PNG));
+	m_undo_btn->SetBitmap(m_is_modified_values ? m_bmp_value_revert : m_bmp_white_bullet);
+	m_undo_to_sys_btn->SetBitmap(m_is_nonsys_values ? *m_bmp_non_system : m_bmp_value_lock);
 }
 
 void Tab::on_back_to_initial_value()
@@ -1853,8 +1856,7 @@ void Tab::load_current_preset()
 	on_preset_loaded();
 	// Reload preset pages with the new configuration values.
 	reload_config();
-	const Preset* parent = m_presets->get_selected_preset_parent();
-	m_nonsys_btn_icon = parent == nullptr ? "bullet_white.png" : "sys_unlock.png";
+	m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet;
 
 	// use CallAfter because some field triggers schedule on_change calls using CallAfter,
 	// and we don't want them to be called after this update_dirty() as they would mark the 
@@ -2142,7 +2144,7 @@ void Tab::toggle_show_hide_incompatible()
 void Tab::update_show_hide_incompatible_button()
 {
 	m_btn_hide_incompatible_presets->SetBitmap(m_show_incompatible_presets ?
-		*m_bmp_show_incompatible_presets : *m_bmp_hide_incompatible_presets);
+		m_bmp_show_incompatible_presets : m_bmp_hide_incompatible_presets);
 	m_btn_hide_incompatible_presets->SetToolTip(m_show_incompatible_presets ?
 		"Both compatible an incompatible presets are shown. Click to hide presets not compatible with the current printer." :
 		"Only compatible presets are shown. Click to show both the presets compatible and not compatible with the current printer.");
@@ -2460,9 +2462,7 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la
 		return static_cast<Tab*>(GetParent())->m_presets->get_selected_preset_parent() != nullptr;
 	};
 
-	optgroup->nonsys_btn_icon = [this](){
-		return static_cast<Tab*>(GetParent())->m_nonsys_btn_icon;
-	};
+//	optgroup->nonsys_btn_icon = m_bmp_non_system;
 
 	vsizer()->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 10);
 	m_optgroups.push_back(optgroup);
diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp
index f9ee4f363..cb622582f 100644
--- a/xs/src/slic3r/GUI/Tab.hpp
+++ b/xs/src/slic3r/GUI/Tab.hpp
@@ -85,8 +85,6 @@ protected:
 	wxBitmapComboBox*	m_presets_choice;
 	wxBitmapButton*		m_btn_save_preset;
 	wxBitmapButton*		m_btn_delete_preset;
-	wxBitmap*			m_bmp_show_incompatible_presets;
-	wxBitmap*			m_bmp_hide_incompatible_presets;
 	wxBitmapButton*		m_btn_hide_incompatible_presets;
 	wxBoxSizer*			m_hsizer;
 	wxBoxSizer*			m_left_sizer;
@@ -95,11 +93,25 @@ protected:
 	wxCheckBox*			m_compatible_printers_checkbox;
 	wxButton*			m_compatible_printers_btn;
 	wxButton*			m_undo_btn;
-	wxButton*			m_undo_to_sys_btn;
+	wxButton*			m_undo_to_sys_btn;	
 	wxComboCtrl*		m_cc_presets_choice;
 	wxDataViewTreeCtrl*	m_presetctrl;
 	wxImageList*		m_preset_icons;
 
+	// Cached bitmaps.
+	// A "flag" icon to be displayned next to the preset name in the Tab's combo box.
+	wxBitmap			m_bmp_show_incompatible_presets;
+	wxBitmap			m_bmp_hide_incompatible_presets;
+	// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
+	wxBitmap 			m_bmp_value_lock;
+	wxBitmap 			m_bmp_value_unlock;
+	wxBitmap 			m_bmp_white_bullet;
+	// The following bitmap points to either m_bmp_value_unlock or m_bmp_white_bullet, depending on whether the current preset has a parent preset.
+	wxBitmap 		   *m_bmp_non_system;
+	// Bitmaps to be shown on the "Undo user changes" button next to each input field.
+	wxBitmap 			m_bmp_value_revert;
+	wxBitmap 			m_bmp_value_unmodified;
+
 	int					m_icon_count;
 	std::map<std::string, size_t>	m_icon_index;		// Map from an icon file name to its index
 	std::vector<PageShp>			m_pages;
@@ -124,7 +136,6 @@ public:
 	bool				m_show_btn_incompatible_presets = false;
 	PresetCollection*	m_presets;
 	DynamicPrintConfig*	m_config;
-	std::string			m_nonsys_btn_icon;
 	ogStaticText*		m_parent_preset_description_line;
 	wxStaticText*		m_colored_Label = nullptr;