From d05f517366d70084d82b77e6b6e23515d9ea5580 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 3 Dec 2021 12:40:51 -0500 Subject: [PATCH] filter based on app names or category --- examples/app_library/grid_item/imp.rs | 2 + examples/app_library/grid_item/mod.rs | 11 +++- examples/app_library/window/mod.rs | 93 +++++++++++++++++++++------ examples/app_library/window/window.ui | 2 +- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/examples/app_library/grid_item/imp.rs b/examples/app_library/grid_item/imp.rs index 2e7b3b67..4707da76 100644 --- a/examples/app_library/grid_item/imp.rs +++ b/examples/app_library/grid_item/imp.rs @@ -2,6 +2,7 @@ use gtk::glib; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk4 as gtk; +use std::cell::Cell; use gtk::CompositeTemplate; @@ -12,6 +13,7 @@ pub struct GridItem { pub name: TemplateChild, #[template_child] pub image: TemplateChild, + pub index: Cell, } #[glib::object_subclass] diff --git a/examples/app_library/grid_item/mod.rs b/examples/app_library/grid_item/mod.rs index 6db1ec46..b7c895b3 100644 --- a/examples/app_library/grid_item/mod.rs +++ b/examples/app_library/grid_item/mod.rs @@ -7,8 +7,9 @@ use gtk::subclass::prelude::*; use gtk::{gio, glib}; glib::wrapper! { - pub struct GridItem(ObjectSubclass) - @extends gtk::Widget, gtk::Box; +pub struct GridItem(ObjectSubclass) + @extends gtk::Widget, gtk::Box, + @implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget; } impl Default for GridItem { @@ -40,11 +41,15 @@ impl GridItem { ); } if let Ok(icon) = app_group.property("icon") { - &self_.image.set_from_icon_name(Some( + self_.image.set_from_icon_name(Some( &icon .get::() .expect("Property name needs to be a String."), )); } } + + pub fn set_index(&self, index: u32) { + imp::GridItem::from_instance(self).index.set(index); + } } diff --git a/examples/app_library/window/mod.rs b/examples/app_library/window/mod.rs index 4e5af176..aff0818a 100644 --- a/examples/app_library/window/mod.rs +++ b/examples/app_library/window/mod.rs @@ -1,7 +1,10 @@ mod imp; use crate::app_group::AppGroup; use crate::app_group::AppGroupData; +use glib::FromVariant; +use glib::Variant; use gtk4 as gtk; +use gtk4::Button; use std::path::Path; use crate::grid_item::GridItem; @@ -127,13 +130,21 @@ impl Window { app_names: Vec::new(), category: "Utility".to_string(), }), + AppGroup::new(AppGroupData { + id: 0, + name: "Web".to_string(), + icon: "folder".to_string(), + mutable: true, + app_names: vec!["Firefox Web Browser".to_string()], + category: "".to_string(), + }), ] .iter() .for_each(|group| { group_model.append(group); }); - imp.group_grid_view - .set_model(Some(>k4::SingleSelection::new(Some(&group_model)))); + let group_selection = gtk4::SingleSelection::new(Some(&group_model)); + imp.group_grid_view.set_model(Some(&group_selection)); } fn setup_callbacks(&self) { @@ -187,7 +198,6 @@ impl Window { } }); - // TODO connect to custom signal from app group grid item activation // 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 => move |grid_view, position| { let model = grid_view.model().unwrap(); @@ -196,16 +206,27 @@ impl Window { .unwrap() .downcast::() .unwrap(); - let category: String; + let category = if let Ok(category_prop) = app_info.property("category") { - category = category_prop.get::().unwrap_or("".to_string()).to_lowercase(); + category_prop.get::().unwrap_or("".to_string()).to_lowercase() } else { - category = "".to_string(); - } + "".to_string() + }; + + let app_names = + if let Ok(app_names_prop) = app_info.property("appnames") { + >::from_variant(&app_names_prop.get::().expect("appnames nneds to be a variant.")).unwrap_or_default() + } else { + vec![] + }; + dbg!(&app_names); let new_filter: gtk::CustomFilter = gtk::CustomFilter::new(move |obj| { let app = obj .downcast_ref::() .expect("The Object needs to be of type AppInfo"); + if app_names.len() > 0 { + return app_names.contains(&String::from(app.name().as_str())); + } match app.categories() { Some(categories) => categories.to_string().to_lowercase().contains(&category), None => false, @@ -213,6 +234,35 @@ 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| { @@ -289,20 +339,23 @@ impl Window { item.set_child(Some(&row)); }); - // the bind stage is used for "binding" the data to the created widgets on the "setup" stage - app_factory.connect_bind(move |_factory, grid_item| { - let app_info = grid_item - .item() - .unwrap() - .downcast::() - .unwrap(); - - let child = grid_item.child().unwrap().downcast::().unwrap(); - child.set_app_info(&app_info); - }); - // Set the factory of the list view let imp = imp::Window::from_instance(self); - imp.app_grid_view.set_factory(Some(&app_factory)); + // the bind stage is used for "binding" the data to the created widgets on the "setup" stage + let app_grid_view = &imp.app_grid_view.get(); + app_factory.connect_bind( + glib::clone!(@weak app_grid_view => move |_factory, grid_item| { + let app_info = grid_item + .item() + .unwrap() + .downcast::() + .unwrap(); + + let child = grid_item.child().unwrap().downcast::().unwrap(); + child.set_app_info(&app_info); + }), + ); + // Set the factory of the list view + app_grid_view.set_factory(Some(&app_factory)); let group_factory = SignalListItemFactory::new(); group_factory.connect_setup(move |_factory, item| { diff --git a/examples/app_library/window/window.ui b/examples/app_library/window/window.ui index 84167ea0..2be8391b 100644 --- a/examples/app_library/window/window.ui +++ b/examples/app_library/window/window.ui @@ -47,7 +47,7 @@ 8 8 - false + true false