From 1c22d788aabc5c87e601d85aa4326fc1930f375d Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 27 Oct 2020 22:19:12 +0100
Subject: [PATCH] Custom control : Implemented blinking icon

---
 src/slic3r/GUI/Field.hpp         |  7 ++++
 src/slic3r/GUI/OG_CustomCtrl.cpp | 17 ++++----
 src/slic3r/GUI/OG_CustomCtrl.hpp |  4 +-
 src/slic3r/GUI/OptionsGroup.cpp  | 15 +++++++
 src/slic3r/GUI/OptionsGroup.hpp  |  3 ++
 src/slic3r/GUI/Tab.cpp           | 71 +++++++++++++++++++++++++-------
 src/slic3r/GUI/Tab.hpp           | 10 ++++-
 7 files changed, 98 insertions(+), 29 deletions(-)

diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp
index c83c7248b..c223b5b12 100644
--- a/src/slic3r/GUI/Field.hpp
+++ b/src/slic3r/GUI/Field.hpp
@@ -227,6 +227,10 @@ public:
 		m_side_text = side_text;
     }
 
+	bool*	get_blink_ptr() {
+		return &m_blink;
+    }
+
     virtual void msw_rescale(bool rescale_sidetext = false);
     void sys_color_changed();
 
@@ -245,6 +249,7 @@ public:
 	const ScalableBitmap*	undo_to_sys_bitmap()	{ return m_undo_to_sys_bitmap; }
 	const wxString*			undo_to_sys_tooltip()	{ return m_undo_to_sys_tooltip; }
 	const wxColour*			label_color()			{ return m_label_color; }
+	const bool				blink()					{ return m_blink; }
 
 protected:
 	RevertButton*			m_Undo_btn = nullptr;
@@ -256,6 +261,8 @@ protected:
     const ScalableBitmap*   m_undo_to_sys_bitmap = nullptr;
 	const wxString*		    m_undo_to_sys_tooltip = nullptr;
 
+	bool					m_blink{ false };
+
 	BlinkingBitmap*			m_blinking_bmp{ nullptr };
 
 	wxStaticText*		m_Label = nullptr;
diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp
index 443d6c148..b21ef7e2f 100644
--- a/src/slic3r/GUI/OG_CustomCtrl.cpp
+++ b/src/slic3r/GUI/OG_CustomCtrl.cpp
@@ -426,7 +426,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
 
     if (draw_just_act_buttons) {
         if (field)
-            draw_act_bmps(dc, wxPoint(0, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp());
+            draw_act_bmps(dc, wxPoint(0, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink());
         return;
     }
 
@@ -445,7 +445,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
 
     // If there's a widget, build it and set result to the correct position.
     if (og_line.widget != nullptr) {
-        draw_blinking_bmp(dc, wxPoint(h_pos, v_pos));
+        draw_blinking_bmp(dc, wxPoint(h_pos, v_pos), og_line.blink);
         return;
     }
 
@@ -458,7 +458,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
         option_set.front().side_widget == nullptr && og_line.get_extra_widgets().size() == 0)
     {
         if (field && field->undo_to_sys_bitmap())
-            draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp());
+            draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink());
         return;
     }
 
@@ -477,7 +477,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
         }
 
         if (field && field->undo_to_sys_bitmap()) {
-            h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), bmp_rect_id++);
+            h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink(), bmp_rect_id++);
             if (field->getSizer())
             {
                 auto children = field->getSizer()->GetChildren();
@@ -559,10 +559,9 @@ wxCoord    OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr
     return pos.x + width + ctrl->m_h_gap;
 }
 
-wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, size_t rect_id)
+wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking, size_t rect_id)
 {
-//    wxBitmap bmp_blinking = create_scaled_bitmap("search_blink", ctrl);
-    wxBitmap bmp_blinking = create_scaled_bitmap("empty", ctrl);
+    wxBitmap bmp_blinking = create_scaled_bitmap(is_blinking ? "search_blink" : "empty", ctrl);
     wxCoord h_pos = pos.x;
     wxCoord v_pos = pos.y + lround((height - bmp_blinking.GetHeight()) / 2);
 
@@ -575,9 +574,9 @@ wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, size_t
     return wxPoint(h_pos, v_pos);
 }
 
-wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, size_t rect_id)
+wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id)
 {
-    pos = draw_blinking_bmp(dc, pos, rect_id);
+    pos = draw_blinking_bmp(dc, pos, is_blinking, rect_id);
     wxCoord h_pos = pos.x;
     wxCoord v_pos = pos.y;
 
diff --git a/src/slic3r/GUI/OG_CustomCtrl.hpp b/src/slic3r/GUI/OG_CustomCtrl.hpp
index dcd43fe20..dfaf97d8b 100644
--- a/src/slic3r/GUI/OG_CustomCtrl.hpp
+++ b/src/slic3r/GUI/OG_CustomCtrl.hpp
@@ -56,8 +56,8 @@ class OG_CustomCtrl :public wxControl
         void    render(wxDC& dc, wxCoord v_pos);
         wxCoord draw_mode_bmp(wxDC& dc, wxCoord v_pos);
         wxCoord draw_text      (wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width);
-        wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, size_t rect_id = 0);
-        wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, size_t rect_id = 0);
+        wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking, size_t rect_id = 0);
+        wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0);
 
         std::vector<wxRect> rects_blinking;
         std::vector<wxRect> rects_undo_icon;
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 4044e80e7..7c0ff2ee9 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -923,6 +923,21 @@ Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int op
 	return opt_id.empty() ? nullptr : get_field(opt_id);
 }
 
+std::pair<OG_CustomCtrl*, bool*> ConfigOptionsGroup::get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/)
+{
+	Field* field = get_fieldc(opt_key, opt_index);
+
+	if (field)
+		return {custom_ctrl, field->get_blink_ptr()};
+
+	for (Line& line : m_lines)
+		for (const Option& opt : line.get_options())
+			if (opt.opt_id == opt_key && line.widget)
+				return { custom_ctrl, line.get_blink_ptr() };
+
+	return { nullptr, nullptr };
+}
+
 // Change an option on m_config, possibly call ModelConfig::touch().
 void ConfigOptionsGroup::change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/)
 
diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp
index 02b641ab5..e20a92b6b 100644
--- a/src/slic3r/GUI/OptionsGroup.hpp
+++ b/src/slic3r/GUI/OptionsGroup.hpp
@@ -54,6 +54,7 @@ public:
     size_t		full_width {0}; 
 	wxStaticText**	full_Label {nullptr};
 	wxColour*	full_Label_color {nullptr};
+	bool		blink	{false};
     widget_t	widget {nullptr};
     std::function<wxWindow*(wxWindow*)>	near_label_widget{ nullptr };
 	wxWindow*	near_label_widget_win {nullptr};
@@ -71,6 +72,7 @@ public:
 
     const std::vector<widget_t>&	get_extra_widgets() const {return m_extra_widgets;}
     const std::vector<Option>&		get_options() const { return m_options; }
+	bool*							get_blink_ptr() { return &blink; }
 
 private:
 	std::vector<Option>		m_options;//! {std::vector<Option>()};
@@ -290,6 +292,7 @@ public:
 	// return option value from config 
 	boost::any	get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index = -1);
 	Field*		get_fieldc(const t_config_option_key& opt_key, int opt_index);
+	std::pair<OG_CustomCtrl*, bool*>	get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/);
 
 private:
     // Reference to libslic3r config or ModelConfig::get(), non-owning pointer.
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 78b035c28..11e4f2510 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -12,6 +12,7 @@
 #include "WipeTowerDialog.hpp"
 #include "ButtonsDescription.hpp"
 #include "Search.hpp"
+#include "OG_CustomCtrl.hpp"
 
 #include <wx/app.h>
 #include <wx/button.h>
@@ -54,7 +55,7 @@ void Tab::Highlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID
 {
     timer.SetOwner(owner, timerid);
 }
