use gdk::{gio::ListStore, prelude::ListModelExt};
use glib::Cast;
use grx_macros::gtk_component;
use gtk::gdk;
use gtk::glib;
use gtk::{
prelude::GObjectPropertyExpressionExt,
traits::{ListBoxRowExt, WidgetExt},
};
use libadwaita::traits::{ActionRowExt, ComboRowExt, PreferencesRowExt};
use std::rc::Rc;
use crate::Component;
use crate::ComponentExt;
use crate::Interactable;
use crate::{handlers::Handler, item::Item, new_gc, props, ItemExt};
use super::{gtk_props::apply, utils::get_nth_child};
#[props]
#[derive(Default)]
pub struct Props {
pub title: String,
pub subtitle: String,
pub selectable: Option<bool>,
pub activatable: Option<bool>,
pub expand_suffix: Option<bool>,
pub on_change: Option<Handler<ComboRow>>,
}
impl std::fmt::Debug for Props {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Props")
.field("title", &self.title)
.field("subtitle", &self.subtitle)
.field("selectable", &self.selectable)
.field("activatable", &self.activatable)
.field("expand_suffix", &self.expand_suffix)
.field("on_click", &self.on_change.is_some())
.finish()
}
}
pub fn combo_row(mut props: Props) -> Rc<ComboRow> {
let combo_row = libadwaita::ComboRow::builder()
.title(&props.title)
.subtitle(&props.subtitle)
.build();
use gtk::glib::StaticType;
let model = gtk::gdk::gio::ListStore::new(crate::gtk_components::item::Item::static_type());
combo_row.set_model(Some(&model));
combo_row.set_expression(Some(Item::this_expression("value")));
if let Some(b) = props.activatable {
combo_row.set_activatable(b)
}
if let Some(b) = props.selectable {
combo_row.set_selectable(b)
}
if let Some(true) = props.expand_suffix {
if let Some(header) = get_nth_child::<gtk::Box>(&combo_row, 0) {
if let Some(suffixes) = get_nth_child::<gtk::Box>(&header, 3) {
suffixes.set_hexpand(true);
}
}
}
let change = props.on_change.take();
let comp = new_gc!(ComboRow { combo_row, props });
apply(comp.clone());
if let Some(handler) = change {
let c = comp.clone();
comp.widget.connect_selected_notify(move |_| {
handler(c.clone());
});
}
for c in comp.children().iter() {
if c.annotations().contains_key("prefix") {
comp.add_prefix(c.clone())
} else if c.annotations().contains_key("suffix") {
comp.add_suffix(c.clone())
}
}
comp
}
#[gtk_component(libadwaita::ComboRow)]
#[derive(Debug)]
pub struct ComboRow {}
impl Interactable for ComboRow {
fn on_change(self: &Rc<Self>, handler: impl Fn(&Rc<Self>) + 'static) {
let sel = self.clone();
self.widget.connect_selected_notify(move |_| handler(&sel));
}
}
impl ComboRow {
pub fn set_title(self: &Rc<Self>, title: &str) {
self.widget.set_title(title);
}
pub fn on_click(self: &Rc<Self>, handler: Handler<Self>) {
let s = self.clone();
self.widget.connect_activated(move |_| {
handler(s.clone());
});
}
pub fn items(self: &Rc<Self>) -> Vec<impl ItemExt> {
let mut items = Vec::new();
let model = &self.widget.model().unwrap();
let len = model.n_items();
for i in 0..len {
if let Some(item) = model.item(i).and_then(|o| o.downcast::<Item>().ok()) {
items.push(item);
}
}
items
}
pub fn set_disabled(self: &Rc<Self>, disabled: bool) {
self.widget.set_sensitive(!disabled);
}
pub fn clear(self: &Rc<Self>) {
let model = self.widget.model().unwrap();
let list = model.downcast_ref::<ListStore>().unwrap();
list.remove_all();
}
pub fn append(self: &Rc<Self>, item: Rc<impl ItemExt + 'static>) {
let item: Rc<dyn std::any::Any> = item;
let item: Rc<Item> = item.downcast().unwrap();
let model = self.widget.model().unwrap();
let list = model.downcast_ref::<ListStore>().unwrap();
list.append(item.as_ref());
}
pub fn selected(self: &Rc<Self>) -> Option<impl ItemExt> {
self.widget
.selected_item()
.and_then(|i| i.downcast::<Item>().ok())
}
pub fn select(self: &Rc<Self>, id: &str) {
for (i, item) in self.items().iter().enumerate() {
if item.id() == id {
self.widget.set_selected(i as u32);
}
}
}
pub fn add_prefix(self: &Rc<Self>, component: Component) {
let widget: Rc<gtk::Widget> = component.inner().downcast().unwrap();
self.widget.add_prefix(widget.as_ref());
}
pub fn add_suffix(self: &Rc<Self>, component: Component) {
let widget: Rc<gtk::Widget> = component.inner().downcast().unwrap();
self.widget.add_suffix(widget.as_ref());
}
}