/* Copyright (C) 2020 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

#include <gdkmm/contentformats.h>
#include <gdkmm/drop.h>
#include <gdkmm/enums.h>
#include <gtkmm/eventcontroller.h>

_DEFS(gtkmm,gtk)
_PINCLUDE(gtkmm/private/eventcontroller_p.h)

namespace Gtk
{
/** Event controller to receive DND drops.
 *
 * %Gtk::DropTargetAsync is an auxiliary object that can be used to receive
 * Drag-and-Drop operations.  
 * It is the more complete but also more complex method of handling drop
 * operations compared to Gtk::DropTarget and you should only use it if
 * Gtk::DropTarget doesn't provide all the features you need.
 *
 * To use a %Gtk::DropTargetAsync to receive drops on a widget, you create
 * a %Gtk::DropTargetAsync object, configure which data formats and actions
 * you support, connect to its signals, and then attach
 * it to the widget with Gtk::Widget::add_controller().
 *
 * During a drag operation, the first signal that a %Gtk::DropTargetAsync
 * emits is signal_accept(), which is meant to determine
 * whether the target is a possible drop site for the ongoing drop.
 * The default handler for the accept signal accepts the drop
 * if it finds a compatible data format and an action that is supported
 * on both sides.
 *
 * If it is, and the widget becomes a target, you will receive a
 * signal_drag_enter(), followed by signal_drag_motion() as the pointer moves,
 * optionally a signal_drop() when a drop happens, and finally a
 * signal_drag_leave() when the pointer moves off the widget.
 *
 * The ::drag-enter and ::drag-motion handler return a Gdk::DragAction
 * to update the status of the ongoing operation. The ::drop handler
 * should decide if it ultimately accepts the drop and if it does, it
 * should initiate the data transfer and finish the operation by calling
 * Gdk::Drop::finish().
 *
 * Between the ::drag-enter and ::drag-leave signals the widget is a
 * current drop target, and will receive the Gtk::StateFlags::DROP_ACTIVE
 * state, which can be used by themes to style the widget as a drop target.
 *
 * @newin{3,98}
 *
 * @ingroup Gestures
 */
class GTKMM_API DropTargetAsync : public EventController
{
  _CLASS_GOBJECT(DropTargetAsync, GtkDropTargetAsync, GTK_DROP_TARGET_ASYNC, EventController, GtkEventController, , , GTKMM_API)

public:
  // Gdk::ContentFormats is an immutable object. It can be declared const
  // in input parameters. No one can change it.
  static Glib::RefPtr<DropTargetAsync> create(const Glib::RefPtr<const Gdk::ContentFormats>& formats,
    Gdk::DragAction actions = static_cast<Gdk::DragAction>(0));
  static Glib::RefPtr<DropTargetAsync> create(Gdk::DragAction actions = static_cast<Gdk::DragAction>(0));
  _IGNORE(gtk_drop_target_async_new)

  _WRAP_METHOD(void set_formats(const Glib::RefPtr<const Gdk::ContentFormats>& formats), gtk_drop_target_async_set_formats)
  _WRAP_METHOD(Glib::RefPtr<Gdk::ContentFormats> get_formats(), gtk_drop_target_async_get_formats, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Gdk::ContentFormats> get_formats() const, gtk_drop_target_async_get_formats, refreturn, constversion)

  _WRAP_METHOD(void set_actions(Gdk::DragAction actions), gtk_drop_target_async_set_actions)
  _WRAP_METHOD(Gdk::DragAction get_actions() const, gtk_drop_target_async_get_actions)

  _WRAP_METHOD(void reject_drop(const Glib::RefPtr<Gdk::Drop>& drop), gtk_drop_target_async_reject_drop)

  _WRAP_PROPERTY("actions", Gdk::DragAction)
  _WRAP_PROPERTY("formats", Glib::RefPtr<Gdk::ContentFormats>)

#m4 _CONVERSION(`GdkDrop*',`const Glib::RefPtr<Gdk::Drop>&',`Glib::wrap($3, true)')
  // no_default_handler because GtkDropTargetAsyncClass is private.
  // All C signals except "drag-leave" use g_signal_accumulator_first_wins().
  /** Only one signal handler is called. If you connect a handler, it must be
   * called before (instead of) the default handler, otherwise it won't be called.
   * Set the @a after parameter in connect() to <tt>false</tt>.
   */
  _WRAP_SIGNAL(bool accept(const Glib::RefPtr<Gdk::Drop>& drop), "accept", no_default_handler)
  /** Only one signal handler is called. If you connect a handler, it must be
   * called before (instead of) the default handler, otherwise it won't be called.
   * Set the @a after parameter in connect() to <tt>false</tt>.
   */
  _WRAP_SIGNAL(Gdk::DragAction drag_enter(const Glib::RefPtr<Gdk::Drop>& drop, double x, double y), "drag-enter", no_default_handler)
  /** Only one signal handler is called. If you connect a handler, it must be
   * called before (instead of) the default handler, otherwise it won't be called.
   * Set the @a after parameter in connect() to <tt>false</tt>.
   */
  _WRAP_SIGNAL(Gdk::DragAction drag_motion(const Glib::RefPtr<Gdk::Drop>& drop, double x, double y), "drag-motion", no_default_handler)
  _WRAP_SIGNAL(void drag_leave(const Glib::RefPtr<Gdk::Drop>& drop), "drag-leave", no_default_handler)
  /** Only one signal handler is called. If you connect a handler, it must be
   * called before (instead of) the default handler, otherwise it won't be called.
   * Set the @a after parameter in connect() to <tt>false</tt>.
   */
  _WRAP_SIGNAL(bool drop(const Glib::RefPtr<Gdk::Drop>& drop, double x, double y), "drop", no_default_handler)
};

} // namespace Gtk
