From f353df3d053c442639209d23fba1c3fdf53c4afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sat, 8 Aug 2020 11:18:56 +0200 Subject: [PATCH] Add `DelayedCall` and integrate it into navigator and histogram - Rename `delayedconnection.h` to `delayed.h` - Align `delayed_helper::apply()` with `std::apply()` --- rtgui/adjuster.h | 2 +- rtgui/{delayedconnection.h => delayed.h} | 168 +++++++++++++++++------ rtgui/histogrampanel.cc | 30 ++-- rtgui/histogrampanel.h | 3 + rtgui/navigator.cc | 85 +++++++----- rtgui/navigator.h | 6 +- 6 files changed, 203 insertions(+), 91 deletions(-) rename rtgui/{delayedconnection.h => delayed.h} (60%) diff --git a/rtgui/adjuster.h b/rtgui/adjuster.h index f26137f71..abafbd730 100644 --- a/rtgui/adjuster.h +++ b/rtgui/adjuster.h @@ -19,7 +19,7 @@ #pragma once #include "editedstate.h" -#include "delayedconnection.h" +#include "delayed.h" #include "guiutils.h" class Adjuster; diff --git a/rtgui/delayedconnection.h b/rtgui/delayed.h similarity index 60% rename from rtgui/delayedconnection.h rename to rtgui/delayed.h index 28c5f0421..cf4f22bf8 100644 --- a/rtgui/delayedconnection.h +++ b/rtgui/delayed.h @@ -20,13 +20,136 @@ #pragma once #include +#include #include #include #include +#include "../rtengine/noncopyable.h" + +namespace delayed_helper +{ + + // C++14 + + // See https://gist.github.com/ntessore/dc17769676fb3c6daa1f + template + struct index_sequence + { + }; + + template + struct make_index_sequence : + make_index_sequence + { + }; + + template + struct make_index_sequence<0, Is...> : + index_sequence + { + }; + + // C++17 + + // See https://aherrmann.github.io/programming/2016/02/28/unpacking-tuples-in-cpp14/ + template + constexpr void apply_impl(F f, T t, index_sequence) + { + f(std::get(t)...); + } + + template + constexpr void apply(F f, T t) + { + apply_impl(f, t, make_index_sequence{}>{}); + } + +} + template -class DelayedConnection final +class DelayedCall final : + public rtengine::NonCopyable +{ +public: + DelayedCall(std::function _function, unsigned int _min_delay_ms, unsigned int _max_delay_ms = 0) : + function(_function), + min_delay_ms(_min_delay_ms), + max_delay_ms(_max_delay_ms) + { + } + + DelayedCall(unsigned int _min_delay_ms, unsigned int _max_delay_ms = 0) : + DelayedCall({}, _min_delay_ms, _max_delay_ms) + { + } + + void setFunction(std::function function) + { + this->function = function; + } + + void operator ()(Ts... ts) + { + if (!function) { + return; + } + + if (!min_delay_ms) { + function(ts...); + return; + } + + params = std::make_tuple(ts...); + + min_timeout.disconnect(); + min_timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &DelayedCall::onMinTimeout), min_delay_ms); + + if (max_delay_ms && !max_timeout.connected()) { + max_timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &DelayedCall::onMaxTimeout), max_delay_ms); + } + } + + void cancel() + { + min_timeout.disconnect(); + max_timeout.disconnect(); + } + +private: + bool onMinTimeout() + { + max_timeout.disconnect(); + if (function) { + delayed_helper::apply(function, params); + } + return false; + } + + bool onMaxTimeout() + { + min_timeout.disconnect(); + if (function) { + delayed_helper::apply(function, params); + } + return false; + } + + std::function function; + + unsigned int min_delay_ms; + unsigned int max_delay_ms; + + sigc::connection min_timeout; + sigc::connection max_timeout; + + std::tuple params; +}; + +template +class DelayedConnection final : + public rtengine::NonCopyable { public: DelayedConnection(unsigned int _min_delay_ms, unsigned int _max_delay_ms = 0) : @@ -45,15 +168,11 @@ public: void block(bool value = true) { signal.block(value); - min_timeout.block(value); - max_timeout.block(value); } void unblock() { signal.unblock(); - min_timeout.unblock(); - max_timeout.unblock(); } void cancel() @@ -96,52 +215,17 @@ private: bool onMinTimeout() { max_timeout.disconnect(); - apply(params, slot); + delayed_helper::apply(slot, params); return false; } bool onMaxTimeout() { min_timeout.disconnect(); - apply(params, slot); + delayed_helper::apply(slot, params); return false; } - // C++14 - - // See https://gist.github.com/ntessore/dc17769676fb3c6daa1f - template - struct index_sequence - { - }; - - template - struct make_index_sequence : - make_index_sequence - { - }; - - template - struct make_index_sequence<0, Is...> : - index_sequence - { - }; - - // C++17 - - // See https://aherrmann.github.io/programming/2016/02/28/unpacking-tuples-in-cpp14/ - template - constexpr void apply_impl(T t, F f, index_sequence) - { - f(std::get(t)...); - } - - template - constexpr void apply(T t, F f) - { - apply_impl(t, f, make_index_sequence{}>{}); - } - unsigned int min_delay_ms; unsigned int max_delay_ms; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index b1c0b62df..62be4c1f4 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -32,7 +32,22 @@ using namespace rtengine; // // // HistogramPanel -HistogramPanel::HistogramPanel () +HistogramPanel::HistogramPanel() : + pointer_moved_delayed_call( + [this](bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int r, int g, int b) + { + if (!validPos) { + // do something to un-show vertical bars + histogramRGBArea->updateBackBuffer(-1, -1, -1); + } else { + // do something to show vertical bars + histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); + } + histogramRGBArea->queue_draw (); + }, + 50, + 100 + ) { setExpandAlignProperties(this, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); set_name("HistogramPanel"); @@ -192,6 +207,8 @@ HistogramPanel::HistogramPanel () HistogramPanel::~HistogramPanel () { + pointer_moved_delayed_call.cancel(); + delete redImage; delete greenImage; delete blueImage; @@ -311,15 +328,7 @@ void HistogramPanel::setHistRGBInvalid () void HistogramPanel::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) { - - if (!validPos) { - // do something to un-show vertical bars - histogramRGBArea->updateBackBuffer(-1, -1, -1); - } else { - // do something to show vertical bars - histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); - } - histogramRGBArea->queue_draw (); + pointer_moved_delayed_call(validPos, profile, profileW, r, g, b); } /* @@ -372,7 +381,6 @@ HistogramRGBArea::HistogramRGBArea () : needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), showMode(options.histogramBar), barDisplayed(options.histogramBar), parent(nullptr) { - get_style_context()->add_class("drawingarea"); set_name("HistogramRGBArea"); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 2a29ded9a..740b0a12c 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -24,6 +24,7 @@ #include +#include "delayed.h" #include "guiutils.h" #include "pointermotionlistener.h" @@ -180,6 +181,8 @@ private: class HistogramPanel final : public Gtk::Grid, public PointerMotionListener, public DrawModeListener, public rtengine::NonCopyable { +private: + DelayedCall pointer_moved_delayed_call; protected: diff --git a/rtgui/navigator.cc b/rtgui/navigator.cc index 619ea0cfd..9397cfc67 100644 --- a/rtgui/navigator.cc +++ b/rtgui/navigator.cc @@ -26,8 +26,50 @@ using namespace rtengine; -Navigator::Navigator () : currentRGBUnit(options.navRGBUnit), currentHSVUnit(options.navHSVUnit) +Navigator::Navigator() : + pointer_moved_delayed_call(50, 100), + currentRGBUnit(options.navRGBUnit), + currentHSVUnit(options.navHSVUnit) { + pointer_moved_delayed_call.setFunction( + [this](bool validPos, Glib::ustring profile, Glib::ustring profileW, int x, int y, int r, int g, int b, bool isRaw) + { + if (!validPos) { + setInvalid (x, y); + } else { + Glib::ustring s1, s2, s3; + + position->set_text (Glib::ustring::compose ("x: %1, y: %2", x, y)); + + getRGBText (r, g, b, s1, s2, s3, isRaw); + R->set_text (s1); + G->set_text (s2); + B->set_text (s3); + if (isRaw) { + H->set_text ("--"); + S->set_text ("--"); + V->set_text ("--"); + LAB_L->set_text ("--"); + LAB_A->set_text ("--"); + LAB_B->set_text ("--"); + } else { + float h, s, v; + float LAB_a, LAB_b, LAB_l; + Color::rgb2hsv01(r / 255.f, g / 255.f, b / 255.f, h, s, v); + getHSVText (h, s, v, s1, s2, s3); + H->set_text (s1); + S->set_text (s2); + V->set_text (s3); + + Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? + getLABText (LAB_l, LAB_a, LAB_b, s1, s2, s3); + LAB_L->set_text (s1); + LAB_A->set_text (s2); + LAB_B->set_text (s3); + } + } + } + ); set_label (M("MAIN_MSG_NAVIGATOR")); Gtk::VBox* mbox = Gtk::manage (new Gtk::VBox ()); @@ -202,6 +244,11 @@ Navigator::Navigator () : currentRGBUnit(options.navRGBUnit), currentHSVUnit(opt show_all (); } +Navigator::~Navigator() +{ + pointer_moved_delayed_call.cancel(); +} + void Navigator::setInvalid (int fullWidth, int fullHeight) { if (fullWidth > 0 && fullHeight > 0) { @@ -278,41 +325,7 @@ void Navigator::getLABText (float l, float a, float b, Glib::ustring &sL, Glib:: // if !validPos then x/y contain the full image size void Navigator::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) { - - if (!validPos) { - setInvalid (x, y); - } else { - Glib::ustring s1, s2, s3; - - position->set_text (Glib::ustring::compose ("x: %1, y: %2", x, y)); - - getRGBText (r, g, b, s1, s2, s3, isRaw); - R->set_text (s1); - G->set_text (s2); - B->set_text (s3); - if (isRaw) { - H->set_text ("--"); - S->set_text ("--"); - V->set_text ("--"); - LAB_L->set_text ("--"); - LAB_A->set_text ("--"); - LAB_B->set_text ("--"); - } else { - float h, s, v; - float LAB_a, LAB_b, LAB_l; - Color::rgb2hsv01(r / 255.f, g / 255.f, b / 255.f, h, s, v); - getHSVText (h, s, v, s1, s2, s3); - H->set_text (s1); - S->set_text (s2); - V->set_text (s3); - - Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? - getLABText (LAB_l, LAB_a, LAB_b, s1, s2, s3); - LAB_L->set_text (s1); - LAB_A->set_text (s2); - LAB_B->set_text (s3); - } - } + pointer_moved_delayed_call(validPos, profile, profileW, x, y, r, g, b, isRaw); } void Navigator::cycleUnitsRGB (GdkEventButton *event) { diff --git a/rtgui/navigator.h b/rtgui/navigator.h index e9d40e309..4c2a3fd32 100644 --- a/rtgui/navigator.h +++ b/rtgui/navigator.h @@ -20,6 +20,7 @@ #include +#include "delayed.h" #include "options.h" #include "pointermotionlistener.h" @@ -33,6 +34,8 @@ class Navigator final : typedef const double (*TMatrix)[3]; private: + DelayedCall pointer_moved_delayed_call; + Options::NavigatorUnit currentRGBUnit; Options::NavigatorUnit currentHSVUnit; void cycleUnitsRGB (GdkEventButton *event); @@ -53,7 +56,8 @@ protected: public: PreviewWindow* previewWindow; - Navigator (); + Navigator(); + ~Navigator() override; // pointermotionlistener interface // void pointerMoved (bool validPos, int x, int y, int r, int g, int b);