[fractal/fractal-next] Make a drag and drop overlay widget
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] Make a drag and drop overlay widget
- Date: Tue, 22 Mar 2022 14:41:28 +0000 (UTC)
commit ec2852dc90225c774b2ea47af3d759a66cbad4f7
Author: Maximiliano Sandoval R <msandova gnome org>
Date: Sat Dec 25 23:33:36 2021 +0100
Make a drag and drop overlay widget
data/resources/ui/content-room-history.ui | 59 +++++-------
src/components/drag_overlay.rs | 143 ++++++++++++++++++++++++++++++
src/components/mod.rs | 2 +
src/session/content/room_history/mod.rs | 11 +--
4 files changed, 172 insertions(+), 43 deletions(-)
---
diff --git a/data/resources/ui/content-room-history.ui b/data/resources/ui/content-room-history.ui
index 0a729ba89..081ab7806 100644
--- a/data/resources/ui/content-room-history.ui
+++ b/data/resources/ui/content-room-history.ui
@@ -129,22 +129,6 @@
</child>
<child>
<object class="GtkOverlay" id="content">
- <child type="overlay">
- <object class="GtkRevealer" id="drag_revealer">
- <property name="can-target">False</property>
- <property name="transition_type">crossfade</property>
- <property name="reveal_child">False</property>
- <child>
- <object class="AdwStatusPage">
- <property name="icon-name">document-send-symbolic</property>
- <property name="title" translatable="yes">Drop Here to Send</property>
- <style>
- <class name="drag-n-drop-overlay"/>
- </style>
- </object>
- </child>
- </object>
- </child>
<child type="overlay">
<object class="GtkRevealer" id="scroll_btn_revealer">
<property name="transition_type">crossfade</property>
@@ -169,30 +153,35 @@
</object>
</child>
<child>
- <object class="GtkScrolledWindow" id="scrolled_window">
- <property name="vexpand">True</property>
- <property name="hscrollbar-policy">never</property>
- <style>
- <class name="room-history"/>
- </style>
+ <object class="DragOverlay" id="drag_overlay">
+ <property name="title" translatable="yes">Drop Here to Send</property>
<property name="child">
- <object class="AdwClampScrollable">
+ <object class="GtkScrolledWindow" id="scrolled_window">
<property name="vexpand">True</property>
- <property name="hexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <style>
+ <class name="room-history"/>
+ </style>
<property name="child">
- <object class="GtkListView" id="listview">
- <style>
- <class name="navigation-sidebar"/>
- </style>
- <property name="factory">
- <object class="GtkBuilderListItemFactory">
- <property name="resource">/org/gnome/FractalNext/content-item.ui</property>
+ <object class="AdwClampScrollable">
+ <property name="vexpand">True</property>
+ <property name="hexpand">True</property>
+ <property name="child">
+ <object class="GtkListView" id="listview">
+ <style>
+ <class name="navigation-sidebar"/>
+ </style>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property
name="resource">/org/gnome/FractalNext/content-item.ui</property>
+ </object>
+ </property>
+ <property name="single-click-activate">True</property>
+ <accessibility>
+ <property name="label" translatable="yes">Room History</property>
+ </accessibility>
</object>
</property>
- <property name="single-click-activate">True</property>
- <accessibility>
- <property name="label" translatable="yes">Room History</property>
- </accessibility>
</object>
</property>
</object>
diff --git a/src/components/drag_overlay.rs b/src/components/drag_overlay.rs
new file mode 100644
index 000000000..93098dd10
--- /dev/null
+++ b/src/components/drag_overlay.rs
@@ -0,0 +1,143 @@
+use gtk::{glib, prelude::*, subclass::prelude::*};
+
+mod imp {
+ use std::cell::RefCell;
+
+ use adw::subclass::prelude::*;
+ use once_cell::sync::Lazy;
+
+ use super::*;
+
+ #[derive(Debug, Default)]
+ pub struct DragOverlay {
+ pub overlay: gtk::Overlay,
+ pub revealer: gtk::Revealer,
+ pub status: adw::StatusPage,
+ pub drop_target: RefCell<Option<gtk::DropTarget>>,
+ pub handler_id: RefCell<Option<glib::SignalHandlerId>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for DragOverlay {
+ const NAME: &'static str = "DragOverlay";
+ type Type = super::DragOverlay;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.set_css_name("dragoverlay");
+ }
+ }
+
+ impl ObjectImpl for DragOverlay {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpecString::new(
+ "title",
+ "title",
+ "title",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpecObject::new(
+ "child",
+ "child",
+ "child",
+ gtk::Widget::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpecObject::new(
+ "drop-target",
+ "drop-target",
+ "drop-target",
+ gtk::DropTarget::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ ]
+ });
+ PROPERTIES.as_ref()
+ }
+
+ fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "title" => self.status.title().to_value(),
+ "child" => self.overlay.child().to_value(),
+ "drop-target" => self.drop_target.borrow().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "title" => self.status.set_title(value.get().unwrap()),
+ "child" => self
+ .overlay
+ .set_child(value.get::<gtk::Widget>().ok().as_ref()),
+ "drop-target" => obj.set_drop_target(&value.get::<gtk::DropTarget>().unwrap()),
+ _ => unimplemented!(),
+ };
+ }
+
+ fn constructed(&self, obj: &Self::Type) {
+ self.overlay.set_parent(obj);
+ self.overlay.add_overlay(&self.revealer);
+
+ self.revealer.set_can_target(false);
+ self.revealer
+ .set_transition_type(gtk::RevealerTransitionType::Crossfade);
+ self.revealer.set_reveal_child(false);
+
+ self.status.set_icon_name(Some("document-send-symbolic"));
+
+ self.revealer.set_child(Some(&self.status));
+ }
+ }
+ impl WidgetImpl for DragOverlay {}
+ impl BinImpl for DragOverlay {}
+}
+
+glib::wrapper! {
+ pub struct DragOverlay(ObjectSubclass<imp::DragOverlay>)
+ @extends gtk::Widget, adw::Bin;
+}
+
+impl Default for DragOverlay {
+ fn default() -> Self {
+ glib::Object::new(&[]).unwrap()
+ }
+}
+
+impl DragOverlay {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn set_drop_target(&self, drop_target: >k::DropTarget) {
+ let priv_ = self.imp();
+
+ if let Some(target) = priv_.drop_target.borrow_mut().take() {
+ self.remove_controller(&target);
+
+ if let Some(handler_id) = priv_.handler_id.borrow_mut().take() {
+ target.disconnect(handler_id);
+ }
+ }
+
+ let handler_id = drop_target.connect_current_drop_notify(
+ glib::clone!(@weak priv_.revealer as revealer => move |target| {
+ revealer.set_reveal_child(target.current_drop().is_some());
+ }),
+ );
+ priv_.handler_id.replace(Some(handler_id));
+
+ self.add_controller(drop_target);
+ priv_.drop_target.replace(Some(drop_target.clone()));
+ self.notify("drop-target");
+ }
+}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index 4a7118ca9..06958227e 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -6,6 +6,7 @@ mod badge;
mod button_row;
mod context_menu_bin;
mod custom_entry;
+mod drag_overlay;
mod editable_avatar;
mod entry_row;
mod in_app_notification;
@@ -29,6 +30,7 @@ pub use self::{
button_row::ButtonRow,
context_menu_bin::{ContextMenuBin, ContextMenuBinExt, ContextMenuBinImpl},
custom_entry::CustomEntry,
+ drag_overlay::DragOverlay,
editable_avatar::EditableAvatar,
entry_row::EntryRow,
in_app_notification::InAppNotification,
diff --git a/src/session/content/room_history/mod.rs b/src/session/content/room_history/mod.rs
index 9410994f5..0a98eaaea 100644
--- a/src/session/content/room_history/mod.rs
+++ b/src/session/content/room_history/mod.rs
@@ -26,7 +26,7 @@ use self::{
};
use crate::spawn;
use crate::{
- components::{CustomEntry, Pill, RoomTitle},
+ components::{CustomEntry, DragOverlay, Pill, RoomTitle},
session::{
content::{MarkdownPopover, RoomDetails},
room::{Item, Room, RoomType, Timeline, TimelineState},
@@ -90,7 +90,7 @@ mod imp {
pub stack: TemplateChild<gtk::Stack>,
pub is_loading: Cell<bool>,
#[template_child]
- pub drag_revealer: TemplateChild<gtk::Revealer>,
+ pub drag_overlay: TemplateChild<DragOverlay>,
}
#[glib::object_subclass]
@@ -758,12 +758,7 @@ impl RoomHistory {
}),
);
- target.connect_current_drop_notify(glib::clone!(@weak self as obj => move |target| {
- let priv_ = imp::RoomHistory::from_instance(&obj);
- priv_.drag_revealer.set_reveal_child(target.current_drop().is_some());
- }));
-
- priv_.scrolled_window.add_controller(&target);
+ priv_.drag_overlay.set_drop_target(&target);
}
fn open_attach_dialog(&self, bytes: Vec<u8>, mime: &str, title: &str) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]