[gnome-tour/bilelmoussaoui/fixes: 7/11] subclass PaginatorWidget




commit aa06f0f660611173781379b515236e1986fa1c96
Author: Bilal Elmoussaoui <bil elmoussaoui gmail com>
Date:   Fri Dec 31 19:00:22 2021 +0100

    subclass PaginatorWidget

 src/application.rs       |   4 +-
 src/widgets/paginator.rs | 268 +++++++++++++++++++++++++++--------------------
 src/widgets/window.rs    |  25 ++---
 3 files changed, 165 insertions(+), 132 deletions(-)
---
diff --git a/src/application.rs b/src/application.rs
index c3e9674..b808f70 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -68,7 +68,7 @@ mod imp {
                 "next-page",
                 clone!(@weak application => move |_, _| {
                     let window = application.window();
-                    if window.paginator.borrow_mut().try_next().is_none() {
+                    if window.paginator.try_next().is_none() {
                         window.widget.close();
                     }
                 }),
@@ -79,7 +79,7 @@ mod imp {
                 "previous-page",
                 clone!(@weak application => move |_, _| {
                     let window = application.window();
-                    if window.paginator.borrow_mut().try_previous().is_none() {
+                    if window.paginator.try_previous().is_none() {
                         window.reset_tour();
                     }
                 }),
diff --git a/src/widgets/paginator.rs b/src/widgets/paginator.rs
index 6a1297e..57ba15d 100644
--- a/src/widgets/paginator.rs
+++ b/src/widgets/paginator.rs
@@ -1,50 +1,140 @@
 use gettextrs::gettext;
-use gtk::glib::{self, clone};
 use gtk::prelude::*;
+use gtk::{
+    glib::{self, clone},
+    subclass::prelude::*,
+};
 use std::cell::RefCell;
-use std::rc::Rc;
-
-#[derive(Debug)]
-pub struct PaginatorWidget {
-    pub widget: gtk::Box,
-    carousel: adw::Carousel,
-    carousel_dots: adw::CarouselIndicatorDots,
-    headerbar: gtk::HeaderBar,
-    pages: RefCell<Vec<gtk::Widget>>,
-    current_page: RefCell<u32>,
-    next_overlay: gtk::Overlay,
-    next_btn: gtk::Button,
-    start_btn: gtk::Button,
-    finish_btn: gtk::Button,
-    close_btn: gtk::Button,
-    previous_btn: gtk::Button,
+
+mod imp {
+    use std::cell::Cell;
+
+    use super::*;
+
+    #[derive(Debug)]
+    pub struct PaginatorWidget {
+        pub(super) carousel: adw::Carousel,
+        pub(super) carousel_dots: adw::CarouselIndicatorDots,
+        pub(super) headerbar: gtk::HeaderBar,
+        pub(super) pages: RefCell<Vec<gtk::Widget>>,
+        pub(super) current_page: Cell<u32>,
+        pub(super) next_overlay: gtk::Overlay,
+        pub(super) next_btn: gtk::Button,
+        pub(super) start_btn: gtk::Button,
+        pub(super) finish_btn: gtk::Button,
+        pub(super) close_btn: gtk::Button,
+        pub(super) previous_btn: gtk::Button,
+    }
+
+    impl Default for PaginatorWidget {
+        fn default() -> Self {
+            Self {
+                carousel: adw::Carousel::new(),
+                carousel_dots: adw::CarouselIndicatorDots::new(),
+                headerbar: gtk::HeaderBar::builder().show_title_buttons(false).build(),
+                start_btn: gtk::Button::with_label(&gettext("_Start")),
+                next_overlay: gtk::Overlay::new(),
+                next_btn: gtk::Button::with_label(&gettext("_Next")),
+                finish_btn: gtk::Button::with_label(&gettext("_Close")),
+                close_btn: gtk::Button::with_label(&gettext("_Close")),
+                previous_btn: gtk::Button::with_label(&gettext("_Previous")),
+                pages: RefCell::new(Vec::new()),
+                current_page: Cell::new(0),
+            }
+        }
+    }
+
+    #[glib::object_subclass]
+    impl ObjectSubclass for PaginatorWidget {
+        const NAME: &'static str = "PaginatorWidget";
+        type ParentType = gtk::Box;
+        type Type = super::PaginatorWidget;
+    }
+
+    impl ObjectImpl for PaginatorWidget {
+        fn constructed(&self, obj: &Self::Type) {
+            let layout_manager = obj
+                .layout_manager()
+                .map(|l| l.downcast::<gtk::BoxLayout>().unwrap())
+                .unwrap();
+            layout_manager.set_orientation(gtk::Orientation::Vertical);
+
+            self.carousel_dots.set_carousel(Some(&self.carousel));
+            self.carousel.set_hexpand(true);
+            self.carousel.set_vexpand(true);
+            self.carousel
+                .set_scroll_params(&adw::SpringParams::new(1.0, 0.5, 300.0));
+
+            self.carousel
+                .connect_position_notify(clone!(@weak obj => move |_| {
+                    obj.update_position();
+                }));
+            self.start_btn.add_css_class("suggested-action");
+            self.start_btn.set_use_underline(true);
+            self.start_btn.set_action_name(Some("app.start-tour"));
+
+            self.next_btn.add_css_class("suggested-action");
+            self.next_btn.set_use_underline(true);
+            self.next_btn.set_action_name(Some("app.next-page"));
+
+            self.close_btn.set_use_underline(true);
+            self.close_btn.set_action_name(Some("app.quit"));
+
+            self.finish_btn.add_css_class("suggested-action");
+            self.finish_btn.set_use_underline(true);
+            self.finish_btn.set_action_name(Some("app.quit"));
+
+            self.previous_btn.set_use_underline(true);
+            self.previous_btn.set_action_name(Some("app.previous-page"));
+
+            self.next_overlay.set_child(Some(&self.next_btn));
+            self.next_overlay.add_overlay(&self.finish_btn);
+            self.next_overlay.set_can_target(false);
+
+            let previous_overlay = gtk::Overlay::new();
+            previous_overlay.set_child(Some(&self.close_btn));
+            previous_overlay.add_overlay(&self.previous_btn);
+
+            let start_overlay = gtk::Overlay::new();
+            start_overlay.set_child(Some(&self.start_btn));
+            start_overlay.add_overlay(&self.next_overlay);
+
+            let btn_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal);
+            btn_size_group.add_widget(&self.previous_btn);
+            btn_size_group.add_widget(&self.close_btn);
+            btn_size_group.add_widget(&self.next_overlay);
+            btn_size_group.add_widget(&start_overlay);
+            btn_size_group.add_widget(&self.finish_btn);
+
+            self.headerbar.set_title_widget(Some(&self.carousel_dots));
+            self.headerbar.pack_start(&previous_overlay);
+            self.headerbar.pack_end(&start_overlay);
+
+            obj.append(&self.headerbar);
+            obj.append(&self.carousel);
+
+            self.parent_constructed(obj);
+        }
+    }
+    impl WidgetImpl for PaginatorWidget {}
+    impl BoxImpl for PaginatorWidget {}
+}
+
+glib::wrapper! {
+    pub struct PaginatorWidget(ObjectSubclass<imp::PaginatorWidget>)
+        @extends gtk::Widget, gtk::Box;
+
 }
 
 impl PaginatorWidget {
-    pub fn new() -> Rc<Self> {
-        let widget = gtk::Box::new(gtk::Orientation::Vertical, 0);
-
-        let paginator = Rc::new(Self {
-            widget,
-            carousel: adw::Carousel::new(),
-            carousel_dots: adw::CarouselIndicatorDots::new(),
-            headerbar: gtk::HeaderBar::builder().show_title_buttons(false).build(),
-            start_btn: gtk::Button::with_label(&gettext("_Start")),
-            next_overlay: gtk::Overlay::new(),
-            next_btn: gtk::Button::with_label(&gettext("_Next")),
-            finish_btn: gtk::Button::with_label(&gettext("_Close")),
-            close_btn: gtk::Button::with_label(&gettext("_Close")),
-            previous_btn: gtk::Button::with_label(&gettext("_Previous")),
-            pages: RefCell::new(Vec::new()),
-            current_page: RefCell::new(0),
-        });
-        paginator.init(paginator.clone());
-        paginator
+    pub fn new() -> Self {
+        glib::Object::new(&[]).unwrap()
     }
 
     pub fn try_next(&self) -> Option<()> {
-        let p = *self.current_page.borrow() + 1;
-        if p == self.carousel.n_pages() {
+        let imp = self.imp();
+        let p = imp.current_page.get() + 1;
+        if p == imp.carousel.n_pages() {
             return None;
         }
         self.set_page(p);
@@ -52,7 +142,7 @@ impl PaginatorWidget {
     }
 
     pub fn try_previous(&self) -> Option<()> {
-        let p = *self.current_page.borrow();
+        let p = self.imp().current_page.get();
         if p == 0 {
             return None;
         }
@@ -61,18 +151,21 @@ impl PaginatorWidget {
     }
 
     pub fn add_page(&self, page: gtk::Widget) {
-        let page_nr = self.pages.borrow().len();
-        self.carousel.insert(&page, page_nr as i32);
-        self.pages.borrow_mut().push(page);
+        let imp = self.imp();
+        let page_nr = imp.pages.borrow().len();
+        imp.carousel.insert(&page, page_nr as i32);
+        imp.pages.borrow_mut().push(page);
 
         self.update_position();
     }
 
     fn update_position(&self) {
-        let position = self.carousel.position();
+        let imp = self.imp();
+
+        let position = imp.carousel.position();
         let page_nr = position.round() as u32;
 
-        let n_pages = self.carousel.n_pages() as f64;
+        let n_pages = imp.carousel.n_pages() as f64;
         let forelast_page = n_pages - 2.0;
         let last_page = n_pages - 1.0;
 
@@ -91,86 +184,31 @@ impl PaginatorWidget {
                 panic!("Position of the carousel is outside the allowed range");
             };
 
-        self.start_btn.set_opacity(opacity_start);
-        self.start_btn.set_visible(opacity_start > 0_f64);
+        imp.start_btn.set_opacity(opacity_start);
+        imp.start_btn.set_visible(opacity_start > 0_f64);
 
-        self.next_btn.set_opacity(opacity_next);
-        self.next_btn.set_visible(opacity_next > 0_f64);
-        self.next_overlay.set_can_target(opacity_next > 0_f64);
+        imp.next_btn.set_opacity(opacity_next);
+        imp.next_btn.set_visible(opacity_next > 0_f64);
+        imp.next_overlay.set_can_target(opacity_next > 0_f64);
 
-        self.finish_btn.set_opacity(opacity_finish);
-        self.finish_btn.set_visible(opacity_finish > 0_f64);
+        imp.finish_btn.set_opacity(opacity_finish);
+        imp.finish_btn.set_visible(opacity_finish > 0_f64);
 
-        self.previous_btn.set_opacity(opacity_previous);
-        self.previous_btn.set_visible(opacity_previous > 0_f64);
+        imp.previous_btn.set_opacity(opacity_previous);
+        imp.previous_btn.set_visible(opacity_previous > 0_f64);
 
-        self.close_btn.set_opacity(opacity_close);
-        self.start_btn.set_visible(opacity_close > 0_f64);
-
-        self.current_page.replace(page_nr);
-    }
+        imp.close_btn.set_opacity(opacity_close);
+        imp.start_btn.set_visible(opacity_close > 0_f64);
 
-    fn init(&self, p: Rc<Self>) {
-        self.carousel_dots.set_carousel(Some(&self.carousel));
-        self.carousel.set_hexpand(true);
-        self.carousel.set_vexpand(true);
-        self.carousel
-            .set_scroll_params(&adw::SpringParams::new(1.0, 0.5, 300.0));
-
-        self.carousel
-            .connect_position_notify(clone!(@weak p => move |_| {
-                p.update_position();
-            }));
-        self.start_btn.add_css_class("suggested-action");
-        self.start_btn.set_use_underline(true);
-        self.start_btn.set_action_name(Some("app.start-tour"));
-
-        self.next_btn.add_css_class("suggested-action");
-        self.next_btn.set_use_underline(true);
-        self.next_btn.set_action_name(Some("app.next-page"));
-
-        self.close_btn.set_use_underline(true);
-        self.close_btn.set_action_name(Some("app.quit"));
-
-        self.finish_btn.add_css_class("suggested-action");
-        self.finish_btn.set_use_underline(true);
-        self.finish_btn.set_action_name(Some("app.quit"));
-
-        self.previous_btn.set_use_underline(true);
-        self.previous_btn.set_action_name(Some("app.previous-page"));
-
-        self.next_overlay.set_child(Some(&self.next_btn));
-        self.next_overlay.add_overlay(&self.finish_btn);
-        self.next_overlay.set_can_target(false);
-
-        let previous_overlay = gtk::Overlay::new();
-        previous_overlay.set_child(Some(&self.close_btn));
-        previous_overlay.add_overlay(&self.previous_btn);
-
-        let start_overlay = gtk::Overlay::new();
-        start_overlay.set_child(Some(&self.start_btn));
-        start_overlay.add_overlay(&self.next_overlay);
-
-        let btn_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal);
-        btn_size_group.add_widget(&self.previous_btn);
-        btn_size_group.add_widget(&self.close_btn);
-        btn_size_group.add_widget(&self.next_overlay);
-        btn_size_group.add_widget(&start_overlay);
-        btn_size_group.add_widget(&self.finish_btn);
-
-        self.headerbar.set_title_widget(Some(&self.carousel_dots));
-        self.headerbar.pack_start(&previous_overlay);
-        self.headerbar.pack_end(&start_overlay);
-
-        self.widget.append(&self.headerbar);
-        self.widget.append(&self.carousel);
+        imp.current_page.set(page_nr);
     }
 
     pub fn set_page(&self, page_nr: u32) {
-        if page_nr < self.carousel.n_pages() {
-            let pages = &self.pages.borrow();
+        let imp = self.imp();
+        if page_nr < imp.carousel.n_pages() {
+            let pages = &imp.pages.borrow();
             let page = pages.get(page_nr as usize).unwrap();
-            self.carousel.scroll_to(page, true);
+            imp.carousel.scroll_to(page, true);
         }
     }
 }
diff --git a/src/widgets/window.rs b/src/widgets/window.rs
index 724ff86..71eb1c4 100644
--- a/src/widgets/window.rs
+++ b/src/widgets/window.rs
@@ -1,7 +1,5 @@
 use adw::prelude::*;
 use gettextrs::gettext;
-use std::cell::RefCell;
-use std::rc::Rc;
 
 use super::pages::{ImagePageWidget, WelcomePageWidget};
 use super::paginator::PaginatorWidget;
@@ -11,14 +9,14 @@ use crate::Application;
 #[derive(Debug)]
 pub struct Window {
     pub widget: adw::ApplicationWindow,
-    pub paginator: RefCell<Rc<PaginatorWidget>>,
+    pub paginator: PaginatorWidget,
 }
 
 impl Window {
     pub fn new(app: &Application) -> Self {
         let widget = adw::ApplicationWindow::new(app);
 
-        let paginator = RefCell::new(PaginatorWidget::new());
+        let paginator = PaginatorWidget::new();
 
         let mut window_widget = Window { widget, paginator };
 
@@ -27,11 +25,11 @@ impl Window {
     }
 
     pub fn start_tour(&self) {
-        self.paginator.borrow_mut().set_page(1);
+        self.paginator.set_page(1);
     }
 
     pub fn reset_tour(&self) {
-        self.paginator.borrow_mut().set_page(0);
+        self.paginator.set_page(0);
     }
 
     fn init(&mut self) {
@@ -43,9 +41,8 @@ impl Window {
             self.widget.add_css_class("devel");
         }
         self.paginator
-            .borrow_mut()
             .add_page(WelcomePageWidget::new().widget.upcast::<gtk::Widget>());
-        self.paginator.borrow_mut().add_page(
+        self.paginator.add_page(
             ImagePageWidget::new(
                 "/org/gnome/Tour/overview.svg",
                 gettext("Get an Overview"),
@@ -55,7 +52,7 @@ impl Window {
             .upcast::<gtk::Widget>(),
         );
 
-        self.paginator.borrow_mut().add_page(
+        self.paginator.add_page(
             ImagePageWidget::new(
                 "/org/gnome/Tour/search.svg",
                 gettext("Just Type to Search"),
@@ -65,7 +62,7 @@ impl Window {
             .upcast::<gtk::Widget>(),
         );
 
-        self.paginator.borrow_mut().add_page(
+        self.paginator.add_page(
             ImagePageWidget::new(
                 "/org/gnome/Tour/workspaces.svg",
                 gettext("Keep on Top with Workspaces"),
@@ -75,7 +72,7 @@ impl Window {
             .upcast::<gtk::Widget>(),
         );
 
-        self.paginator.borrow_mut().add_page(
+        self.paginator.add_page(
             ImagePageWidget::new(
                 "/org/gnome/Tour/blank.svg",
                 gettext("Up/Down for the Overview"),
@@ -85,7 +82,7 @@ impl Window {
             .upcast::<gtk::Widget>(),
         );
 
-        self.paginator.borrow_mut().add_page(
+        self.paginator.add_page(
             ImagePageWidget::new(
                 "/org/gnome/Tour/blank.svg",
                 gettext("Left/Right for Workspaces"),
@@ -102,10 +99,8 @@ impl Window {
         );
         last_page.widget.add_css_class("last-page");
         self.paginator
-            .borrow_mut()
             .add_page(last_page.widget.upcast::<gtk::Widget>());
 
-        self.widget
-            .set_content(Some(&self.paginator.borrow().widget));
+        self.widget.set_content(Some(&self.paginator));
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]