-
+/*
 void Tab::Highlighter::init(BlinkingBitmap* bmp)
 {
     if (timer.IsRunning())
@@ -67,24 +68,53 @@ void Tab::Highlighter::init(BlinkingBitmap* bmp)
     bbmp = bmp;
     bbmp->activate();
 }
+*/
+void Tab::Highlighter::init(std::pair<OG_CustomCtrl*, bool*> params)
+{
+    if (timer.IsRunning())
+        invalidate();
+    if (!params.first || !params.second)
+        return;
+
+    timer.Start(300, false);
+
+    custom_ctrl = params.first;
+    blink_ptr = params.second;
+
+    *blink_ptr = true;
+    custom_ctrl->Refresh();
+}
 
 void Tab::Highlighter::invalidate()
 {
     timer.Stop();
 
-    if (bbmp) {
-        bbmp->invalidate();
-        bbmp = nullptr;
+    //if (bbmp) {
+    //    bbmp->invalidate();
+    //    bbmp = nullptr;
+    //}
+
+    if (custom_ctrl && blink_ptr) {
+        *blink_ptr = false;
+        custom_ctrl->Refresh();
+        blink_ptr   = nullptr;
+        custom_ctrl = nullptr;
     }
+
     blink_counter = 0;
 }
 
 void Tab::Highlighter::blink()
 {
-    if (!bbmp)
+    //if (!bbmp)
+    if (custom_ctrl && blink_ptr) {
+        *blink_ptr = !*blink_ptr;
+        custom_ctrl->Refresh();
+    }
+    else
         return;
 
-    bbmp->blink();
+//    bbmp->blink();
     if ((++blink_counter) == 11)
         invalidate();
 }
@@ -1014,14 +1044,21 @@ void Tab::sys_color_changed()
 Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const
 {
     return m_active_page ? m_active_page->get_field(opt_key, opt_index) : nullptr;
+}
 
-    Field* field = nullptr;
-    for (auto page : m_pages) {
-        field = page->get_field(opt_key, opt_index);
-        if (field != nullptr)
-            return field;
+std::pair<OG_CustomCtrl*, bool*> Tab::get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/)
+{
+    if (!m_active_page)
+        return {nullptr, nullptr};
+
+    std::pair<OG_CustomCtrl*, bool*> ret = {nullptr, nullptr};
+
+    for (auto opt_group : m_active_page->m_optgroups) {
+        ret = opt_group->get_custom_ctrl_with_blinking_ptr(opt_key, opt_index);
+        if (ret.first && ret.second)
+            break;
     }
-    return field;
+    return ret;
 }
 
 Field* Tab::get_field(const t_config_option_key& opt_key, Page** selected_page, int opt_index/* = -1*/)
@@ -1165,7 +1202,8 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
     // focused selected field
     if (field) {
         field->getWindow()->SetFocus();
-        m_highlighter.init(field->blinking_bitmap());
+//        m_highlighter.init()
+//        m_highlighter.init(field->blinking_bitmap());
     }
     else if (category == "Single extruder MM setup")
     {
@@ -1176,12 +1214,13 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
         field = get_field("single_extruder_multi_material");
         if (field) {
             field->getWindow()->SetFocus();
-            m_highlighter.init(field->blinking_bitmap());
+//            m_highlighter.init(field->blinking_bitmap());
         }
     }
-    else
-        m_highlighter.init(m_blinking_ikons[opt_key]);
+    //else
+    //    m_highlighter.init(m_blinking_ikons[opt_key]);
 
+    m_highlighter.init(get_custom_ctrl_with_blinking_ptr(opt_key));
 }
 
 void Tab::apply_searcher()
diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp
index 0ebac4f7c..8c00f825c 100644
--- a/src/slic3r/GUI/Tab.hpp
+++ b/src/slic3r/GUI/Tab.hpp
@@ -40,6 +40,7 @@ namespace Slic3r {
 namespace GUI {
 
 class TabPresetComboBox;
+class OG_CustomCtrl;
 
 // Single Tab page containing a{ vsizer } of{ optgroups }
 // package Slic3r::GUI::Tab::Page;
@@ -226,13 +227,16 @@ protected:
 	struct Highlighter
 	{
 		void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY);
-		void init(BlinkingBitmap* bmp);
+//		void init(BlinkingBitmap* bmp);
+		void init(std::pair<OG_CustomCtrl*, bool*>);
 		void blink();
 		void invalidate();
 
 	private:
 
-		BlinkingBitmap*	bbmp {nullptr};
+		OG_CustomCtrl*	custom_ctrl {nullptr};
+		bool*			blink_ptr   {nullptr};
+//		BlinkingBitmap*	bbmp {nullptr};
 		int				blink_counter {0};
 	    wxTimer         timer;
 	} 
@@ -338,6 +342,8 @@ public:
     virtual void    msw_rescale();
     virtual void	sys_color_changed();
 	Field*			get_field(const t_config_option_key& opt_key, int opt_index = -1) const;
+	std::pair<OG_CustomCtrl*, bool*> get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index = -1);
+
     Field*          get_field(const t_config_option_key &opt_key, Page** selected_page, int opt_index = -1);
 	void			toggle_option(const std::string& opt_key, bool toggle, int opt_index = -1);
 	wxSizer*		description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString);