fractal/components/
drag_overlay.rs1use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
2
3use crate::utils::BoundObject;
4
5mod imp {
6 use std::marker::PhantomData;
7
8 use super::*;
9
10 #[derive(Debug, Default, glib::Properties)]
11 #[properties(wrapper_type = super::DragOverlay)]
12 pub struct DragOverlay {
13 overlay: gtk::Overlay,
14 revealer: gtk::Revealer,
15 status: adw::StatusPage,
16 #[property(get = Self::title, set = Self::set_title)]
18 title: PhantomData<glib::GString>,
19 #[property(get = Self::child, set = Self::set_child, nullable)]
21 child: PhantomData<Option<gtk::Widget>>,
22 #[property(get, set = Self::set_drop_target)]
24 drop_target: BoundObject<gtk::DropTarget>,
25 }
26
27 #[glib::object_subclass]
28 impl ObjectSubclass for DragOverlay {
29 const NAME: &'static str = "DragOverlay";
30 type Type = super::DragOverlay;
31 type ParentType = gtk::Widget;
32
33 fn class_init(klass: &mut Self::Class) {
34 klass.set_css_name("dragoverlay");
35 klass.set_layout_manager_type::<gtk::BinLayout>();
36 }
37 }
38
39 #[glib::derived_properties]
40 impl ObjectImpl for DragOverlay {
41 fn constructed(&self) {
42 let obj = self.obj();
43
44 self.overlay.set_parent(&*obj);
45 self.overlay.add_overlay(&self.revealer);
46
47 self.revealer.set_can_target(false);
48 self.revealer
49 .set_transition_type(gtk::RevealerTransitionType::Crossfade);
50 self.revealer.set_reveal_child(false);
51 self.revealer.set_visible(false);
52
53 self.status.set_icon_name(Some("attachment-symbolic"));
54
55 self.revealer.set_child(Some(&self.status));
56
57 self.revealer.connect_child_revealed_notify(|revealer| {
58 if !revealer.reveals_child() && !revealer.is_child_revealed() {
61 revealer.set_visible(false);
62 }
63 });
64 }
65
66 fn dispose(&self) {
67 self.overlay.unparent();
68 }
69 }
70
71 impl WidgetImpl for DragOverlay {}
72
73 impl DragOverlay {
74 fn title(&self) -> glib::GString {
76 self.status.title()
77 }
78
79 fn set_title(&self, title: &str) {
81 self.status.set_title(title);
82 self.obj()
83 .update_property(&[gtk::accessible::Property::Label(title)]);
84 }
85
86 fn child(&self) -> Option<gtk::Widget> {
88 self.overlay.child()
89 }
90
91 fn set_child(&self, child: Option<>k::Widget>) {
93 self.overlay.set_child(child);
94 }
95
96 fn set_drop_target(&self, drop_target: gtk::DropTarget) {
98 let obj = self.obj();
99
100 if let Some(target) = self.drop_target.obj() {
101 obj.remove_controller(&target);
102 }
103 self.drop_target.disconnect_signals();
104
105 let handler_id = drop_target.connect_current_drop_notify(clone!(
106 #[weak(rename_to = revealer)]
107 self.revealer,
108 move |target| {
109 let reveal = target.current_drop().is_some();
110
111 if reveal {
112 revealer.set_visible(true);
113 }
114
115 revealer.set_reveal_child(reveal);
116 }
117 ));
118
119 obj.add_controller(drop_target.clone());
120 self.drop_target.set(drop_target, vec![handler_id]);
121 obj.notify_drop_target();
122 }
123 }
124}
125
126glib::wrapper! {
127 pub struct DragOverlay(ObjectSubclass<imp::DragOverlay>)
129 @extends gtk::Widget,
130 @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
131}
132
133impl DragOverlay {
134 pub fn new() -> Self {
135 glib::Object::new()
136 }
137}
138
139impl Default for DragOverlay {
140 fn default() -> Self {
141 Self::new()
142 }
143}