summaryrefslogtreecommitdiffstats
path: root/src/ui/widget/scrollprotected.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/widget/scrollprotected.h')
-rw-r--r--src/ui/widget/scrollprotected.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/ui/widget/scrollprotected.h b/src/ui/widget/scrollprotected.h
new file mode 100644
index 0000000..c060398
--- /dev/null
+++ b/src/ui/widget/scrollprotected.h
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef SEEN_INKSCAPE_UI_WIDGET_SCROLLPROTECTED_H
+#define SEEN_INKSCAPE_UI_WIDGET_SCROLLPROTECTED_H
+
+/* Authors:
+ * Thomas Holder
+ * Anshudhar Kumar Singh <anshudhar2001@gmail.com>
+ *
+ * Copyright (C) 2020-2021 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <gtkmm.h>
+
+#include "scroll-utils.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+/**
+ * A class decorator which blocks the scroll event if the widget does not have
+ * focus and any ancestor is a scrollable window, and SHIFT is not pressed.
+ *
+ * For custom scroll event handlers, derived classes must implement
+ * on_safe_scroll_event instead of on_scroll_event. Directly connecting to
+ * signal_scroll_event() will bypass the scroll protection.
+ *
+ * @tparam Base A subclass of Gtk::Widget
+ */
+template <typename Base>
+class ScrollProtected : public Base
+{
+public:
+ using Base::Base;
+ using typename Base::BaseObjectType;
+ ScrollProtected()
+ : Base()
+ {}
+ ScrollProtected(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &refGlade)
+ : Base(cobject){};
+ ~ScrollProtected() override{};
+
+protected:
+ /**
+ * Event handler for "safe" scroll events which are only triggered if:
+ * - the widget has focus
+ * - or the widget has no scrolled window ancestor
+ * - or the Shift key is pressed
+ */
+ virtual bool on_safe_scroll_event(GdkEventScroll *event)
+ { //
+ return Base::on_scroll_event(event);
+ }
+
+ bool on_scroll_event(GdkEventScroll *event) final
+ {
+ if (!scrolling_allowed(this, event)) {
+ return false;
+ }
+ return on_safe_scroll_event(event);
+ }
+};
+
+/**
+ * A class decorator for scroll widgets like scrolled window to transfer scroll to
+ * any ancestor which is is a scrollable window when scroll reached end.
+ *
+ * For custom scroll event handlers, derived classes must implement
+ * on_safe_scroll_event instead of on_scroll_event. Directly connecting to
+ * signal_scroll_event() will bypass the scroll protection.
+ *
+ * @tparam Base A subclass of Gtk::Widget
+ */
+template <typename Base>
+class ScrollTransfer : public Base
+{
+public:
+ using Base::Base;
+ using typename Base::BaseObjectType;
+ ScrollTransfer()
+ : Base()
+ {}
+ ScrollTransfer(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &refGlade)
+ : Base(cobject){};
+ ~ScrollTransfer() override{};
+protected:
+ /**
+ * Event handler for "safe" scroll events
+ */
+ virtual bool on_safe_scroll_event(GdkEventScroll *event)
+ { //
+ return Base::on_scroll_event(event);
+ }
+
+ bool on_scroll_event(GdkEventScroll *event) final
+ {
+ auto scrollable = dynamic_cast<Gtk::Widget *>(Inkscape::UI::Widget::get_scrollable_ancestor(this));
+ auto adj = this->get_vadjustment();
+ auto before = adj->get_value();
+ bool result = on_safe_scroll_event(event);
+ auto after = adj->get_value();
+ if (scrollable && before == after) {
+ return false;
+ }
+
+ return result;
+ }
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif
+// vim: filetype=cpp:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 :