fractal/components/pill/
source.rsuse gtk::{glib, prelude::*, subclass::prelude::*};
use super::Pill;
use crate::components::AvatarData;
mod imp {
use std::{cell::Cell, marker::PhantomData};
use super::*;
#[repr(C)]
pub struct PillSourceClass {
parent_class: glib::object::ObjectClass,
pub(super) identifier: fn(&super::PillSource) -> String,
}
unsafe impl ClassStruct for PillSourceClass {
type Type = PillSource;
}
pub(super) fn pill_source_identifier(this: &super::PillSource) -> String {
let klass = this.class();
(klass.as_ref().identifier)(this)
}
#[derive(Debug, Default, glib::Properties)]
#[properties(wrapper_type = super::PillSource)]
pub struct PillSource {
#[property(get = Self::identifier)]
identifier: PhantomData<String>,
#[property(get = Self::display_name, set = Self::set_display_name, explicit_notify)]
display_name: PhantomData<String>,
#[property(get, set = Self::set_name_ambiguous, explicit_notify)]
is_name_ambiguous: Cell<bool>,
#[property(get = Self::disambiguated_name)]
disambiguated_name: PhantomData<String>,
#[property(get)]
avatar_data: AvatarData,
}
#[glib::object_subclass]
impl ObjectSubclass for PillSource {
const NAME: &'static str = "PillSource";
const ABSTRACT: bool = true;
type Type = super::PillSource;
type Class = PillSourceClass;
}
#[glib::derived_properties]
impl ObjectImpl for PillSource {}
impl PillSource {
fn identifier(&self) -> String {
imp::pill_source_identifier(&self.obj())
}
fn display_name(&self) -> String {
self.avatar_data.display_name()
}
fn set_display_name(&self, display_name: String) {
if self.display_name() == display_name {
return;
}
self.avatar_data.set_display_name(display_name);
let obj = self.obj();
obj.notify_display_name();
obj.notify_disambiguated_name();
}
fn set_name_ambiguous(&self, is_ambiguous: bool) {
if self.is_name_ambiguous.get() == is_ambiguous {
return;
}
self.is_name_ambiguous.set(is_ambiguous);
let obj = self.obj();
obj.notify_is_name_ambiguous();
obj.notify_disambiguated_name();
}
fn disambiguated_name(&self) -> String {
let display_name = self.display_name();
if self.is_name_ambiguous.get() {
format!("{display_name} ({})", self.identifier())
} else {
display_name
}
}
}
}
glib::wrapper! {
pub struct PillSource(ObjectSubclass<imp::PillSource>);
}
pub trait PillSourceExt: 'static {
#[allow(dead_code)]
fn identifier(&self) -> String;
fn display_name(&self) -> String;
fn set_display_name(&self, display_name: String);
#[allow(dead_code)]
fn is_name_ambiguous(&self) -> bool;
fn set_is_name_ambiguous(&self, is_ambiguous: bool);
fn disambiguated_name(&self) -> String;
fn avatar_data(&self) -> AvatarData;
fn connect_display_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId;
fn connect_disambiguated_name_notify<F: Fn(&Self) + 'static>(
&self,
f: F,
) -> glib::SignalHandlerId;
fn to_pill(&self) -> Pill;
}
impl<O: IsA<PillSource>> PillSourceExt for O {
fn identifier(&self) -> String {
self.upcast_ref().identifier()
}
fn display_name(&self) -> String {
self.upcast_ref().display_name()
}
fn set_display_name(&self, display_name: String) {
self.upcast_ref().set_display_name(display_name);
}
fn is_name_ambiguous(&self) -> bool {
self.upcast_ref().is_name_ambiguous()
}
fn set_is_name_ambiguous(&self, is_ambiguous: bool) {
self.upcast_ref().set_is_name_ambiguous(is_ambiguous);
}
fn disambiguated_name(&self) -> String {
self.upcast_ref().disambiguated_name()
}
fn avatar_data(&self) -> AvatarData {
self.upcast_ref().avatar_data()
}
fn connect_display_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
self.upcast_ref()
.connect_display_name_notify(move |source| f(source.downcast_ref().unwrap()))
}
fn connect_disambiguated_name_notify<F: Fn(&Self) + 'static>(
&self,
f: F,
) -> glib::SignalHandlerId {
self.upcast_ref()
.connect_disambiguated_name_notify(move |source| f(source.downcast_ref().unwrap()))
}
fn to_pill(&self) -> Pill {
Pill::new(self)
}
}
pub trait PillSourceImpl: ObjectImpl {
fn identifier(&self) -> String;
}
unsafe impl<T> IsSubclassable<T> for PillSource
where
T: PillSourceImpl,
T::Type: IsA<PillSource>,
{
fn class_init(class: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(class.upcast_ref_mut());
let klass = class.as_mut();
klass.identifier = identifier_trampoline::<T>;
}
}
fn identifier_trampoline<T>(this: &PillSource) -> String
where
T: ObjectSubclass + PillSourceImpl,
T::Type: IsA<PillSource>,
{
let this = this.downcast_ref::<T::Type>().unwrap();
this.imp().identifier()
}