From 04755fabb73b333355ea33ee89463904f950169f Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Fri, 31 Jan 2025 15:34:09 +0100 Subject: [PATCH] Reimplement collation menu as component --- .../collation_menu/mod.rs | 37 +++++----- .../collation_menu/sort_button.rs | 69 ++++++++++++++++--- src/ui/collatable_container/mod.rs | 21 +++--- src/ui/utility.rs | 51 ++++++++++++-- 4 files changed, 133 insertions(+), 45 deletions(-) diff --git a/src/ui/collatable_container/collation_menu/mod.rs b/src/ui/collatable_container/collation_menu/mod.rs index c29e35c..1ae00da 100644 --- a/src/ui/collatable_container/collation_menu/mod.rs +++ b/src/ui/collatable_container/collation_menu/mod.rs @@ -3,8 +3,7 @@ mod sort_button ; use { gtk4 :: { Box , Image , Label , ListBox , ListBoxRow , Popover , - Align :: * , - Orientation :: * , + Align :: * , Orientation :: * , prelude :: * , } , libadwaita :: * , @@ -12,33 +11,31 @@ use { } ; use crate :: { - ui :: { collatable_container :: * , component :: * , utility :: * } , + ui :: { + component :: * , utility :: * , + collatable_container :: { * , collation_menu :: sort_button :: * } } , utility :: * , } ; -pub struct FilmCollationMenu { - widget : Box , - sorting : & 'static RefCell < ( FilmsSortedBy , SortingDirection ) > , -} +pub struct FilmCollationMenu { widget : Box } pub struct SeriesCollationMenu { widget : Box } impl FilmCollationMenu { pub fn new < F : Fn ( FilmsSortedBy , SortingDirection ) + 'static > ( on_sort : F ) -> Self { - let widget = Box :: builder () - . orientation (Horizontal) - . halign (Center) - . spacing (20) - . name ("film-collation-menu") - . css_classes ( ["toolbar"] ) - . build () ; - let sorting = leak ( RefCell :: new ( ( FilmsSortedBy :: Name , SortingDirection :: Ascending ) ) ) ; + let film_sort_button = FilmSortButton :: new (on_sort) ; - widget . append ( & create_sort_button ( & create_films_sort_menu ( sorting , on_sort ) ) ) ; - widget . append ( & create_filter_button () ) ; + let widget = g_box ! ( + @ orientation : Horizontal , + @ halign : Center , + @ spacing : 20 , + @ widget_name : "film-collation-menu" , + @ css_classes : [ "toolbar" ] , + * film_sort_button . get_widget () + ) ; - Self { widget , sorting } + Self { widget } } } impl SeriesCollationMenu { @@ -126,12 +123,12 @@ fn create_sort_menu_entry ( label : & str , reverse : bool ) -> ListBoxRow { let container = g_box ! ( @ orientation : Horizontal , - & Label :: builder () + Label :: builder () . label (label) . hexpand (true) . halign (Start) . build () , - & icon , + icon , ) ; container . set_spacing (20) ; diff --git a/src/ui/collatable_container/collation_menu/sort_button.rs b/src/ui/collatable_container/collation_menu/sort_button.rs index e7ba0d5..703a205 100644 --- a/src/ui/collatable_container/collation_menu/sort_button.rs +++ b/src/ui/collatable_container/collation_menu/sort_button.rs @@ -1,18 +1,71 @@ -use libadwaita :: * ; +use { gtk4 :: Align :: * , libadwaita :: * , std :: cell :: * } ; -use crate :: ui :: { * , utility :: * } ; +use crate :: { utility :: * , ui :: { * , utility :: * } } ; -pub struct FilmSortButton { widget : SplitButton } +pub struct FilmSortButton { + widget : SplitButton , + previous_sorting : & 'static RefCell < ( FilmsSortedBy , SortingDirection ) > , +} impl FilmSortButton { - pub fn new () -> Self { - let widget = SplitButton :: builder () - . child ( & label ! ("Sort") ) - . build () ; + pub fn new < F : Fn ( FilmsSortedBy , SortingDirection ) + 'static > ( on_sort : F ) -> Self { + let list_box = list_box ! ( + g_box ! ( + @ orientation : Horizontal , @ spacing : 20 , + label ! ( @ hexpand : true , @ halign : Start , "Name" ) , + icon ! ("view-sort-ascending-symbolic") , + ) , + g_box ! ( + @ orientation : Horizontal , @ spacing : 20 , + label ! ( @ hexpand : true , @ halign : Start , "Release date" ) , + icon ! ("view-sort-ascending-symbolic") , + ) , + g_box ! ( + @ orientation : Horizontal , @ spacing : 20 , + label ! ( @ hexpand : true , @ halign : Start , "Runtime" ) , + icon ! ("view-sort-ascending-symbolic") , + ) , + ) ; - Self { widget } + let widget = split_button ! ( + @ popover : popover ! ( @ css_classes : [ "menu" ] , list_box ) , + label ! ("Sort") , + ) ; + + let previous_sorting = leak ( RefCell :: new ( + ( FilmsSortedBy :: Name , SortingDirection :: Ascending ) + ) ) ; + + list_box . connect_row_activated ( move | _ , row | { + let sorting_property = match row . index () { + 0 => FilmsSortedBy :: Name , + 1 => FilmsSortedBy :: ReleaseDate , + 2 => FilmsSortedBy :: Runtime , + _ => panic ! () , + } ; + + let previous_sorting_property = previous_sorting . borrow () . 0 ; + if sorting_property == previous_sorting_property { + let previous_sorting_direction = previous_sorting . borrow () . 1 ; + match previous_sorting_direction { + SortingDirection :: Ascending => { + previous_sorting . replace ( ( sorting_property , SortingDirection :: Descending ) ) ; + on_sort ( sorting_property , SortingDirection :: Descending ) ; + } , + SortingDirection :: Descending => { + previous_sorting . replace ( ( sorting_property , SortingDirection :: Ascending ) ) ; + on_sort ( sorting_property , SortingDirection :: Ascending ) ; + } , + } + } else { + previous_sorting . replace ( ( sorting_property , SortingDirection :: Ascending ) ) ; + on_sort ( sorting_property , SortingDirection :: Ascending ) ; + } + } ) ; + + Self { widget , previous_sorting } } } diff --git a/src/ui/collatable_container/mod.rs b/src/ui/collatable_container/mod.rs index 2d7adcf..0c7299a 100644 --- a/src/ui/collatable_container/mod.rs +++ b/src/ui/collatable_container/mod.rs @@ -6,18 +6,19 @@ use gtk4 :: { * , Orientation :: * , prelude :: * } ; use crate :: { collection :: * , ui :: { + component :: * , utility :: * , collatable_container :: { collated_grid :: * , collation_menu :: * } , - component :: * , - utility :: * , } , utility :: * , } ; -# [ derive (PartialEq) ] pub enum FilmsSortedBy { Name , ReleaseDate , Runtime } -# [ derive (PartialEq) ] pub enum SeriesSortedBy { Name , FirstReleaseDate } -# [ derive (PartialEq) ] pub enum SortingDirection { Ascending , Descending } +# [ derive ( Clone , Copy , PartialEq ) ] pub enum FilmsSortedBy { Name , ReleaseDate , Runtime } +# [ derive ( Clone , Copy , PartialEq ) ] pub enum SeriesSortedBy { Name , FirstReleaseDate } +# [ derive ( Clone , Copy , PartialEq ) ] pub enum SortingDirection { Ascending , Descending } + +pub struct FilmSorting { property : FilmsSortedBy , direction : SortingDirection } pub struct CollatableFilmsContainer { collated_grid : & 'static CollatedFilmsGrid , @@ -37,8 +38,8 @@ impl CollatableFilmsContainer { let widget = g_box ! ( @ orientation : Vertical , - film_collation_menu . get_widget () , - & create_collection_scrolled_window ( collated_grid . get_widget () ) , + * film_collation_menu . get_widget () , + create_collection_scrolled_window ( collated_grid . get_widget () ) , ) ; Self { collated_grid , widget } @@ -58,8 +59,8 @@ impl CollatableSeriesContainer { let widget = g_box ! ( @ orientation : Vertical , - series_collation_menu . get_widget () , - & create_collection_scrolled_window ( collated_grid . get_widget () ) , + * series_collation_menu . get_widget () , + create_collection_scrolled_window ( collated_grid . get_widget () ) , ) ; Self { collated_grid , widget } @@ -79,7 +80,7 @@ impl Component for CollatableSeriesContainer { fn create_collection_scrolled_window ( child : & FlowBox ) -> ScrolledWindow { ScrolledWindow :: builder () - . child ( & vertically_filling ! (child) ) + . child ( & vertically_filling ! ( * child ) ) . propagate_natural_height (true) . build () } diff --git a/src/ui/utility.rs b/src/ui/utility.rs index abae8dc..691c449 100644 --- a/src/ui/utility.rs +++ b/src/ui/utility.rs @@ -3,24 +3,34 @@ macro_rules ! label { ( $ ( @ vexpand : $ vexpand : expr , ) ? $ ( @ halign : $ halign : expr , ) ? $ ( @ valign : $ valign : expr , ) ? - $ ( $ label : expr ) ? $ (,) ? + $ label : expr $ (,) ? ) => { { let label = gtk4 :: Label :: builder () . build () ; $ ( label . set_hexpand ( $ hexpand ) ; ) ? $ ( label . set_vexpand ( $ vexpand ) ; ) ? $ ( label . set_halign ( $ halign ) ; ) ? $ ( label . set_valign ( $ valign ) ; ) ? - $ ( label . set_label ( $ label ) ; ) ? + label . set_label ( $ label ) ; label } } } macro_rules ! g_box { ( $ ( @ orientation : $ orientation : expr , ) ? - $ ( $ child : expr ) , * $ (,) ? + $ ( @ halign : $ halign : expr , ) ? + $ ( @ valign : $ valign : expr , ) ? + $ ( @ spacing : $ spacing : expr , ) ? + $ ( @ widget_name : $ widget_name : expr , ) ? + $ ( @ css_classes : $ css_classes : expr , ) ? + $ ( $ child : expr ) , + $ (,) ? ) => { { let container = gtk4 :: Box :: builder () . build () ; $ ( container . set_orientation ( $ orientation ) ; ) ? - $ ( container . append ( $ child ) ; ) * + $ ( container . set_halign ( $ halign ) ; ) ? + $ ( container . set_valign ( $ valign ) ; ) ? + $ ( container . set_spacing ( $ spacing ) ; ) ? + $ ( container . set_widget_name ( & $ widget_name ) ; ) ? + $ ( container . set_css_classes ( & $ css_classes ) ; ) ? + $ ( container . append ( & $ child ) ; ) * container } } } @@ -32,17 +42,41 @@ macro_rules ! view_stack { ( container } } } -macro_rules ! list_box { ( $ ( $ child : expr , ) * ) => { { +macro_rules ! list_box { ( $ ( $ child : expr ) , * $ (,) ? ) => { { let container = gtk4 :: ListBox :: new () ; - $ ( container . append ( $ child ) ; ) * + $ ( container . append ( & $ child ) ; ) * container } } } +macro_rules ! split_button { ( + $ ( @ popover : $ popover : expr , ) ? + $ child : expr $ (,) ? +) => { { + let widget = libadwaita :: SplitButton :: new () ; + $ ( widget . set_popover ( Some ( & $ popover ) ) ; ) ? + widget . set_child ( Some ( & $ child ) ) ; + widget +} } } + +macro_rules ! popover { ( + $ ( @ css_classes : $ css_classes : expr , ) ? + $ child : expr $ (,) ? +) => { { + let widget = gtk4 :: Popover :: new () ; + $ ( widget . set_css_classes ( & $ css_classes ) ; ) ? + widget . set_child ( Some ( & $ child ) ) ; + widget +} } } + +macro_rules ! icon { ( $ icon_name : expr ) => { + gtk4 :: Image :: from_icon_name ( $ icon_name ) +} } + macro_rules ! vertically_filling { ( $ child : expr ) => { g_box ! ( @ orientation : gtk4 :: Orientation :: Vertical , $ child , - & libadwaita :: Bin :: builder () + libadwaita :: Bin :: builder () . css_name ("filler") . vexpand (true) . build () , @@ -56,5 +90,8 @@ pub (crate) use { g_box , view_stack , list_box , + split_button , + popover , + icon , vertically_filling , } ;