replace hashmap index with custom gobject properties impl

This commit is contained in:
yggverse 2024-11-18 22:16:20 +02:00
parent 5d647518c0
commit 46a25306e1
4 changed files with 114 additions and 26 deletions

View File

@ -23,7 +23,7 @@ impl Gemini {
let widget = Rc::new(Widget::new()); let widget = Rc::new(Widget::new());
// Add new identity option // Add new identity option
widget.form.list.append(None, "Create new.."); widget.form.list.append(None, "Create new..", true);
// Collect additional options from database // Collect additional options from database
match profile.identity.gemini.database.records() { match profile.identity.gemini.database.records() {
@ -49,6 +49,7 @@ impl Gemini {
Some(name) => format!("{name} ({expires})"), Some(name) => format!("{name} ({expires})"),
None => format!("{expires}"), None => format!("{expires}"),
}, },
true,
); );
} }
} }

View File

@ -1,10 +1,12 @@
use gtk::{gio::ListStore, DropDown, Label}; mod item;
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use item::Item;
use gio::prelude::{Cast, CastNone};
use gtk::{gio::ListStore, prelude::ListItemExt, DropDown, Label, ListItem, SignalListItemFactory};
pub struct List { pub struct List {
pub gobject: DropDown, pub gobject: DropDown,
model: ListStore, model: ListStore,
index: Rc<RefCell<HashMap<Label, Option<i64>>>>,
} }
impl List { impl List {
@ -12,31 +14,40 @@ impl List {
/// Create new `Self` /// Create new `Self`
pub fn new() -> Self { pub fn new() -> Self {
let index = Rc::new(RefCell::new(HashMap::new())); // Init model with custom `GObject` properties
let model = ListStore::new::<Label>(); let model = ListStore::new::<Item>();
let gobject = DropDown::builder().model(&model).build();
Self { // Setup item factory to append items after `DropDown` init
model, let factory = SignalListItemFactory::new();
index,
gobject, // @TODO factory.connect_setup(move |_, gobject| {});
} factory.connect_bind(move |_, gobject| {
// Cast components
let list_item = gobject.downcast_ref::<ListItem>().unwrap();
let item = list_item.item().and_downcast::<Item>().unwrap();
// Update menu item
list_item.set_child(Some(&Label::new(Some(&item.label()))));
// @TODO
println!("{:?}", item.profile_identity_gemini_id_option());
println!("{:?}", item.label());
println!("{:?}", item.is_enabled());
});
// Init list `GObject`
let gobject = DropDown::builder().model(&model).factory(&factory).build();
// Return activated `Self`
Self { model, gobject }
} }
// Actions // Actions
/// Append new item with `profile_identity_gemini_id` as `key` and label as `value` /// Append new item with `profile_identity_gemini_id` as `key` and label as `value`
pub fn append(&self, profile_identity_gemini_id: Option<i64>, label: &str) { pub fn append(&self, profile_identity_gemini_id: Option<i64>, label: &str, is_enabled: bool) {
// Create new label for item self.model
let item = Label::new(Some(label)); .append(&Item::new(profile_identity_gemini_id, label, is_enabled));
// Append formatted record
self.model.append(&item);
// Register ID in hash map index
self.index
.borrow_mut()
.insert(item, profile_identity_gemini_id);
} }
// Events // Events
@ -44,9 +55,13 @@ impl List {
/// Run callback function on `connect_selected_notify` event /// Run callback function on `connect_selected_notify` event
/// * return formatted `profile_identity_gemini_id` match selected /// * return formatted `profile_identity_gemini_id` match selected
pub fn connect_selected_notify(&self, callback: impl Fn(Option<i64>) + 'static) { pub fn connect_selected_notify(&self, callback: impl Fn(Option<i64>) + 'static) {
self.gobject.connect_selected_notify({ self.gobject.connect_selected_notify(move |list| {
let index = self.index.clone(); callback(
move |list| callback(*index.borrow().get(&list.selected_item().unwrap()).unwrap()) list.selected_item()
.and_downcast::<Item>()
.unwrap()
.profile_identity_gemini_id_option(),
)
}); });
} }
} }

View File

@ -0,0 +1,38 @@
mod imp;
use gtk::glib::{self, Object};
glib::wrapper! {
pub struct Item(ObjectSubclass<imp::Item>);
}
// C-based conversion for `None` value
const PROFILE_IDENTITY_GEMINI_ID_NONE: i64 = -1;
impl Item {
// Constructors
/// Create new `GObject` with formatted properties
pub fn new(profile_identity_gemini_id: Option<i64>, label: &str, is_enabled: bool) -> Self {
Object::builder()
.property(
"profile_identity_gemini_id",
match profile_identity_gemini_id {
Some(value) => value,
None => PROFILE_IDENTITY_GEMINI_ID_NONE,
},
)
.property("label", label)
.property("is_enabled", is_enabled)
.build()
}
// Getters
/// Additional `profile_identity_gemini_id` wrapper with `Option` value support
pub fn profile_identity_gemini_id_option(&self) -> Option<i64> {
match self.profile_identity_gemini_id() {
PROFILE_IDENTITY_GEMINI_ID_NONE => None,
value => Some(value),
}
}
}

View File

@ -0,0 +1,34 @@
//! Custom `GObject` implementation for dropdown
//! [ListStore](https://docs.gtk.org/gio/class.ListStore.html) menu item
use gtk::{
gio::subclass::prelude::{DerivedObjectProperties, ObjectImpl, ObjectImplExt, ObjectSubclass},
glib::{self, Object, Properties},
prelude::ObjectExt,
};
use std::cell::{Cell, RefCell};
#[derive(Properties, Default)]
#[properties(wrapper_type = super::Item)]
pub struct Item {
#[property(get, set)]
profile_identity_gemini_id: Cell<i64>,
#[property(get, set)]
label: RefCell<String>,
#[property(get, set)]
is_enabled: Cell<bool>,
}
#[glib::object_subclass]
impl ObjectSubclass for Item {
const NAME: &str = "Item"; // @TODO make globally unique
type Type = super::Item;
type ParentType = Object;
}
#[glib::derived_properties]
impl ObjectImpl for Item {
fn constructed(&self) {
self.parent_constructed();
}
}