[fractal/fractal-next] components: Create ButtonRow



commit 577f582b6e71a1ea88c89cea064c004ea5bb597f
Author: Kévin Commaille <zecakeh tedomum fr>
Date:   Sun Feb 13 14:20:38 2022 +0100

    components: Create ButtonRow

 data/resources/resources.gresource.xml     |   1 +
 data/resources/style.css                   |   4 +
 data/resources/ui/components-button-row.ui |  32 +++++++
 src/components/button_row.rs               | 144 +++++++++++++++++++++++++++++
 src/components/mod.rs                      |   2 +
 5 files changed, 183 insertions(+)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index c43246189..8150002c1 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -20,6 +20,7 @@
     <file compressed="true" preprocess="xml-stripblanks" 
alias="components-audio-player.ui">ui/components-audio-player.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="components-auth-dialog.ui">ui/components-auth-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="components-avatar.ui">ui/components-avatar.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks" 
alias="components-button-row.ui">ui/components-button-row.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="components-editable-avatar.ui">ui/components-editable-avatar.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="components-entry-row.ui">ui/components-entry-row.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="components-loading-listbox-row.ui">ui/components-loading-listbox-row.ui</file>
diff --git a/data/resources/style.css b/data/resources/style.css
index 2725cc6e3..335667d63 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -166,6 +166,10 @@ row.entry.error levelbar.discrete block.filled {
   background-color: @error_color;
 }
 
+row .heading {
+  font-weight: 600;
+}
+
 
 /* Login */
 
diff --git a/data/resources/ui/components-button-row.ui b/data/resources/ui/components-button-row.ui
new file mode 100644
index 000000000..e24531431
--- /dev/null
+++ b/data/resources/ui/components-button-row.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="ComponentsButtonRow" parent="AdwPreferencesRow">
+    <property name="activatable">true</property>
+    <property name="selectable">false</property>
+    <child>
+      <object class="GtkBox">
+        <style>
+          <class name="header"/>
+        </style>
+        <property name="spacing">6</property>
+        <property name="valign">center</property>
+        <property name="halign">center</property>
+        <child>
+          <object class="GtkLabel">
+            <style>
+              <class name="heading"/>
+            </style>
+            <property name="label" bind-source="ComponentsButtonRow" bind-property="title" 
bind-flags="sync-create"/>
+            <property name="ellipsize">end</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkImage">
+            <property name="visible" bind-source="ComponentsButtonRow" bind-property="to-subpage" 
bind-flags="sync-create"/>
+            <property name="icon-name">go-next-symbolic</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/components/button_row.rs b/src/components/button_row.rs
new file mode 100644
index 000000000..d5db93038
--- /dev/null
+++ b/src/components/button_row.rs
@@ -0,0 +1,144 @@
+use adw::subclass::prelude::*;
+use gtk::{
+    glib,
+    glib::{clone, closure_local},
+    prelude::*,
+    subclass::prelude::*,
+    CompositeTemplate,
+};
+
+mod imp {
+    use std::cell::Cell;
+
+    use glib::subclass::{InitializingObject, Signal};
+    use once_cell::sync::Lazy;
+
+    use super::*;
+
+    #[derive(Debug, Default, CompositeTemplate)]
+    #[template(resource = "/org/gnome/FractalNext/components-button-row.ui")]
+    pub struct ButtonRow {
+        /// Whether activating this button opens a subpage.
+        pub to_subpage: Cell<bool>,
+    }
+
+    #[glib::object_subclass]
+    impl ObjectSubclass for ButtonRow {
+        const NAME: &'static str = "ComponentsButtonRow";
+        type Type = super::ButtonRow;
+        type ParentType = adw::PreferencesRow;
+
+        fn class_init(klass: &mut Self::Class) {
+            Self::bind_template(klass);
+        }
+
+        fn instance_init(obj: &InitializingObject<Self>) {
+            obj.init_template();
+        }
+    }
+
+    impl ObjectImpl for ButtonRow {
+        fn signals() -> &'static [Signal] {
+            static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
+                vec![Signal::builder("activated", &[], <()>::static_type().into()).build()]
+            });
+            SIGNALS.as_ref()
+        }
+
+        fn properties() -> &'static [glib::ParamSpec] {
+            static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+                vec![glib::ParamSpecBoolean::new(
+                    "to-subpage",
+                    "To Subpage",
+                    "Whether activating this button opens a subpage",
+                    false,
+                    glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+                )]
+            });
+
+            PROPERTIES.as_ref()
+        }
+
+        fn set_property(
+            &self,
+            obj: &Self::Type,
+            _id: usize,
+            value: &glib::Value,
+            pspec: &glib::ParamSpec,
+        ) {
+            match pspec.name() {
+                "to-subpage" => obj.set_to_subpage(value.get().unwrap()),
+                _ => unimplemented!(),
+            }
+        }
+
+        fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+            match pspec.name() {
+                "to-subpage" => obj.to_subpage().to_value(),
+                _ => unimplemented!(),
+            }
+        }
+
+        fn constructed(&self, obj: &Self::Type) {
+            self.parent_constructed(obj);
+
+            obj.connect_parent_notify(|obj| {
+                if let Some(listbox) = obj
+                    .parent()
+                    .as_ref()
+                    .and_then(|parent| parent.downcast_ref::<gtk::ListBox>())
+                {
+                    listbox.connect_row_activated(clone!(@weak obj => move |_, row| {
+                        if row == obj.upcast_ref::<gtk::ListBoxRow>() {
+                            obj.emit_by_name::<()>("activated", &[]);
+                        }
+                    }));
+                }
+            });
+        }
+    }
+    impl WidgetImpl for ButtonRow {}
+    impl ListBoxRowImpl for ButtonRow {}
+    impl PreferencesRowImpl for ButtonRow {}
+}
+
+glib::wrapper! {
+    /// An `AdwPreferencesRow` usable as a button.
+    pub struct ButtonRow(ObjectSubclass<imp::ButtonRow>)
+        @extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, @implements gtk::Accessible;
+}
+
+impl ButtonRow {
+    pub fn new() -> Self {
+        glib::Object::new(&[]).expect("Failed to create ButtonRow")
+    }
+
+    pub fn to_subpage(&self) -> bool {
+        self.imp().to_subpage.get()
+    }
+
+    pub fn set_to_subpage(&self, to_subpage: bool) {
+        if self.to_subpage() == to_subpage {
+            return;
+        }
+
+        self.imp().to_subpage.replace(to_subpage);
+        self.notify("to-subpage");
+    }
+
+    pub fn connect_activated<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
+        self.connect_closure(
+            "activated",
+            true,
+            closure_local!(move |obj: Self| {
+                f(&obj);
+            }),
+        )
+    }
+}
+
+impl Default for ButtonRow {
+    fn default() -> Self {
+        Self::new()
+    }
+}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index fbc952162..4a7118ca9 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -3,6 +3,7 @@ mod audio_player;
 mod auth_dialog;
 mod avatar;
 mod badge;
+mod button_row;
 mod context_menu_bin;
 mod custom_entry;
 mod editable_avatar;
@@ -25,6 +26,7 @@ pub use self::{
     auth_dialog::{AuthData, AuthDialog, AuthError},
     avatar::Avatar,
     badge::Badge,
+    button_row::ButtonRow,
     context_menu_bin::{ContextMenuBin, ContextMenuBinExt, ContextMenuBinImpl},
     custom_entry::CustomEntry,
     editable_avatar::EditableAvatar,


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