// Fragments - drag_overlay.rs
// Copyright (C) 2023  Felix Häcker <haeckerfelix@gnome.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

// Inspired by [Loupe](https://gitlab.gnome.org/GNOME/loupe) and
// [Amberol](https://gitlab.gnome.org/World/amberol)

use adw::subclass::prelude::*;
use glib::Properties;
use gtk::glib;
use gtk::prelude::*;

mod imp {
    use super::*;

    #[derive(Debug, Default, Properties)]
    #[properties(wrapper_type = super::FrgDragOverlay)]
    pub struct FrgDragOverlay {
        #[property(set = Self::set_child)]
        pub child: Option<gtk::Widget>,
        #[property(get)]
        drop_target: gtk::DropTarget,
        overlay: gtk::Overlay,
        revealer: gtk::Revealer,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for FrgDragOverlay {
        const NAME: &'static str = "FrgDragOverlay";
        type Type = super::FrgDragOverlay;
        type ParentType = adw::Bin;
    }

    #[glib::derived_properties]
    impl ObjectImpl for FrgDragOverlay {
        fn constructed(&self) {
            self.parent_constructed();

            self.overlay.set_parent(&*self.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.drop_target.set_actions(gtk::gdk::DragAction::COPY);
            self.drop_target.connect_current_drop_notify(
                glib::clone!(@weak self.revealer as revealer => move |target| {
                    let reveal = target.current_drop().is_some();
                    revealer.set_reveal_child(reveal);
                }),
            );

            let bin = adw::Bin::new();
            bin.set_can_target(false);
            bin.add_css_class("dragging-area-highlight");

            self.revealer.set_child(Some(&bin));
        }

        fn dispose(&self) {
            self.overlay.unparent();
        }
    }

    impl WidgetImpl for FrgDragOverlay {}

    impl BinImpl for FrgDragOverlay {}

    impl FrgDragOverlay {
        pub fn set_child(&self, child: Option<gtk::Widget>) {
            self.overlay.set_child(child.as_ref());
        }
    }
}

glib::wrapper! {
    pub struct FrgDragOverlay(
        ObjectSubclass<imp::FrgDragOverlay>)
        @extends gtk::Widget, adw::Bin;
}
