fractal/session/view/content/room_history/message_row/
caption.rs

1use gtk::{glib, prelude::*, subclass::prelude::*};
2use ruma::events::room::message::FormattedBody;
3
4use super::{text::MessageText, ContentFormat};
5use crate::{prelude::*, session::model::Room};
6
7mod imp {
8    use std::marker::PhantomData;
9
10    use super::*;
11
12    #[derive(Debug, Default, glib::Properties)]
13    #[properties(wrapper_type = super::MessageCaption)]
14    pub struct MessageCaption {
15        /// The widget displaying the file alongside the caption.
16        #[property(get = Self::child, set = Self::set_child, explicit_notify, nullable)]
17        child: PhantomData<Option<gtk::Widget>>,
18        caption_widget: MessageText,
19    }
20
21    #[glib::object_subclass]
22    impl ObjectSubclass for MessageCaption {
23        const NAME: &'static str = "ContentMessageCaption";
24        type Type = super::MessageCaption;
25        type ParentType = gtk::Grid;
26
27        fn class_init(klass: &mut Self::Class) {
28            klass.set_css_name("message-caption");
29
30            klass.set_accessible_role(gtk::AccessibleRole::Group);
31        }
32    }
33
34    #[glib::derived_properties]
35    impl ObjectImpl for MessageCaption {
36        fn constructed(&self) {
37            self.parent_constructed();
38
39            let obj = self.obj();
40            obj.attach(&self.caption_widget, 0, 1, 1, 1);
41            obj.set_row_spacing(6);
42        }
43    }
44
45    impl WidgetImpl for MessageCaption {}
46    impl GridImpl for MessageCaption {}
47
48    impl MessageCaption {
49        /// The widget displaying the file alongside the caption.
50        fn child(&self) -> Option<gtk::Widget> {
51            self.obj().child_at(0, 0)
52        }
53
54        /// Set the widget displaying the file alongside the caption.
55        fn set_child(&self, widget: Option<gtk::Widget>) {
56            let prev_widget = self.child();
57
58            if prev_widget == widget {
59                return;
60            }
61            let obj = self.obj();
62
63            if let Some(widget) = prev_widget {
64                obj.remove(&widget);
65            }
66
67            if let Some(widget) = widget {
68                obj.attach(&widget, 0, 0, 1, 1);
69            }
70
71            obj.notify_child();
72        }
73
74        /// Set the caption.
75        pub(super) fn set_caption(
76            &self,
77            caption: String,
78            formatted_caption: Option<FormattedBody>,
79            room: &Room,
80            format: ContentFormat,
81            detect_at_room: bool,
82        ) {
83            self.caption_widget.with_markup(
84                formatted_caption,
85                caption,
86                room,
87                format,
88                detect_at_room,
89            );
90        }
91    }
92}
93
94glib::wrapper! {
95    /// A widget displaying a caption alongside a file message.
96    pub struct MessageCaption(ObjectSubclass<imp::MessageCaption>)
97        @extends gtk::Widget, gtk::Grid, @implements gtk::Accessible;
98}
99
100impl MessageCaption {
101    pub fn new() -> Self {
102        glib::Object::new()
103    }
104
105    /// Set the caption.
106    pub(crate) fn set_caption(
107        &self,
108        caption: String,
109        formatted_caption: Option<FormattedBody>,
110        room: &Room,
111        format: ContentFormat,
112        detect_at_room: bool,
113    ) {
114        self.imp()
115            .set_caption(caption, formatted_caption, room, format, detect_at_room);
116    }
117}
118
119impl Default for MessageCaption {
120    fn default() -> Self {
121        Self::new()
122    }
123}
124
125impl ChildPropertyExt for MessageCaption {
126    fn child_property(&self) -> Option<gtk::Widget> {
127        self.child()
128    }
129
130    fn set_child_property(&self, child: Option<&impl IsA<gtk::Widget>>) {
131        self.set_child(child.map(Cast::upcast_ref));
132    }
133}