From 04112515f56227367713095c898f955cffdbe54f Mon Sep 17 00:00:00 2001 From: Dave Patrick Caberto Date: Sun, 13 Aug 2023 15:22:45 +0800 Subject: [PATCH 1/9] refactor: split Diagram to DiagramView and Diagram This is a preparation for drawing on top of the ListView in DiagramView. --- data/resources/resources.gresource.xml | 1 + data/resources/ui/diagram.ui | 13 +- data/resources/ui/diagram_view.ui | 18 +++ src/diagram.rs | 43 ++---- src/diagram_view.rs | 187 +++++++++++++++++++++++++ src/main.rs | 1 + 6 files changed, 218 insertions(+), 45 deletions(-) create mode 100644 data/resources/ui/diagram_view.ui create mode 100644 src/diagram_view.rs diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml index 4c49d46..a5a84bd 100644 --- a/data/resources/resources.gresource.xml +++ b/data/resources/resources.gresource.xml @@ -10,6 +10,7 @@ ui/details_view.ui ui/diagram.ui ui/diagram_row.ui + ui/diagram_view.ui ui/durations_page.ui ui/frequencies_page.ui ui/sizes_page.ui diff --git a/data/resources/ui/diagram.ui b/data/resources/ui/diagram.ui index fa09068..978d09e 100644 --- a/data/resources/ui/diagram.ui +++ b/data/resources/ui/diagram.ui @@ -6,19 +6,8 @@ - True - - - - True - False - - - - + diff --git a/data/resources/ui/diagram_view.ui b/data/resources/ui/diagram_view.ui new file mode 100644 index 0000000..fbaf268 --- /dev/null +++ b/data/resources/ui/diagram_view.ui @@ -0,0 +1,18 @@ + + + + diff --git a/src/diagram.rs b/src/diagram.rs index 496b7c9..5cb8790 100644 --- a/src/diagram.rs +++ b/src/diagram.rs @@ -5,13 +5,10 @@ use gtk::{ subclass::prelude::*, }; -use crate::{diagram_item::DiagramItem, diagram_model::DiagramModel, diagram_row::DiagramRow}; +use crate::{diagram_item::DiagramItem, diagram_model::DiagramModel, diagram_view::DiagramView}; mod imp { - use std::{ - cell::{Cell, RefCell}, - marker::PhantomData, - }; + use std::{cell::Cell, marker::PhantomData}; use super::*; @@ -25,11 +22,7 @@ mod imp { #[template_child] pub(super) scrolled_window: TemplateChild, #[template_child] - pub(super) list_view: TemplateChild, - #[template_child] - pub(super) selection_model: TemplateChild, - - pub(super) model: RefCell>, + pub(super) view: TemplateChild, pub(super) is_sticky: Cell, pub(super) is_auto_scrolling: Cell, @@ -48,9 +41,7 @@ mod imp { gdk::Key::Escape, gdk::ModifierType::empty(), |obj, _| { - obj.imp() - .selection_model - .set_selected(gtk::INVALID_LIST_POSITION); + obj.imp().view.unselect(); true }, None, @@ -69,26 +60,14 @@ mod imp { let obj = self.obj(); - let factory = gtk::SignalListItemFactory::new(); - factory.connect_setup(clone!(@weak obj => move |_, list_item| { - let list_item = list_item.downcast_ref::().unwrap(); - - let row = DiagramRow::default(); - - list_item.property_expression("item").bind(&row, "item", glib::Object::NONE); - - list_item.set_child(Some(&row)); - })); - self.list_view.set_factory(Some(&factory)); - - self.selection_model + self.view .connect_selected_item_notify(clone!(@weak obj => move |_| { obj.notify_selected_item(); })); self.is_sticky.set(true); - let vadj = self.list_view.vadjustment().unwrap(); + let vadj = self.view.vadjustment().unwrap(); vadj.connect_value_changed(clone!(@weak obj => move |vadj| { let imp = obj.imp(); @@ -125,26 +104,24 @@ mod imp { impl Diagram { fn selected_item(&self) -> Option { - self.selection_model.selected_item().and_downcast() + self.view.selected_item() } } } glib::wrapper! { + /// Wrapper to DiagramView pub struct Diagram(ObjectSubclass) @extends gtk::Widget; } impl Diagram { pub fn set_model(&self, model: Option<&DiagramModel>) { - let imp = self.imp(); - - imp.model.replace(model.cloned()); - imp.selection_model.set_model(model); + self.imp().view.set_model(model); } pub fn model(&self) -> Option { - self.imp().model.borrow().clone() + self.imp().view.model() } fn scroll_to_end(&self) { diff --git a/src/diagram_view.rs b/src/diagram_view.rs new file mode 100644 index 0000000..e6fedc6 --- /dev/null +++ b/src/diagram_view.rs @@ -0,0 +1,187 @@ +use gtk::{ + glib::{self, clone}, + prelude::*, + subclass::prelude::*, +}; + +use crate::{diagram_item::DiagramItem, diagram_model::DiagramModel, diagram_row::DiagramRow}; + +mod imp { + use std::marker::PhantomData; + + use super::*; + + #[derive(Debug, Default, glib::Properties, gtk::CompositeTemplate)] + #[properties(wrapper_type = super::DiagramView)] + #[template(resource = "/org/freedesktop/Bustle/ui/diagram_view.ui")] + pub struct DiagramView { + #[property(get = Self::selected_item)] + pub(super) selected_item: PhantomData>, + #[property(get = Self::hscroll_policy, set = Self::set_hscroll_policy, override_interface = gtk::Scrollable)] + pub(super) hscroll_policy: PhantomData, + #[property(get = Self::hadjustment, set = Self::set_hadjustment, override_interface = gtk::Scrollable)] + pub(super) hadjustment: PhantomData>, + #[property(get = Self::vscroll_policy, set = Self::set_vscroll_policy, override_interface = gtk::Scrollable)] + pub(super) vscroll_policy: PhantomData, + #[property(get = Self::vadjustment, set = Self::set_vadjustment, override_interface = gtk::Scrollable)] + pub(super) vadjustment: PhantomData>, + + #[template_child] + pub(super) list_view: TemplateChild, + #[template_child] + pub(super) selection_model: TemplateChild, + } + + #[glib::object_subclass] + impl ObjectSubclass for DiagramView { + const NAME: &'static str = "BustleDiagramView"; + type Type = super::DiagramView; + type ParentType = gtk::Widget; + type Interfaces = (gtk::Scrollable,); + + fn class_init(klass: &mut Self::Class) { + klass.bind_template(); + } + + fn instance_init(obj: &glib::subclass::InitializingObject) { + obj.init_template(); + } + } + + #[glib::derived_properties] + impl ObjectImpl for DiagramView { + fn constructed(&self) { + self.parent_constructed(); + + let obj = self.obj(); + + let factory = gtk::SignalListItemFactory::new(); + factory.connect_setup(clone!(@weak obj => move |_, list_item| { + let list_item = list_item.downcast_ref::().unwrap(); + + let row = DiagramRow::default(); + + list_item.property_expression("item").bind(&row, "item", glib::Object::NONE); + + list_item.set_child(Some(&row)); + })); + self.list_view.set_factory(Some(&factory)); + + self.selection_model + .connect_selected_item_notify(clone!(@weak obj => move |_| { + obj.notify_selected_item(); + })); + } + + fn dispose(&self) { + self.dispose_template(); + } + } + + impl WidgetImpl for DiagramView { + fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) { + self.list_view.measure(orientation, for_size) + } + + fn size_allocate(&self, width: i32, height: i32, baseline: i32) { + self.list_view + .size_allocate(>k::Allocation::new(0, 0, width, height), baseline) + } + } + + impl ScrollableImpl for DiagramView { + fn border(&self) -> Option { + self.list_view.border() + } + } + + impl DiagramView { + fn selected_item(&self) -> Option { + self.selection_model.selected_item().and_downcast() + } + + fn hscroll_policy(&self) -> gtk::ScrollablePolicy { + self.list_view.hscroll_policy() + } + + fn set_hscroll_policy(&self, policy: gtk::ScrollablePolicy) { + self.list_view.set_hscroll_policy(policy); + } + + fn hadjustment(&self) -> Option { + self.list_view.hadjustment() + } + + fn set_hadjustment(&self, adj: Option<>k::Adjustment>) { + self.list_view.set_hadjustment(adj); + + if let Some(adj) = adj { + let obj = self.obj(); + + adj.connect_value_changed(clone!(@weak obj => move |_| { + obj.queue_draw(); + })); + adj.connect_upper_notify(clone!(@weak obj => move |_| { + obj.queue_draw(); + })); + adj.connect_page_size_notify(clone!(@weak obj => move |_| { + obj.queue_draw(); + })); + } + } + + fn vscroll_policy(&self) -> gtk::ScrollablePolicy { + self.list_view.vscroll_policy() + } + + fn set_vscroll_policy(&self, policy: gtk::ScrollablePolicy) { + self.list_view.set_vscroll_policy(policy); + } + + fn vadjustment(&self) -> Option { + self.list_view.vadjustment() + } + + fn set_vadjustment(&self, adj: Option<>k::Adjustment>) { + self.list_view.set_vadjustment(adj); + + if let Some(adj) = adj { + let obj = self.obj(); + + adj.connect_value_changed(clone!(@weak obj => move |_| { + obj.queue_draw(); + })); + adj.connect_upper_notify(clone!(@weak obj => move |_| { + obj.queue_draw(); + })); + adj.connect_page_size_notify(clone!(@weak obj => move |_| { + obj.queue_draw(); + })); + } + } + } +} + +glib::wrapper! { + pub struct DiagramView(ObjectSubclass) + @extends gtk::Widget; +} + +impl DiagramView { + pub fn set_model(&self, model: Option<&DiagramModel>) { + self.imp().selection_model.set_model(model); + } + + pub fn model(&self) -> Option { + self.imp() + .selection_model + .model() + .map(|selection_model| selection_model.downcast().unwrap()) + } + + pub fn unselect(&self) { + self.imp() + .selection_model + .set_selected(gtk::INVALID_LIST_POSITION); + } +} diff --git a/src/main.rs b/src/main.rs index a8617e7..e8e67e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod diagram; mod diagram_item; mod diagram_model; mod diagram_row; +mod diagram_view; mod i18n; mod message_type; mod monitor; -- GitLab From ed8a8e34462d255faffc7d0b5519eb50c6be86b4 Mon Sep 17 00:00:00 2001 From: Dave Patrick Caberto Date: Sun, 13 Aug 2023 15:30:12 +0800 Subject: [PATCH 2/9] refactor: handle filtering in Diagram instead of DiagramModel In the future, we will need info on the items we filtered, so it is great for them to be around --- data/resources/ui/diagram_view.ui | 3 +++ src/diagram.rs | 4 ++++ src/diagram_model.rs | 11 ----------- src/diagram_view.rs | 8 +++++++- src/window.rs | 12 ++++++++++++ 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/data/resources/ui/diagram_view.ui b/data/resources/ui/diagram_view.ui index fbaf268..4f7c813 100644 --- a/data/resources/ui/diagram_view.ui +++ b/data/resources/ui/diagram_view.ui @@ -7,6 +7,9 @@ True False + + +