window: First work for drag overlay visuals
Issue #59 Part-of: <https://gitlab.gnome.org/GNOME/loupe/-/merge_requests/258>
This commit is contained in:
parent
597f581980
commit
3111efdd94
3 changed files with 114 additions and 35 deletions
|
|
@ -168,46 +168,53 @@
|
||||||
<property name="locked">True</property>
|
<property name="locked">True</property>
|
||||||
<property name="reveal-flap" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create"/>
|
<property name="reveal-flap" bind-source="properties_button" bind-property="active" bind-flags="bidirectional|sync-create"/>
|
||||||
<property name="content">
|
<property name="content">
|
||||||
<object class="GtkStack" id="stack">
|
<object class="GtkOverlay" id="drop_area_overlay">
|
||||||
<property name="visible-child">status_page</property>
|
<style>
|
||||||
<property name="vexpand">True</property>
|
<class name="custom-drag-n-drop-highlight"/>
|
||||||
<child>
|
</style>
|
||||||
<object class="AdwStatusPage" id="status_page">
|
|
||||||
<property name="title" translatable="yes">View Images</property>
|
|
||||||
<property name="description" translatable="yes">Drag and drop images here</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton">
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="label" translatable="yes">_Open Files…</property>
|
|
||||||
<property name="use-underline">True</property>
|
|
||||||
<property name="action-name">win.open</property>
|
|
||||||
<style>
|
|
||||||
<class name="pill"/>
|
|
||||||
<class name="suggested-action"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="LpImageView" id="image_view">
|
|
||||||
<child>
|
|
||||||
<object class="GtkGestureClick" id="forward_click_gesture">
|
|
||||||
<property name="button">9</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkGestureClick" id="backward_click_gesture">
|
|
||||||
<property name="button">8</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkDropTarget" id="drop_target">
|
<object class="GtkDropTarget" id="drop_target">
|
||||||
<property name="actions">copy</property>
|
<property name="actions">copy</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStack" id="stack">
|
||||||
|
<property name="visible-child">status_page</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage" id="status_page">
|
||||||
|
<property name="title" translatable="yes">View Images</property>
|
||||||
|
<property name="description" translatable="yes">Drag and drop images here</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton">
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="label" translatable="yes">_Open Files…</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="action-name">win.open</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill"/>
|
||||||
|
<class name="suggested-action"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="LpImageView" id="image_view">
|
||||||
|
<child>
|
||||||
|
<object class="GtkGestureClick" id="forward_click_gesture">
|
||||||
|
<property name="button">9</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGestureClick" id="backward_click_gesture">
|
||||||
|
<property name="button">8</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</property>
|
</property>
|
||||||
<property name="separator">
|
<property name="separator">
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,15 @@ row.property label.subtitle {
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 200);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-drag-n-drop-highlight {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.lp-dragging-area-highlight {
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: alpha(@accent_color, 0.35);
|
||||||
|
border: 2px @accent_color solid;
|
||||||
|
}
|
||||||
|
|
||||||
lpprintpreview {
|
lpprintpreview {
|
||||||
background-color: rgb(240, 240, 240);
|
background-color: rgb(240, 240, 240);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,12 @@ mod imp {
|
||||||
pub(super) image_view: TemplateChild<LpImageView>,
|
pub(super) image_view: TemplateChild<LpImageView>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) properties_view: TemplateChild<LpPropertiesView>,
|
pub(super) properties_view: TemplateChild<LpPropertiesView>,
|
||||||
|
|
||||||
|
#[template_child]
|
||||||
|
pub(super) drop_area_overlay: TemplateChild<gtk::Overlay>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) drop_target: TemplateChild<gtk::DropTarget>,
|
pub(super) drop_target: TemplateChild<gtk::DropTarget>,
|
||||||
|
pub(super) drop_area_highlight_widget: OnceCell<gtk::Widget>,
|
||||||
|
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub(super) forward_click_gesture: TemplateChild<gtk::GestureClick>,
|
pub(super) forward_click_gesture: TemplateChild<gtk::GestureClick>,
|
||||||
|
|
@ -374,12 +378,41 @@ mod imp {
|
||||||
|
|
||||||
self.drop_target.set_types(&[gdk::FileList::static_type()]);
|
self.drop_target.set_types(&[gdk::FileList::static_type()]);
|
||||||
|
|
||||||
|
// # Drag and drop stuff ---
|
||||||
|
|
||||||
|
// - Define widget used as a visual cue for users trying to drag-n-drop
|
||||||
|
self.drop_area_highlight_widget.set({
|
||||||
|
const MARGIN: i32 = 24;
|
||||||
|
gtk::Box::builder()
|
||||||
|
.margin_top(MARGIN).margin_bottom(MARGIN).margin_start(MARGIN).margin_end(MARGIN)
|
||||||
|
.css_classes(["lp-dragging-area-highlight"])
|
||||||
|
.can_target(false)
|
||||||
|
.build()
|
||||||
|
.upcast() // Upcasting to fit into the required `gtk::Widget` type
|
||||||
|
}).expect("Drop area highlight widget was defined twice");
|
||||||
|
|
||||||
|
// - Adds the widget on drag enter
|
||||||
|
self.drop_target.connect_enter(
|
||||||
|
clone!(@weak obj => @default-return gdk::DragAction::COPY, move |_drop_target, _x, _y| {
|
||||||
|
obj.toggle_drop_area_highlight(true);
|
||||||
|
gdk::DragAction::COPY
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// - Removes the widget on drag leave
|
||||||
|
self.drop_target.connect_leave(clone!(@weak obj => move |_drop_target| {
|
||||||
|
obj.toggle_drop_area_highlight(false);
|
||||||
|
}));
|
||||||
|
|
||||||
// For callbacks, you will want to reference the GTK docs on
|
// For callbacks, you will want to reference the GTK docs on
|
||||||
// the relevant signal to see which parameters you need.
|
// the relevant signal to see which parameters you need.
|
||||||
// In this case, we need only need the GValue,
|
// In this case, we need only need the GValue,
|
||||||
// so we name it `value` then use `_` for the other spots.
|
// so we name it `value` then use `_` for the other spots.
|
||||||
self.drop_target.connect_drop(
|
self.drop_target.connect_drop(
|
||||||
clone!(@weak obj => @default-return false, move |_, value, _, _| {
|
clone!(@weak obj => @default-return false, move |_, value, _, _| {
|
||||||
|
// - Removes the widget on drag completion
|
||||||
|
obj.toggle_drop_area_highlight(false);
|
||||||
|
|
||||||
// Here we use a GValue, which is a dynamic object that can hold different types,
|
// Here we use a GValue, which is a dynamic object that can hold different types,
|
||||||
// e.g. strings, numbers, or in this case objects. In order to get the GdkFileList
|
// e.g. strings, numbers, or in this case objects. In order to get the GdkFileList
|
||||||
// from the GValue, we need to use the `get()` method.
|
// from the GValue, we need to use the `get()` method.
|
||||||
|
|
@ -916,6 +949,36 @@ impl LpWindow {
|
||||||
&& (!self.is_headerbar_flat() || !self.imp().headerbar_events.contains_pointer())
|
&& (!self.is_headerbar_flat() || !self.imp().headerbar_events.contains_pointer())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Displays visual feedback for users trying to drag and drop
|
||||||
|
fn toggle_drop_area_highlight(&self, display: bool) {
|
||||||
|
let overlay = &self.imp().drop_area_overlay;
|
||||||
|
let widget = self.imp().drop_area_highlight_widget.get()
|
||||||
|
.expect("`drop_area_highlight_widget` needs to be defined before being toggled");
|
||||||
|
|
||||||
|
// Create fade in animation. Will be reversed to make a fade-out.
|
||||||
|
let animation = adw::TimedAnimation::new(
|
||||||
|
widget, 0.0, 1.0, 250, adw::PropertyAnimationTarget::new(widget, "opacity")
|
||||||
|
);
|
||||||
|
|
||||||
|
if display && widget.parent().is_none() {
|
||||||
|
// Overlay widget
|
||||||
|
overlay.add_overlay(widget);
|
||||||
|
// Hide controls to avoid messy superpositions
|
||||||
|
self.hide_controls()
|
||||||
|
} else if !display && widget.parent().is_some() {
|
||||||
|
// Reverse the fade-in animation
|
||||||
|
animation.set_reverse(true);
|
||||||
|
// Remove overlay after animation end
|
||||||
|
animation.connect_done(|animation| {
|
||||||
|
let widget = animation.widget();
|
||||||
|
let overlay = widget.parent().and_downcast::<gtk::Overlay>().unwrap();
|
||||||
|
overlay.remove_overlay(&widget);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
animation.play();
|
||||||
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn on_fullscreened(&self) {
|
fn on_fullscreened(&self) {
|
||||||
if !self.is_fullscreened() {
|
if !self.is_fullscreened() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue