From e160649a14eb335deb807c8aae09ef03bd7b3530 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 6 Dec 2021 14:50:52 -0500 Subject: [PATCH] show scrollbar if >2 rows of app groups --- examples/app_library/grid_item/grid_item.ui | 3 +- examples/app_library/utils.rs | 9 ++ examples/app_library/window/imp.rs | 5 +- examples/app_library/window/mod.rs | 141 ++++++++++---------- examples/app_library/window/window.ui | 20 ++- 5 files changed, 102 insertions(+), 76 deletions(-) diff --git a/examples/app_library/grid_item/grid_item.ui b/examples/app_library/grid_item/grid_item.ui index 6c9d582..6e32859 100644 --- a/examples/app_library/grid_item/grid_item.ui +++ b/examples/app_library/grid_item/grid_item.ui @@ -5,13 +5,14 @@ center true 4 + 4 4 4 4 4 - 80 + 64 diff --git a/examples/app_library/utils.rs b/examples/app_library/utils.rs index 7b463e9..e320b8e 100644 --- a/examples/app_library/utils.rs +++ b/examples/app_library/utils.rs @@ -1,3 +1,4 @@ +use gtk4::ScrolledWindow; use std::path::PathBuf; use gtk4::glib; @@ -9,3 +10,11 @@ pub fn data_path() -> PathBuf { path.push("data.json"); path } + +pub fn set_group_scroll_policy(scroll_window: &ScrolledWindow, group_cnt: u32) { + if scroll_window.policy().1 == gtk4::PolicyType::Never && group_cnt > 16 { + scroll_window.set_policy(gtk4::PolicyType::Never, gtk4::PolicyType::Automatic); + } else if scroll_window.policy().1 == gtk4::PolicyType::Automatic && group_cnt <= 16 { + scroll_window.set_policy(gtk4::PolicyType::Never, gtk4::PolicyType::Never); + } +} diff --git a/examples/app_library/window/imp.rs b/examples/app_library/window/imp.rs index 2545a5c..7e30066 100644 --- a/examples/app_library/window/imp.rs +++ b/examples/app_library/window/imp.rs @@ -1,4 +1,5 @@ use gtk4 as gtk; +use gtk4::ScrolledWindow; use std::fs::File; use glib::signal::Inhibit; @@ -23,6 +24,8 @@ pub struct Window { pub app_model: OnceCell, #[template_child] pub group_grid_view: TemplateChild, + #[template_child] + pub group_scroll_window: TemplateChild, pub group_model: OnceCell, } @@ -50,7 +53,7 @@ impl ObjectImpl for Window { // Setup obj.setup_model(); - obj.restore_data(); + // obj.restore_data(); obj.setup_callbacks(); obj.setup_factory(); } diff --git a/examples/app_library/window/mod.rs b/examples/app_library/window/mod.rs index 8933f93..cf390fa 100644 --- a/examples/app_library/window/mod.rs +++ b/examples/app_library/window/mod.rs @@ -2,15 +2,14 @@ mod imp; use crate::app_group::AppGroup; use crate::app_group::AppGroupData; use crate::utils::data_path; +use crate::utils::set_group_scroll_policy; use glib::FromVariant; use glib::Variant; use gtk4 as gtk; -use gtk4::Button; use gtk4::Dialog; use gtk4::Entry; use gtk4::Label; use std::fs::File; -use std::path::Path; use crate::grid_item::GridItem; use glib::Object; @@ -39,7 +38,7 @@ impl Window { Object::new(&[("application", app)]).expect("Failed to create `Window`.") } - fn app_model(&self) -> &gio::ListStore { + fn _app_model(&self) -> &gio::ListStore { // Get state let imp = imp::Window::from_instance(self); imp.app_model.get().expect("Could not get model") @@ -140,6 +139,7 @@ impl Window { app_names: Vec::new(), category: "Utility".to_string(), }), + // Example of group with app name // AppGroup::new(AppGroupData { // id: 0, // name: "Custom Web".to_string(), @@ -191,7 +191,14 @@ impl Window { .expect("could not downcast sort list model to filter list model"); let entry = &imp.entry; + let scroll_window = &imp.group_scroll_window.get(); + // dynamically set scroll method bc of buggy gtk scroll behavior + self.group_model().connect_items_changed( + glib::clone!(@weak scroll_window => move |scroll_list_model, _i, _rmv_cnt, _add_cnt| { + set_group_scroll_policy(&scroll_window, scroll_list_model.n_items()); + }), + ); // Launch the application when an item of the list is activated app_grid_view.connect_activate(move |grid_view, position| { let model = grid_view.model().unwrap(); @@ -218,14 +225,16 @@ impl Window { // on activation change the group filter model to use the app names, and category group_grid_view.connect_activate(glib::clone!(@weak app_filter_model, @weak window => move |grid_view, position| { + println!("grid view activated."); let group_model = grid_view.model().unwrap().downcast::() .expect("could not downcast app group view model to single selection model") .model() .downcast::() .expect("could not downcast app group view selection model to list store model"); - // if last item in the model, don't change filter, instead show dialog for adding new group! + + // if last item in the model, don't change filter, instead show dialog for adding new group! if position == group_model.n_items() - 1 { - let entry = Entry::new(); + let dialog_entry = Entry::new(); let label = Label::new(Some("Name")); label.set_justify(gtk4::Justification::Left); label.set_xalign(0.0); @@ -237,12 +246,11 @@ impl Window { .margin_bottom(12) .margin_end(12) .margin_start(12) - .build(); vbox.append(&label); - vbox.append(&entry); + vbox.append(&dialog_entry); - let dialog = Dialog::builder() + let dialog = Dialog::builder() .modal(true) .resizable(false) .use_header_bar(true.into()) @@ -251,26 +259,49 @@ impl Window { .title("New App Group") .child(&vbox) .build(); - dialog.add_buttons(&[("Apply", gtk4::ResponseType::Apply), ("Cancel", gtk4::ResponseType::Cancel)]); - // dialog.add_action_widget(>k4::Button::new(), gtk4::ResponseType::Apply); - dialog.connect_response(glib::clone!(@weak entry, @weak group_model => move |dialog, response_type| { - println!("dialog should be closing..."); - if response_type == gtk4::ResponseType::Apply { - let new_app_group = AppGroup::new(AppGroupData { - id: 0, - name: entry.text().to_string(), - icon: "folder".to_string(), - mutable: true, - app_names: vec![], - category: "".to_string(), - }); - group_model.insert(group_model.n_items() - 1, &new_app_group); + let app = window + .application() + .expect("could not get application from window"); + + dialog.set_application(Some(&app)); + dialog.add_buttons(&[ + ("Apply", gtk4::ResponseType::Apply), + ("Cancel", gtk4::ResponseType::Cancel), + ]); + + dialog.connect_response( + glib::clone!(@weak dialog_entry, @weak group_model => move |dialog, response_type| { + println!("dialog should be closing..."); + let name = dialog_entry.text().to_string(); + if response_type == gtk4::ResponseType::Apply && name != "" { + let new_app_group = AppGroup::new(AppGroupData { + id: 0, + name: name, + icon: "folder".to_string(), + mutable: true, + app_names: vec![], + category: "".to_string(), + }); + group_model.insert(group_model.n_items() - 1, &new_app_group); + } + dialog.emit_close(); + }), + ); + dialog.connect_is_active_notify(move |win| { + let app = win + .application() + .expect("could not get application from window"); + let active_window = app + .active_window() + .expect("no active window available, closing app library."); + dbg!(&active_window); + if win == &active_window && !win.is_active() { + println!("no focus"); + // close top level window + window.close(); } - dialog.emit_close(); - })); - // let flags = gtk4::DialogFlags::MODAL; - // let dialog = Dialog::with_buttons(Some("New App Group"), Some(&window), flags, &[("Apply", gtk4::ResponseType::Apply), ("Cancel", gtk4::ResponseType::Cancel)]); - dialog.present(); + }); + dialog.show(); return; }; // update the application filter @@ -308,35 +339,6 @@ impl Window { }); group_filter_model.set_filter(Some(new_filter).as_ref()); })); - // can't listen to select signal on grid view, but this a good to know example... - // if group_grid_view.connect_local("select", true, glib::clone!(@weak group_filter_model => @default-return None, move |args| { - // let grid_view = args[0].get::().unwrap(); - // let position = args[1].get::().unwrap(); - // // on activation change the group filter model to use the app names, and category - // let model = grid_view.model().unwrap(); - // let app_info = model - // .item(position) - // .unwrap() - // .downcast::() - // .unwrap(); - // let category: String; - // if let Ok(category_prop) = app_info.property("category") { - // category = category_prop.get::().unwrap_or("".to_string()).to_lowercase(); - // } else { - // category = "".to_string(); - // } - // let new_filter: gtk::CustomFilter = gtk::CustomFilter::new(move |obj| { - // let app = obj - // .downcast_ref::() - // .expect("The Object needs to be of type AppInfo"); - // match app.categories() { - // Some(categories) => categories.to_string().to_lowercase().contains(&category), - // None => false, - // } - // }); - // group_filter_model.set_filter(Some(new_filter).as_ref()); - // None - // })).is_err() { println!("Failed to connect to grid view select...") }; entry.connect_changed( glib::clone!(@weak app_filter_model, @weak sorted_model => move |search: >k::SearchEntry| { @@ -398,19 +400,18 @@ impl Window { window.close(); })); self.add_action(&action_quit); - - // window.connect_is_active_notify(|win| { - // let app = win - // .application() - // .expect("could not get application from window"); - // let active_window = app - // .active_window() - // .expect("no active window available, closing app library."); - // dbg!(&active_window); - // if !active_window.is_active() { - // win.close(); - // } - // }); + window.connect_is_active_notify(move |win| { + let app = win + .application() + .expect("could not get application from window"); + let active_window = app + .active_window() + .expect("no active window available, closing app library."); + dbg!(&active_window); + if win == &active_window && !win.is_active() { + win.close(); + } + }); } fn setup_factory(&self) { @@ -465,9 +466,11 @@ impl Window { .into_iter() .map(|data| AppGroup::new(data).upcast::()) .collect(); + let scroll_window = &imp::Window::from_instance(self).group_scroll_window; // Insert restored objects into model self.group_model().splice(3, 0, &app_group_objects); + set_group_scroll_policy(&scroll_window, self.group_model().n_items()); } else { println!("Backup file does not exist yet {:?}", data_path()); } diff --git a/examples/app_library/window/window.ui b/examples/app_library/window/window.ui index 2be8391..b56178b 100644 --- a/examples/app_library/window/window.ui +++ b/examples/app_library/window/window.ui @@ -44,11 +44,21 @@ - - 8 - 8 - true - false + + never + never + true + 150 + 300 + 12 + + + 8 + 8 + true + false + +