refactor: make tab label their own widget

This helps with downcasting which greatly helps with type safety.
merge-requests/15/head
Nefo Fortressia 2021-11-15 07:14:59 +07:00
parent 9a21bd54e5
commit 18ac470c47
Signed by: fortressia
GPG Key ID: 6D7972CC76174995
5 changed files with 112 additions and 30 deletions

View File

@ -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 {

View File

@ -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<gtk::Button>,
}
#[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<Self>) {
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: &gtk::Builder,
child: &glib::Object,
type_: Option<&str>,
) {
buildable.prepend(child.downcast_ref::<gtk::Widget>().unwrap());
}
}

View File

@ -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<imp::TabLabel>)
@extends gtk::Box, gtk::Widget,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
}
impl TabLabel {
pub fn new<U: IsA<gtk::Widget>>(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)
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="4.5.0" />
<!-- 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/.
-->
<template class="TabLabel">
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
<child>
<object class="GtkButton" id="button">
<property name="has-frame">0</property>
<property name="icon-name">window-close-symbolic</property>
</object>
</child>
</template>
</interface>

View File

@ -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<U: IsA<Widget>>(tab_label: Option<&U>) -> (Box, Button);
}
impl ClosableTabImplementedNotebook for gtk::Notebook {
fn create_closable_tab<U: IsA<Widget>>(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<T: IsA<Widget>, U: IsA<Widget>>(
&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
}