From e2330cae508cff4fd3ed63793534d2f8be298f35 Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Fri, 31 Jan 2025 16:24:22 +0100 Subject: [PATCH] Introduce sorting structs --- src/ui/collatable_container/collated_grid.rs | 38 +++++++-------- .../collation_menu/mod.rs | 42 ++++++++--------- .../collation_menu/sort_button.rs | 40 ++++++++-------- src/ui/collatable_container/mod.rs | 46 +++++++++++++++---- src/ui/utility.rs | 11 +++++ 5 files changed, 106 insertions(+), 71 deletions(-) diff --git a/src/ui/collatable_container/collated_grid.rs b/src/ui/collatable_container/collated_grid.rs index 6e131fe..1584b8f 100644 --- a/src/ui/collatable_container/collated_grid.rs +++ b/src/ui/collatable_container/collated_grid.rs @@ -23,56 +23,56 @@ pub struct CollatedSeriesGrid { } impl CollatedFilmsGrid { - pub fn new ( films : Vec , sorting : FilmsSortedBy , direction : SortingDirection ) -> Self { + pub fn new ( films : Vec , sorting : FilmsSorting ) -> Self { let grid_widget = create_flow_box () ; let film_widget_pairs = RefCell :: new ( vec ! () ) ; let component = Self { film_widget_pairs , grid_widget } ; - component . set_films ( films , sorting , direction ) ; + component . set_films ( films , sorting ) ; component } - pub fn set_films ( & self , films : Vec , sorting : FilmsSortedBy , direction : SortingDirection ) { + pub fn set_films ( & self , films : Vec , sorting : FilmsSorting ) { let widgets = films . iter () . map (create_film_entry) . collect :: < Vec <_> > () ; * self . film_widget_pairs . borrow_mut () = zip ( films , widgets ) . collect () ; - for ( _ , film_widget ) in self . sort_film_widget_pairs ( sorting , direction ) { + for ( _ , film_widget ) in self . sort_film_widget_pairs (sorting) { self . grid_widget . append ( & film_widget ) ; } } - pub fn set_sorting ( & self , sorting : FilmsSortedBy , direction : SortingDirection ) { + pub fn set_sorting ( & self , sorting : FilmsSorting ) { self . grid_widget . remove_all () ; - for ( _ , film_widget ) in self . sort_film_widget_pairs ( sorting , direction ) { + for ( _ , film_widget ) in self . sort_film_widget_pairs (sorting) { self . grid_widget . append ( & film_widget ) ; } } - fn sort_film_widget_pairs ( & self , sorting : FilmsSortedBy , direction : SortingDirection ) -> Vec < ( Film , Box ) > { + fn sort_film_widget_pairs ( & self , sorting : FilmsSorting ) -> Vec < ( Film , Box ) > { let mut sorted = Vec :: from ( self . film_widget_pairs . borrow () . as_slice () ) ; - sorted . sort_by ( | ( film_1 , _ ) , ( film_2 , _ ) | match sorting { - FilmsSortedBy :: Name => + sorted . sort_by ( | ( film_1 , _ ) , ( film_2 , _ ) | match sorting . property { + FilmProperty :: Name => film_1 . name . cmp ( & film_2 . name ) , - FilmsSortedBy :: ReleaseDate => + FilmProperty :: ReleaseDate => film_1 . release_date . cmp ( & film_2 . release_date ) , - FilmsSortedBy :: Runtime => + FilmProperty :: Runtime => film_1 . runtime_minutes . cmp ( & film_2 . runtime_minutes ) , } ) ; - if direction == SortingDirection :: Descending { sorted . reverse () } + if sorting . direction == SortingDirection :: Descending { sorted . reverse () } // See it, say it, ... sorted } } impl CollatedSeriesGrid { - pub fn new ( series : Vec , sorting : SeriesSortedBy ) -> Self { + pub fn new ( series : Vec , sorting : SeriesSorting ) -> Self { let grid_widget = create_flow_box () ; let series_widget_pairs = RefCell :: new ( vec ! () ) ; @@ -82,7 +82,7 @@ impl CollatedSeriesGrid { component } - pub fn set_series ( & self , series : Vec , sorting : SeriesSortedBy ) { + pub fn set_series ( & self , series : Vec , sorting : SeriesSorting ) { let widgets = series . iter () . map (create_series_entry) . collect :: < Vec <_> > () ; @@ -94,7 +94,7 @@ impl CollatedSeriesGrid { } } - pub fn set_sorting ( & self , sorting : SeriesSortedBy ) { + pub fn set_sorting ( & self , sorting : SeriesSorting ) { self . grid_widget . remove_all () ; for ( _ , series_widget ) in self . sort_series_widget_pairs (sorting) { @@ -102,13 +102,13 @@ impl CollatedSeriesGrid { } } - fn sort_series_widget_pairs ( & self , sorting : SeriesSortedBy ) -> Vec < ( Series , Box ) > { + fn sort_series_widget_pairs ( & self , sorting : SeriesSorting ) -> Vec < ( Series , Box ) > { let mut sorted = Vec :: from ( self . series_widget_pairs . borrow () . as_slice () ) ; - sorted . sort_by ( | ( series_1 , _ ) , ( series_2 , _ ) | match sorting { - SeriesSortedBy :: Name => series_1 . name . cmp ( & series_2 . name ) , - SeriesSortedBy :: FirstReleaseDate => todo ! () , + sorted . sort_by ( | ( series_1 , _ ) , ( series_2 , _ ) | match sorting . property { + SeriesProperty :: Name => series_1 . name . cmp ( & series_2 . name ) , + SeriesProperty :: FirstReleaseDate => todo ! () , } ) ; sorted diff --git a/src/ui/collatable_container/collation_menu/mod.rs b/src/ui/collatable_container/collation_menu/mod.rs index 1ae00da..a0b1d32 100644 --- a/src/ui/collatable_container/collation_menu/mod.rs +++ b/src/ui/collatable_container/collation_menu/mod.rs @@ -7,14 +7,12 @@ use { prelude :: * , } , libadwaita :: * , - std :: { cell :: * , ops :: * } , + std :: ops :: * , } ; -use crate :: { - ui :: { - component :: * , utility :: * , - collatable_container :: { * , collation_menu :: sort_button :: * } } , - utility :: * , +use crate :: ui :: { + component :: * , utility :: * , + collatable_container :: { * , collation_menu :: sort_button :: * } , } ; @@ -23,7 +21,7 @@ pub struct FilmCollationMenu { widget : Box } pub struct SeriesCollationMenu { widget : Box } impl FilmCollationMenu { - pub fn new < F : Fn ( FilmsSortedBy , SortingDirection ) + 'static > ( on_sort : F ) -> Self { + pub fn new < F : Fn (FilmsSorting) + 'static > ( on_sort : F ) -> Self { let film_sort_button = FilmSortButton :: new (on_sort) ; let widget = g_box ! ( @@ -39,7 +37,7 @@ impl FilmCollationMenu { } } impl SeriesCollationMenu { - pub fn new < F : Fn (SeriesSortedBy) + 'static > ( on_sort : F ) -> Self { + pub fn new < F : Fn (SeriesSorting) + 'static > ( on_sort : F ) -> Self { let widget = Box :: builder () . orientation (Horizontal) . halign (Center) @@ -68,10 +66,7 @@ fn create_sort_button ( sort_menu : & Popover ) -> SplitButton { . build () } -fn create_films_sort_menu < F : Fn ( FilmsSortedBy , SortingDirection ) + 'static > ( - sorting : & 'static RefCell < ( FilmsSortedBy , SortingDirection ) > , - on_sort : F , -) -> Popover { +fn create_films_sort_menu < F : Fn (FilmsSorting) + 'static > ( on_sort : F ) -> Popover { let container = ListBox :: new () ; container . append ( & create_sort_menu_entry ( "Name" , false ) ) ; @@ -82,12 +77,12 @@ fn create_films_sort_menu < F : Fn ( FilmsSortedBy , SortingDirection ) + 'stati container . connect_row_activated ( move | _ , row | { let sorting_property = match row . index () { - 0 => FilmsSortedBy :: Name , - 1 => FilmsSortedBy :: ReleaseDate , - 2 => FilmsSortedBy :: Runtime , + 0 => FilmProperty :: Name , + 1 => FilmProperty :: ReleaseDate , + 2 => FilmProperty :: Runtime , _ => panic ! () , } ; - on_sort ( sorting_property , SortingDirection :: Ascending ) + on_sort ( FilmsSorting :: new ( sorting_property , SortingDirection :: Ascending ) ) ; } ) ; Popover :: builder () @@ -95,7 +90,7 @@ fn create_films_sort_menu < F : Fn ( FilmsSortedBy , SortingDirection ) + 'stati . css_classes ( ["menu"] ) . build () } -fn create_series_sort_menu < F : Fn (SeriesSortedBy) + 'static > ( on_sort : F ) -> Popover { +fn create_series_sort_menu < F : Fn (SeriesSorting) + 'static > ( on_sort : F ) -> Popover { let container = ListBox :: new () ; container . append ( & create_sort_menu_entry ( "Name" , false ) ) ; @@ -103,11 +98,14 @@ fn create_series_sort_menu < F : Fn (SeriesSortedBy) + 'static > ( on_sort : F ) container . select_row ( container . row_at_index (0) . as_ref () ) ; - container . connect_row_activated ( move | _ , row | on_sort ( match row . index () { - 0 => SeriesSortedBy :: Name , - 1 => SeriesSortedBy :: FirstReleaseDate , - _ => panic ! () , - } ) ) ; + container . connect_row_activated ( move | _ , row | { + let sorting_property = match row . index () { + 0 => SeriesProperty :: Name , + 1 => SeriesProperty :: FirstReleaseDate , + _ => panic ! () , + } ; + on_sort ( SeriesSorting :: new ( sorting_property , SortingDirection :: Ascending ) ) ; + } ) ; Popover :: builder () . child ( & container ) diff --git a/src/ui/collatable_container/collation_menu/sort_button.rs b/src/ui/collatable_container/collation_menu/sort_button.rs index 703a205..1905b1e 100644 --- a/src/ui/collatable_container/collation_menu/sort_button.rs +++ b/src/ui/collatable_container/collation_menu/sort_button.rs @@ -1,16 +1,19 @@ use { gtk4 :: Align :: * , libadwaita :: * , std :: cell :: * } ; -use crate :: { utility :: * , ui :: { * , utility :: * } } ; +use crate :: { + utility :: * , + ui :: { * , utility :: * , collatable_container :: SortingDirection :: * } , +} ; pub struct FilmSortButton { widget : SplitButton , - previous_sorting : & 'static RefCell < ( FilmsSortedBy , SortingDirection ) > , + previous_sorting : & 'static RefCell , } impl FilmSortButton { - pub fn new < F : Fn ( FilmsSortedBy , SortingDirection ) + 'static > ( on_sort : F ) -> Self { + pub fn new < F : Fn (FilmsSorting) + 'static > ( on_sort : F ) -> Self { let list_box = list_box ! ( g_box ! ( @ orientation : Horizontal , @ spacing : 20 , @@ -34,34 +37,31 @@ impl FilmSortButton { label ! ("Sort") , ) ; - let previous_sorting = leak ( RefCell :: new ( - ( FilmsSortedBy :: Name , SortingDirection :: Ascending ) - ) ) ; + let previous_sorting = leak ( RefCell :: new ( FilmsSorting :: default () ) ) ; list_box . connect_row_activated ( move | _ , row | { let sorting_property = match row . index () { - 0 => FilmsSortedBy :: Name , - 1 => FilmsSortedBy :: ReleaseDate , - 2 => FilmsSortedBy :: Runtime , + 0 => FilmProperty :: Name , + 1 => FilmProperty :: ReleaseDate , + 2 => FilmProperty :: Runtime , _ => panic ! () , } ; - let previous_sorting_property = previous_sorting . borrow () . 0 ; - if sorting_property == previous_sorting_property { - let previous_sorting_direction = previous_sorting . borrow () . 1 ; + if sorting_property == previous_sorting . borrow () . property { + let previous_sorting_direction = previous_sorting . borrow () . direction ; match previous_sorting_direction { - SortingDirection :: Ascending => { - previous_sorting . replace ( ( sorting_property , SortingDirection :: Descending ) ) ; - on_sort ( sorting_property , SortingDirection :: Descending ) ; + Ascending => { + previous_sorting . replace ( FilmsSorting :: new ( sorting_property , Descending ) ) ; + on_sort ( FilmsSorting :: new ( sorting_property , Descending ) ) ; } , - SortingDirection :: Descending => { - previous_sorting . replace ( ( sorting_property , SortingDirection :: Ascending ) ) ; - on_sort ( sorting_property , SortingDirection :: Ascending ) ; + Descending => { + previous_sorting . replace ( FilmsSorting :: new ( sorting_property , Ascending ) ) ; + on_sort ( FilmsSorting :: new ( sorting_property , Ascending ) ) ; } , } } else { - previous_sorting . replace ( ( sorting_property , SortingDirection :: Ascending ) ) ; - on_sort ( sorting_property , SortingDirection :: Ascending ) ; + previous_sorting . replace ( FilmsSorting :: new ( sorting_property , Ascending ) ) ; + on_sort ( FilmsSorting :: new ( sorting_property , Ascending ) ) ; } } ) ; diff --git a/src/ui/collatable_container/mod.rs b/src/ui/collatable_container/mod.rs index 0c7299a..24e3abd 100644 --- a/src/ui/collatable_container/mod.rs +++ b/src/ui/collatable_container/mod.rs @@ -14,11 +14,34 @@ use crate :: { -# [ 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 FilmProperty { Name , ReleaseDate , Runtime } +# [ derive ( Clone , Copy , PartialEq ) ] pub enum SeriesProperty { Name , FirstReleaseDate } # [ derive ( Clone , Copy , PartialEq ) ] pub enum SortingDirection { Ascending , Descending } -pub struct FilmSorting { property : FilmsSortedBy , direction : SortingDirection } +# [ derive ( Clone , Copy ) ] pub struct FilmsSorting { property : FilmProperty , direction : SortingDirection } +# [ derive ( Clone , Copy ) ] pub struct SeriesSorting { property : SeriesProperty , direction : SortingDirection } + +impl FilmsSorting { + pub fn new ( property : FilmProperty , direction : SortingDirection ) -> Self { Self { property , direction } } +} +impl SeriesSorting { + pub fn new ( property : SeriesProperty , direction : SortingDirection ) -> Self { Self { property , direction } } +} + +impl Default for FilmsSorting { + fn default () -> Self { Self { + property : FilmProperty :: Name , + direction : SortingDirection :: Ascending , + } } +} +impl Default for SeriesSorting { + fn default () -> Self { Self { + property : SeriesProperty :: Name , + direction : SortingDirection :: Ascending , + } } +} + + pub struct CollatableFilmsContainer { collated_grid : & 'static CollatedFilmsGrid , @@ -32,27 +55,30 @@ pub struct CollatableSeriesContainer { impl CollatableFilmsContainer { pub fn new ( films : Vec ) -> Self { let collated_grid = leak ( - CollatedFilmsGrid :: new ( films , FilmsSortedBy :: Name , SortingDirection :: Ascending ) ) ; - let film_collation_menu = FilmCollationMenu :: new ( | sorting , direction | - collated_grid . set_sorting ( sorting , direction ) ) ; + CollatedFilmsGrid :: new ( films , FilmsSorting :: default () ) ) ; + let film_collation_menu = FilmCollationMenu :: new ( |sorting| + collated_grid . set_sorting (sorting) ) ; let widget = g_box ! ( @ orientation : Vertical , * film_collation_menu . get_widget () , - create_collection_scrolled_window ( collated_grid . get_widget () ) , + scrolled_window ! ( + @ propagate_natural_height : true , + vertically_filling ! ( * collated_grid . get_widget () ) , + ) , ) ; Self { collated_grid , widget } } pub fn set_films ( & self , films : Vec ) { - self . collated_grid . set_films ( films , FilmsSortedBy :: Name , SortingDirection :: Ascending ) ; + self . collated_grid . set_films ( films , FilmsSorting :: default () ) ; } } impl CollatableSeriesContainer { pub fn new ( series : Vec ) -> Self { let collated_grid = leak ( - CollatedSeriesGrid :: new ( series , SeriesSortedBy :: Name ) ) ; + CollatedSeriesGrid :: new ( series , SeriesSorting :: default () ) ) ; let series_collation_menu = SeriesCollationMenu :: new ( |sorted_by| { collated_grid . set_sorting (sorted_by) ; } ) ; @@ -67,7 +93,7 @@ impl CollatableSeriesContainer { } pub fn set_series ( & self , series : Vec ) { - self . collated_grid . set_series ( series , SeriesSortedBy :: Name ) ; + self . collated_grid . set_series ( series , SeriesSorting :: default () ) ; } } diff --git a/src/ui/utility.rs b/src/ui/utility.rs index 691c449..41264be 100644 --- a/src/ui/utility.rs +++ b/src/ui/utility.rs @@ -72,6 +72,16 @@ macro_rules ! icon { ( $ icon_name : expr ) => { gtk4 :: Image :: from_icon_name ( $ icon_name ) } } +macro_rules ! scrolled_window { ( + $ ( @ propagate_natural_height : $ propagate_natural_height : expr , ) ? + $ child : expr $ (,) ? +) => { { + let widget = gtk4 :: ScrolledWindow :: new () ; + $ ( widget . set_propagate_natural_height ( $ propagate_natural_height ) ; ) ? + widget . set_child ( Some ( & $ child ) ) ; + widget +} } } + macro_rules ! vertically_filling { ( $ child : expr ) => { g_box ! ( @ orientation : gtk4 :: Orientation :: Vertical , @@ -93,5 +103,6 @@ pub (crate) use { split_button , popover , icon , + scrolled_window , vertically_filling , } ;