From 18ac470c473f34d0b1b1e42d883039ec6dfd7af5 Mon Sep 17 00:00:00 2001 From: Nefo Fortressia Date: Mon, 15 Nov 2021 07:14:59 +0700 Subject: [PATCH] refactor: make tab label their own widget This helps with downcasting which greatly helps with type safety. --- src/components/mod.rs | 2 ++ src/components/tab_label/imp.rs | 45 ++++++++++++++++++++++++ src/components/tab_label/mod.rs | 29 ++++++++++++++++ src/components/tab_label/tab-label.ui | 17 ++++++++++ src/lib/closeable_tab.rs | 49 +++++++++++---------------- 5 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 src/components/tab_label/imp.rs create mode 100644 src/components/tab_label/mod.rs create mode 100644 src/components/tab_label/tab-label.ui diff --git a/src/components/mod.rs b/src/components/mod.rs index 1cd3fdb..5353e5a 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -5,11 +5,13 @@ pub mod app; pub mod editor; pub mod sidebar; +pub mod tab_label; pub mod window; pub use app::EchidnaEditor; pub use editor::EchidnaCoreEditor; pub use sidebar::EchidnaSidebar; +pub use tab_label::TabLabel; pub use window::EchidnaWindow; pub mod prelude { diff --git a/src/components/tab_label/imp.rs b/src/components/tab_label/imp.rs new file mode 100644 index 0000000..34ca917 --- /dev/null +++ b/src/components/tab_label/imp.rs @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use gtk::prelude::*; +use gtk::subclass::prelude::*; +use gtk::CompositeTemplate; + +#[derive(Default, CompositeTemplate)] +#[template(file = "./tab-label.ui")] +pub struct TabLabel { + #[template_child] + pub button: TemplateChild, +} + +#[glib::object_subclass] +impl ObjectSubclass for TabLabel { + const NAME: &'static str = "TabLabel"; + type Type = super::TabLabel; + type ParentType = gtk::Box; + + fn class_init(klass: &mut Self::Class) { + Self::bind_template(klass); + } + + fn instance_init(obj: &glib::subclass::InitializingObject) { + obj.init_template(); + } +} + +impl ObjectImpl for TabLabel {} +impl WidgetImpl for TabLabel {} +impl BoxImpl for TabLabel {} + +impl BuildableImpl for TabLabel { + fn add_child( + &self, + buildable: &Self::Type, + builder: >k::Builder, + child: &glib::Object, + type_: Option<&str>, + ) { + buildable.prepend(child.downcast_ref::().unwrap()); + } +} diff --git a/src/components/tab_label/mod.rs b/src/components/tab_label/mod.rs new file mode 100644 index 0000000..1b45623 --- /dev/null +++ b/src/components/tab_label/mod.rs @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +pub mod imp; +use glib::IsA; +use gtk::prelude::*; +use gtk::subclass::prelude::*; + +glib::wrapper! { + pub struct TabLabel(ObjectSubclass) + @extends gtk::Box, gtk::Widget, + @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable; +} + +impl TabLabel { + pub fn new>(tab_label: Option<&U>) -> Self { + let this: Self = glib::Object::new(&[]).expect("Failed to create 'TabLabel' component."); + + if tab_label.is_some() { + this.prepend(tab_label.unwrap()); + } + this + } + + pub fn to_imp(&self) -> &imp::TabLabel { + imp::TabLabel::from_instance(self) + } +} diff --git a/src/components/tab_label/tab-label.ui b/src/components/tab_label/tab-label.ui new file mode 100644 index 0000000..a383977 --- /dev/null +++ b/src/components/tab_label/tab-label.ui @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/src/lib/closeable_tab.rs b/src/lib/closeable_tab.rs index 85900df..be42037 100644 --- a/src/lib/closeable_tab.rs +++ b/src/lib/closeable_tab.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use crate::components::tab_label::TabLabel; use glib::IsA; use gtk::{prelude::*, Box, Button, Widget}; @@ -16,39 +17,24 @@ pub trait ClosableTabImplementedNotebook { child: &T, tab_label: Option<&U>, ) -> u32; - - fn create_closable_tab>(tab_label: Option<&U>) -> (Box, Button); } impl ClosableTabImplementedNotebook for gtk::Notebook { - fn create_closable_tab>(tab_label: Option<&U>) -> (Box, Button) { - let tab = Box::new(gtk::Orientation::Horizontal, 5); - if tab_label.is_some() { - tab.append(tab_label.unwrap()); - } - - let button = gtk::Button::new(); - - button.set_icon_name("window-close-symbolic"); - button.set_has_frame(false); - - tab.append(&button); - - (tab, button) - } - fn prepend_closable_page, U: IsA>( &self, child: &T, tab_label: Option<&U>, ) -> u32 { - let (tab, button) = &Self::create_closable_tab(tab_label); - let page = self.prepend_page(child, Some(tab)); + let tab_label_widget = TabLabel::new(tab_label); + let page = self.prepend_page(child, Some(&tab_label_widget)); - button.connect_clicked(glib::clone!(@weak self as notebook => - move |_| { - notebook.remove_page(Some(page)); - })); + tab_label_widget + .to_imp() + .button + .connect_clicked(glib::clone!(@weak self as notebook => + move |_| { + notebook.remove_page(Some(page)); + })); page } @@ -58,13 +44,16 @@ impl ClosableTabImplementedNotebook for gtk::Notebook { child: &T, tab_label: Option<&U>, ) -> u32 { - let (tab, button) = &Self::create_closable_tab(tab_label); - let page = self.append_page(child, Some(tab)); + let tab_label_widget = TabLabel::new(tab_label); + let page = self.append_page(child, Some(&tab_label_widget)); - button.connect_clicked(glib::clone!(@weak self as notebook => - move |_| { - notebook.remove_page(Some(page)); - })); + tab_label_widget + .to_imp() + .button + .connect_clicked(glib::clone!(@weak self as notebook => + move |_| { + notebook.remove_page(Some(page)); + })); page }