Skip to main content

fractal/session_view/room_history/message_row/
caption.rs

1use gtk::{glib, prelude::*, subclass::prelude::*};
2use ruma::events::room::message::FormattedBody;
3
4use super::{ContentFormat, text::MessageText};
5use crate::{prelude::*, session::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,
98        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
99}
100
101impl MessageCaption {
102    pub fn new() -> Self {
103        glib::Object::new()
104    }
105
106    /// Set the caption.
107    pub(crate) fn set_caption(
108        &self,
109        caption: String,
110        formatted_caption: Option<FormattedBody>,
111        room: &Room,
112        format: ContentFormat,
113        detect_at_room: bool,
114    ) {
115        self.imp()
116            .set_caption(caption, formatted_caption, room, format, detect_at_room);
117    }
118}
119
120impl Default for MessageCaption {
121    fn default() -> Self {
122        Self::new()
123    }
124}
125
126impl ChildPropertyExt for MessageCaption {
127    fn child_property(&self) -> Option<gtk::Widget> {
128        self.child()
129    }
130
131    fn set_child_property(&self, child: Option<&impl IsA<gtk::Widget>>) {
132        self.set_child(child.map(Cast::upcast_ref));
133    }
134}