[gimp/gimp-2-10] app: "You can drop dockable dialogs here" no more!



commit 4730bc2a4d4277dfaca8e96a7a69df82650ff5f6
Author: Ell <ell_se yahoo com>
Date:   Sun Feb 2 23:04:26 2020 +0200

    app: "You can drop dockable dialogs here" no more!
    
    This commit removes the empty-dock-pane message, and instead
    highlights all empty dockable drop-target areas once a drag
    operation begins.
    
    Add new gimp_dockbook_{add,remove}_callback() global functions,
    which can be used to register a callback function to be called when
    a dockable drag operation begins and ends.
    
    Register such a callback in GimpPanedBox, and use it to highlight
    all drop areas the widget handles.  Furthermore, when the widget is
    contained in a GtkPaned, make sure that it has a minimal size for
    the duration of the drag operation, so that the drop area is
    visible even if the widget is normally hidden.

 app/widgets/gimpdockbook.c |  88 +++++++++
 app/widgets/gimpdockbook.h |  58 +++---
 app/widgets/gimppanedbox.c | 469 +++++++++++++++++++++++++++++++--------------
 3 files changed, 450 insertions(+), 165 deletions(-)
---
diff --git a/app/widgets/gimpdockbook.c b/app/widgets/gimpdockbook.c
index 2c7485b8c7..d4d5208533 100644
--- a/app/widgets/gimpdockbook.c
+++ b/app/widgets/gimpdockbook.c
@@ -82,6 +82,13 @@ static const GimpTabStyle gimp_tab_style_candidates[] =
   GIMP_TAB_STYLE_PREVIEW
 };
 
+
+typedef struct
+{
+  GimpDockbookDragCallback callback;
+  gpointer                 data;
+} GimpDockbookDragCallbackData;
+
 struct _GimpDockbookPrivate
 {
   GimpDock       *dock;
@@ -144,6 +151,9 @@ static void         gimp_dockbook_tab_drag_source_setup       (GtkWidget      *w
 static void         gimp_dockbook_tab_drag_begin              (GtkWidget      *widget,
                                                                GdkDragContext *context,
                                                                GimpDockable   *dockable);
+static void         gimp_dockbook_tab_drag_end                (GtkWidget      *widget,
+                                                               GdkDragContext *context,
+                                                               GimpDockable   *dockable);
 static gboolean     gimp_dockbook_tab_drag_failed             (GtkWidget      *widget,
                                                                GdkDragContext *context,
                                                                GtkDragResult   result,
@@ -196,6 +206,8 @@ static guint dockbook_signals[LAST_SIGNAL] = { 0 };
 
 static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_DIALOG };
 
+static GList *drag_callbacks = NULL;
+
 
 static void
 gimp_dockbook_class_init (GimpDockbookClass *klass)
@@ -1173,6 +1185,9 @@ gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
   g_signal_connect_object (tab_widget, "drag-begin",
                            G_CALLBACK (gimp_dockbook_tab_drag_begin),
                            dockable, 0);
+  g_signal_connect_object (tab_widget, "drag-end",
+                           G_CALLBACK (gimp_dockbook_tab_drag_end),
+                           dockable, 0);
   g_signal_connect_object (tab_widget, "drag-failed",
                            G_CALLBACK (gimp_dockbook_tab_drag_failed),
                            dockable, 0);
@@ -1180,6 +1195,9 @@ gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
   g_signal_connect_object (dockable, "drag-begin",
                            G_CALLBACK (gimp_dockbook_tab_drag_begin),
                            dockable, 0);
+  g_signal_connect_object (dockable, "drag-end",
+                           G_CALLBACK (gimp_dockbook_tab_drag_end),
+                           dockable, 0);
   g_signal_connect_object (dockable, "drag-failed",
                            G_CALLBACK (gimp_dockbook_tab_drag_failed),
                            dockable, 0);
@@ -1296,6 +1314,45 @@ gimp_dockbook_drag_source_to_dockable (GtkWidget *drag_source)
   return dockable;
 }
 
+void
+gimp_dockbook_add_drag_callback (GimpDockbookDragCallback callback,
+                                 gpointer                 data)
+{
+  GimpDockbookDragCallbackData *callback_data;
+
+  callback_data = g_slice_new (GimpDockbookDragCallbackData);
+
+  callback_data->callback = callback;
+  callback_data->data     = data;
+
+  drag_callbacks = g_list_prepend (drag_callbacks, callback_data);
+}
+
+void
+gimp_dockbook_remove_drag_callback (GimpDockbookDragCallback callback,
+                                    gpointer                 data)
+{
+  GList *iter;
+
+  iter = drag_callbacks;
+
+  while (iter)
+    {
+      GimpDockbookDragCallbackData *callback_data = iter->data;
+      GList                        *next          = g_list_next (iter);
+
+      if (callback_data->callback == callback &&
+          callback_data->data     == data)
+        {
+          g_slice_free (GimpDockbookDragCallbackData, callback_data);
+
+          drag_callbacks = g_list_delete_link (drag_callbacks, iter);
+        }
+
+      iter = next;
+    }
+}
+
 /*  tab DND source side  */
 
 static void
@@ -1364,6 +1421,7 @@ gimp_dockbook_tab_drag_begin (GtkWidget      *widget,
   GtkAllocation   allocation;
   GtkWidget      *window;
   GtkWidget      *view;
+  GList          *iter;
   GtkRequisition  requisition;
   gint            drag_x;
   gint            drag_y;
@@ -1391,6 +1449,36 @@ gimp_dockbook_tab_drag_begin (GtkWidget      *widget,
 
   gimp_dockable_get_drag_pos (dockable, &drag_x, &drag_y);
   gtk_drag_set_icon_widget (context, window, drag_x, drag_y);
+
+  iter = drag_callbacks;
+
+  while (iter)
+    {
+      GimpDockbookDragCallbackData *callback_data = iter->data;
+
+      iter = g_list_next (iter);
+
+      callback_data->callback (context, TRUE, callback_data->data);
+    }
+}
+
+static void
+gimp_dockbook_tab_drag_end (GtkWidget      *widget,
+                            GdkDragContext *context,
+                            GimpDockable   *dockable)
+{
+  GList *iter;
+
+  iter = drag_callbacks;
+
+  while (iter)
+    {
+      GimpDockbookDragCallbackData *callback_data = iter->data;
+
+      iter = g_list_next (iter);
+
+      callback_data->callback (context, FALSE, callback_data->data);
+    }
 }
 
 static gboolean
diff --git a/app/widgets/gimpdockbook.h b/app/widgets/gimpdockbook.h
index b9e069f4a1..ab8693e84f 100644
--- a/app/widgets/gimpdockbook.h
+++ b/app/widgets/gimpdockbook.h
@@ -30,6 +30,11 @@
 #define GIMP_DOCKBOOK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DOCKBOOK, 
GimpDockbookClass))
 
 
+typedef void (* GimpDockbookDragCallback) (GdkDragContext *context,
+                                           gboolean        begin,
+                                           gpointer        data);
+
+
 typedef struct _GimpDockbookClass    GimpDockbookClass;
 typedef struct _GimpDockbookPrivate  GimpDockbookPrivate;
 
@@ -59,30 +64,35 @@ struct _GimpDockbookClass
 };
 
 
-GType           gimp_dockbook_get_type                  (void) G_GNUC_CONST;
-GtkWidget     * gimp_dockbook_new                       (GimpMenuFactory *menu_factory);
-GimpDock      * gimp_dockbook_get_dock                  (GimpDockbook    *dockbook);
-void            gimp_dockbook_set_dock                  (GimpDockbook    *dockbook,
-                                                         GimpDock        *dock);
-GimpUIManager * gimp_dockbook_get_ui_manager            (GimpDockbook    *dockbook);
-void            gimp_dockbook_add                       (GimpDockbook    *dockbook,
-                                                         GimpDockable    *dockable,
-                                                         gint             position);
-GtkWidget     * gimp_dockbook_add_from_dialog_factory   (GimpDockbook    *dockbook,
-                                                         const gchar     *identifiers,
-                                                         gint             position);
-void            gimp_dockbook_remove                    (GimpDockbook    *dockbook,
-                                                         GimpDockable    *dockable);
-void            gimp_dockbook_update_with_context       (GimpDockbook    *dockbook,
-                                                         GimpContext     *context);
-GtkWidget    *  gimp_dockbook_create_tab_widget         (GimpDockbook    *dockbook,
-                                                         GimpDockable    *dockable);
-void            gimp_dockbook_update_auto_tab_style     (GimpDockbook    *dockbook);
-gboolean        gimp_dockbook_drop_dockable             (GimpDockbook    *dockbook,
-                                                         GtkWidget       *drag_source);
-void            gimp_dockbook_set_drag_handler          (GimpDockbook    *dockbook,
-                                                         GimpPanedBox    *drag_handler);
-GimpDockable *  gimp_dockbook_drag_source_to_dockable   (GtkWidget       *drag_source);
+GType           gimp_dockbook_get_type                (void) G_GNUC_CONST;
+GtkWidget     * gimp_dockbook_new                     (GimpMenuFactory          *menu_factory);
+GimpDock      * gimp_dockbook_get_dock                (GimpDockbook             *dockbook);
+void            gimp_dockbook_set_dock                (GimpDockbook             *dockbook,
+                                                       GimpDock                 *dock);
+GimpUIManager * gimp_dockbook_get_ui_manager          (GimpDockbook             *dockbook);
+void            gimp_dockbook_add                     (GimpDockbook             *dockbook,
+                                                       GimpDockable             *dockable,
+                                                       gint                      position);
+GtkWidget     * gimp_dockbook_add_from_dialog_factory (GimpDockbook             *dockbook,
+                                                       const gchar              *identifiers,
+                                                       gint                      position);
+void            gimp_dockbook_remove                  (GimpDockbook             *dockbook,
+                                                       GimpDockable             *dockable);
+void            gimp_dockbook_update_with_context     (GimpDockbook             *dockbook,
+                                                       GimpContext              *context);
+GtkWidget    *  gimp_dockbook_create_tab_widget       (GimpDockbook             *dockbook,
+                                                       GimpDockable             *dockable);
+void            gimp_dockbook_update_auto_tab_style   (GimpDockbook             *dockbook);
+gboolean        gimp_dockbook_drop_dockable           (GimpDockbook             *dockbook,
+                                                       GtkWidget                *drag_source);
+void            gimp_dockbook_set_drag_handler        (GimpDockbook             *dockbook,
+                                                       GimpPanedBox             *drag_handler);
+GimpDockable *  gimp_dockbook_drag_source_to_dockable (GtkWidget                *drag_source);
+
+void            gimp_dockbook_add_drag_callback       (GimpDockbookDragCallback  callback,
+                                                       gpointer                  data);
+void            gimp_dockbook_remove_drag_callback    (GimpDockbookDragCallback  callback,
+                                                       gpointer                  data);
 
 
 #endif /* __GIMP_DOCKBOOK_H__ */
diff --git a/app/widgets/gimppanedbox.c b/app/widgets/gimppanedbox.c
index 731b58c922..6dc447a78b 100644
--- a/app/widgets/gimppanedbox.c
+++ b/app/widgets/gimppanedbox.c
@@ -22,8 +22,12 @@
 #include "config.h"
 
 #include <gegl.h>
+#ifdef GDK_DISABLE_DEPRECATED
+#undef GDK_DISABLE_DEPRECATED
+#endif
 #include <gtk/gtk.h>
 
+#include "libgimpcolor/gimpcolor.h"
 #include "libgimpwidgets/gimpwidgets.h"
 
 #include "widgets-types.h"
@@ -51,12 +55,14 @@
  * order to be inserted and get space on their own (rather than
  * inserted among others and sharing space)
  */
-#define DROP_AREA_SIZE            6
+#define DROP_AREA_SIZE                  6
 
-#define INSERT_INDEX_UNUSED       G_MININT
+#define DROP_HIGHLIGHT_MIN_SIZE         32
+#define DROP_HIGHLIGHT_COLOR            "#215d9c"
+#define DROP_HIGHLIGHT_OPACITY_ACTIVE   1.0
+#define DROP_HIGHLIGHT_OPACITY_INACTIVE 0.5
 
-#define INSTRUCTIONS_TEXT_PADDING 6
-#define INSTRUCTIONS_TEXT         _("You can drop dockable dialogs here")
+#define INSERT_INDEX_UNUSED             G_MININT
 
 
 struct _GimpPanedBoxPrivate
@@ -64,11 +70,11 @@ struct _GimpPanedBoxPrivate
   /* Widgets that are separated by panes */
   GList                  *widgets;
 
-  /* Displays INSTRUCTIONS_TEXT when there are no dockables */
-  GtkWidget              *instructions;
-
-  /* Window used for drag-and-drop output */
-  GdkWindow              *dnd_window;
+  /* Windows used for drag-and-drop output */
+  GdkWindow              *dnd_windows[3];
+  GdkDragContext         *dnd_context;
+  gint                    dnd_paned_position;
+  gint                    dnd_idle_id;
 
   /* The insert index to use on drop */
   gint                    insert_index;
@@ -103,6 +109,10 @@ static void      gimp_paned_box_set_widget_drag_handler (GtkWidget      *widget,
                                                          GimpPanedBox   *handler);
 static gint      gimp_paned_box_get_drop_area_size      (GimpPanedBox   *paned_box);
 
+static void      gimp_paned_box_drag_callback           (GdkDragContext *context,
+                                                         gboolean        begin,
+                                                         GimpPanedBox   *paned_box);
+
 
 G_DEFINE_TYPE_WITH_PRIVATE (GimpPanedBox, gimp_paned_box, GTK_TYPE_BOX)
 
@@ -131,32 +141,15 @@ gimp_paned_box_init (GimpPanedBox *paned_box)
 {
   paned_box->p = gimp_paned_box_get_instance_private (paned_box);
 
-  /* Instructions label
-   *
-   * Size a small size request so it don't mess up dock window layouts
-   * during startup; in particular, set its height request to 0 so it
-   * doesn't contribute to the minimum height of the toolbox.
-   */
-  paned_box->p->instructions = gtk_label_new (INSTRUCTIONS_TEXT);
-  gtk_misc_set_padding (GTK_MISC (paned_box->p->instructions),
-                        INSTRUCTIONS_TEXT_PADDING, INSTRUCTIONS_TEXT_PADDING);
-  gtk_label_set_line_wrap (GTK_LABEL (paned_box->p->instructions), TRUE);
-  gtk_label_set_justify (GTK_LABEL (paned_box->p->instructions),
-                         GTK_JUSTIFY_CENTER);
-  gtk_widget_set_size_request (paned_box->p->instructions, 1, DROP_AREA_SIZE);
-  gimp_label_set_attributes (GTK_LABEL (paned_box->p->instructions),
-                             PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-                             -1);
-  gtk_box_pack_start (GTK_BOX (paned_box), paned_box->p->instructions,
-                      TRUE, TRUE, 0);
-  gtk_widget_show (paned_box->p->instructions);
-
-
   /* Setup DND */
   gtk_drag_dest_set (GTK_WIDGET (paned_box),
                      0,
                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
                      GDK_ACTION_MOVE);
+
+  gimp_dockbook_add_drag_callback (
+    (GimpDockbookDragCallback) gimp_paned_box_drag_callback,
+    paned_box);
 }
 
 static void
@@ -164,6 +157,13 @@ gimp_paned_box_dispose (GObject *object)
 {
   GimpPanedBox *paned_box = GIMP_PANED_BOX (object);
 
+  if (paned_box->p->dnd_idle_id)
+    {
+      g_source_remove (paned_box->p->dnd_idle_id);
+
+      paned_box->p->dnd_idle_id = 0;
+    }
+
   while (paned_box->p->widgets)
     {
       GtkWidget *widget = paned_box->p->widgets->data;
@@ -174,6 +174,10 @@ gimp_paned_box_dispose (GObject *object)
       g_object_unref (widget);
     }
 
+  gimp_dockbook_remove_drag_callback (
+    (GimpDockbookDragCallback) gimp_paned_box_drag_callback,
+    paned_box);
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
@@ -191,12 +195,19 @@ static void
 gimp_paned_box_unrealize (GtkWidget *widget)
 {
   GimpPanedBox *paned_box = GIMP_PANED_BOX (widget);
+  gint          i;
 
-  if (paned_box->p->dnd_window)
+  for (i = 0; i < G_N_ELEMENTS (paned_box->p->dnd_windows); i++)
     {
-      gdk_window_set_user_data (paned_box->p->dnd_window, NULL);
-      gdk_window_destroy (paned_box->p->dnd_window);
-      paned_box->p->dnd_window = NULL;
+      GdkWindow *window = paned_box->p->dnd_windows[i];
+
+      if (window)
+        {
+          gdk_window_set_user_data (window, NULL);
+          gdk_window_destroy (window);
+
+          paned_box->p->dnd_windows[i] = NULL;
+        }
     }
 
   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
@@ -261,24 +272,127 @@ gimp_paned_box_get_drop_area_size (GimpPanedBox *paned_box)
   return drop_area_size;
 }
 
+static gboolean
+gimp_paned_box_get_handle_drag (GimpPanedBox   *paned_box,
+                                GdkDragContext *context,
+                                gint            x,
+                                gint            y,
+                                guint           time,
+                                gint           *insert_index,
+                                GeglRectangle  *area)
+{
+  gint           index          = INSERT_INDEX_UNUSED;
+  GtkAllocation  allocation     = { 0, };
+  gint           area_x         = 0;
+  gint           area_y         = 0;
+  gint           area_w         = 0;
+  gint           area_h         = 0;
+  GtkOrientation orientation    = 0;
+  gint           drop_area_size = gimp_paned_box_get_drop_area_size (paned_box);
+
+  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
+                                       GTK_WIDGET (paned_box),
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      return FALSE;
+    }
+
+  gtk_widget_get_allocation (GTK_WIDGET (paned_box), &allocation);
+
+  /* See if we're at the edge of the dock If there are no dockables,
+   * the entire paned box is a drop area
+   */
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      area_y = 0;
+      area_h = allocation.height;
+
+      /* If there are no widgets, the drop area is as big as the paned
+       * box
+       */
+      if (! paned_box->p->widgets)
+        area_w = allocation.width;
+      else
+        area_w = drop_area_size;
+
+      if (x < drop_area_size)
+        {
+          index = 0;
+          area_x = 0;
+        }
+      if (x > allocation.width - drop_area_size)
+        {
+          index = -1;
+          area_x = allocation.width - drop_area_size;
+        }
+    }
+  else /* if (orientation = GTK_ORIENTATION_VERTICAL) */
+    {
+      area_x = 0;
+      area_w = allocation.width;
+
+      /* If there are no widgets, the drop area is as big as the paned
+       * box
+       */
+      if (! paned_box->p->widgets)
+        area_h = allocation.height;
+      else
+        area_h = drop_area_size;
+
+      if (y < drop_area_size)
+        {
+          index = 0;
+          area_y = 0;
+        }
+      if (y > allocation.height - drop_area_size)
+        {
+          index = -1;
+          area_y = allocation.height - drop_area_size;
+        }
+    }
+
+  if (area)
+    {
+      area->x      = allocation.x + area_x;
+      area->y      = allocation.y + area_y;
+      area->width  = area_w;
+      area->height = area_h;
+    }
+
+  if (insert_index)
+    *insert_index = index;
+
+  return index != INSERT_INDEX_UNUSED;
+}
+
 static void
 gimp_paned_box_position_drop_indicator (GimpPanedBox *paned_box,
+                                        gint          index,
                                         gint          x,
                                         gint          y,
                                         gint          width,
-                                        gint          height)
+                                        gint          height,
+                                        gdouble       opacity)
 {
-  GtkWidget *widget = GTK_WIDGET (paned_box);
+  GtkWidget    *widget = GTK_WIDGET (paned_box);
+  GdkWindow    *window = paned_box->p->dnd_windows[index];
+  GtkStyle     *style  = gtk_widget_get_style (widget);
+  GtkStateType  state  = gtk_widget_get_state (widget);
+  GimpRGB       bg;
+  GimpRGB       fg;
+  GdkColor      color;
 
   if (! gtk_widget_is_drawable (widget))
     return;
 
   /* Create or move the GdkWindow in place */
-  if (! paned_box->p->dnd_window)
+  if (! window)
     {
-      GtkStyle      *style = gtk_widget_get_style (widget);
-      GtkAllocation  allocation;
-      GdkWindowAttr  attributes;
+      GtkAllocation allocation;
+      GdkWindowAttr attributes;
 
       gtk_widget_get_allocation (widget, &allocation);
 
@@ -290,31 +404,50 @@ gimp_paned_box_position_drop_indicator (GimpPanedBox *paned_box,
       attributes.wclass      = GDK_INPUT_OUTPUT;
       attributes.event_mask  = gtk_widget_get_events (widget);
 
-      paned_box->p->dnd_window = gdk_window_new (gtk_widget_get_window (widget),
-                                                 &attributes,
-                                                 GDK_WA_X | GDK_WA_Y);
-      gdk_window_set_user_data (paned_box->p->dnd_window, widget);
+      window = gdk_window_new (gtk_widget_get_window (widget),
+                               &attributes,
+                               GDK_WA_X | GDK_WA_Y);
+      gdk_window_set_user_data (window, widget);
 
-      gdk_window_set_background (paned_box->p->dnd_window,
-                                 &style->bg[GTK_STATE_SELECTED]);
+      paned_box->p->dnd_windows[index] = window;
     }
   else
     {
-      gdk_window_move_resize (paned_box->p->dnd_window,
+      gdk_window_move_resize (window,
                               x, y,
                               width, height);
     }
 
-  gdk_window_show (paned_box->p->dnd_window);
+  gimp_rgb_set_uchar (&bg,
+                      style->bg[state].red   >> 8,
+                      style->bg[state].green >> 8,
+                      style->bg[state].blue  >> 8);
+  bg.a = 1.0;
+
+  gimp_rgb_parse_hex (&fg, DROP_HIGHLIGHT_COLOR, -1);
+  fg.a = opacity;
+
+  gimp_rgb_composite (&bg, &fg, GIMP_RGB_COMPOSITE_NORMAL);
+
+  color.red   = bg.r * 0xffff;
+  color.green = bg.g * 0xffff;
+  color.blue  = bg.b * 0xffff;
+
+  gdk_rgb_find_color (gtk_widget_get_colormap (widget), &color);
+
+  gdk_window_set_background (window, &color);
+
+  gdk_window_show (window);
 }
 
 static void
-gimp_paned_box_hide_drop_indicator (GimpPanedBox *paned_box)
+gimp_paned_box_hide_drop_indicator (GimpPanedBox *paned_box,
+                                    gint          index)
 {
-  if (! paned_box->p->dnd_window)
+  if (! paned_box->p->dnd_windows[index])
     return;
 
-  gdk_window_hide (paned_box->p->dnd_window);
+  gdk_window_hide (paned_box->p->dnd_windows[index]);
 }
 
 static void
@@ -322,7 +455,9 @@ gimp_paned_box_drag_leave (GtkWidget      *widget,
                            GdkDragContext *context,
                            guint           time)
 {
-  gimp_paned_box_hide_drop_indicator (GIMP_PANED_BOX (widget));
+  GimpPanedBox *paned_box = GIMP_PANED_BOX (widget);
+
+  gimp_paned_box_hide_drop_indicator (paned_box, 0);
   gimp_highlight_widget (widget, FALSE);
 }
 
@@ -333,99 +468,30 @@ gimp_paned_box_drag_motion (GtkWidget      *widget,
                             gint            y,
                             guint           time)
 {
-  GimpPanedBox  *paned_box      = GIMP_PANED_BOX (widget);
-  gint           insert_index   = INSERT_INDEX_UNUSED;
-  gint           dnd_window_x   = 0;
-  gint           dnd_window_y   = 0;
-  gint           dnd_window_w   = 0;
-  gint           dnd_window_h   = 0;
-  GtkAllocation  allocation     = { 0, };
-  GtkOrientation orientation    = 0;
-  gboolean       handle         = FALSE;
-  gint           drop_area_size = gimp_paned_box_get_drop_area_size (paned_box);
-
-  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
-                                       widget,
-                                       context,
-                                       x, y,
-                                       time))
-    {
-      gdk_drag_status (context, 0, time);
-      gimp_highlight_widget (widget, FALSE);
-
-      return FALSE;
-    }
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  /* See if we're at the edge of the dock If there are no dockables,
-   * the entire paned box is a drop area
-   */
-  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      dnd_window_y = 0;
-      dnd_window_h = allocation.height;
-
-      /* If there are no widgets, the drop area is as big as the paned
-       * box
-       */
-      if (! paned_box->p->widgets)
-        dnd_window_w = allocation.width;
-      else
-        dnd_window_w = drop_area_size;
-
-      if (x < drop_area_size)
-        {
-          insert_index = 0;
-          dnd_window_x = 0;
-        }
-      if (x > allocation.width - drop_area_size)
-        {
-          insert_index = -1;
-          dnd_window_x = allocation.width - drop_area_size;
-        }
-    }
-  else /* if (orientation = GTK_ORIENTATION_VERTICAL) */
-    {
-      dnd_window_x = 0;
-      dnd_window_w = allocation.width;
+  GimpPanedBox  *paned_box = GIMP_PANED_BOX (widget);
+  gint           insert_index;
+  GeglRectangle  area;
+  gboolean       handle;
 
-      /* If there are no widgets, the drop area is as big as the paned
-       * box
-       */
-      if (! paned_box->p->widgets)
-        dnd_window_h = allocation.height;
-      else
-        dnd_window_h = drop_area_size;
-
-      if (y < drop_area_size)
-        {
-          insert_index = 0;
-          dnd_window_y = 0;
-        }
-      if (y > allocation.height - drop_area_size)
-        {
-          insert_index = -1;
-          dnd_window_y = allocation.height - drop_area_size;
-        }
-    }
+  handle = gimp_paned_box_get_handle_drag (paned_box, context, x, y, time,
+                                           &insert_index, &area);
 
   /* If we are at the edge, show a GdkWindow to communicate that a
    * drop will create a new dock column
    */
-  handle = (insert_index != INSERT_INDEX_UNUSED);
   if (handle)
     {
       gimp_paned_box_position_drop_indicator (paned_box,
-                                              allocation.x + dnd_window_x,
-                                              allocation.y + dnd_window_y,
-                                              dnd_window_w,
-                                              dnd_window_h);
+                                              0,
+                                              area.x,
+                                              area.y,
+                                              area.width,
+                                              area.height,
+                                              DROP_HIGHLIGHT_OPACITY_ACTIVE);
     }
   else
     {
-      gimp_paned_box_hide_drop_indicator (paned_box);
+      gimp_paned_box_hide_drop_indicator (paned_box, 0);
     }
 
   /* Save the insert index for drag-drop */
@@ -435,7 +501,7 @@ gimp_paned_box_drag_motion (GtkWidget      *widget,
   gimp_highlight_widget (widget, handle);
 
   /* Return TRUE so drag_leave() is called */
-  return TRUE;
+  return handle;
 }
 
 static gboolean
@@ -472,6 +538,133 @@ gimp_paned_box_drag_drop (GtkWidget      *widget,
   return TRUE;
 }
 
+static gboolean
+gimp_paned_box_drag_callback_idle (GimpPanedBox *paned_box)
+{
+  GtkAllocation  allocation;
+  GtkOrientation orientation;
+  GeglRectangle  area;
+
+  paned_box->p->dnd_idle_id = 0;
+
+  gtk_widget_get_allocation (GTK_WIDGET (paned_box), &allocation);
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
+
+  #define ADD_AREA(index, left, top)               \
+    if (gimp_paned_box_get_handle_drag (           \
+        paned_box,                                 \
+        paned_box->p->dnd_context,                 \
+        (left), (top),                             \
+        0,                                         \
+        NULL, &area))                              \
+      {                                            \
+        gimp_paned_box_position_drop_indicator (   \
+          paned_box,                               \
+          index,                                   \
+          area.x, area.y, area.width, area.height, \
+          DROP_HIGHLIGHT_OPACITY_INACTIVE);        \
+      }
+
+  if (! paned_box->p->widgets)
+    {
+      ADD_AREA (1, allocation.width / 2, allocation.height / 2)
+    }
+  else if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      ADD_AREA (1, 0,                    allocation.height / 2)
+      ADD_AREA (2, allocation.width - 1, allocation.height / 2)
+    }
+  else
+    {
+      ADD_AREA (1, allocation.width / 2, 0)
+      ADD_AREA (2, allocation.width / 2, allocation.height - 1)
+    }
+
+  #undef ADD_AREA
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+gimp_paned_box_drag_callback (GdkDragContext *context,
+                              gboolean        begin,
+                              GimpPanedBox   *paned_box)
+{
+  GtkWidget *paned;
+  gint       position;
+
+  if (! gtk_widget_get_sensitive (GTK_WIDGET (paned_box)))
+    return;
+
+  paned = gtk_widget_get_ancestor (GTK_WIDGET (paned_box),
+                                   GTK_TYPE_PANED);
+
+  if (begin)
+    {
+      paned_box->p->dnd_context = context;
+
+      if (paned)
+        {
+          GtkAllocation allocation;
+
+          gtk_widget_get_allocation (paned, &allocation);
+
+          position = gtk_paned_get_position (GTK_PANED (paned));
+
+          paned_box->p->dnd_paned_position = position;
+
+          if (position < 0)
+            {
+              position = 0;
+            }
+          else if (gtk_widget_is_ancestor (
+                     GTK_WIDGET (paned_box),
+                     gtk_paned_get_child2 (GTK_PANED (paned))))
+            {
+              position = allocation.width - position;
+            }
+
+          if (position < DROP_HIGHLIGHT_MIN_SIZE)
+            {
+              position = DROP_HIGHLIGHT_MIN_SIZE;
+
+              if (gtk_widget_is_ancestor (
+                    GTK_WIDGET (paned_box),
+                    gtk_paned_get_child2 (GTK_PANED (paned))))
+                {
+                  position = allocation.width - position;
+                }
+
+              gtk_paned_set_position (GTK_PANED (paned), position);
+            }
+        }
+
+      paned_box->p->dnd_idle_id = g_idle_add (
+        (GSourceFunc) gimp_paned_box_drag_callback_idle,
+        paned_box);
+    }
+  else
+    {
+      if (paned_box->p->dnd_idle_id)
+        {
+          g_source_remove (paned_box->p->dnd_idle_id);
+
+          paned_box->p->dnd_idle_id = 0;
+        }
+
+      paned_box->p->dnd_context = NULL;
+
+      gimp_paned_box_hide_drop_indicator (paned_box, 1);
+      gimp_paned_box_hide_drop_indicator (paned_box, 2);
+
+      if (paned)
+        {
+          gtk_paned_set_position (GTK_PANED (paned),
+                                  paned_box->p->dnd_paned_position);
+        }
+    }
+}
+
 
 GtkWidget *
 gimp_paned_box_new (gboolean       homogeneous,
@@ -537,9 +730,6 @@ gimp_paned_box_add_widget (GimpPanedBox *paned_box,
   /* Insert into the GtkPaned hierarchy */
   if (old_length == 0)
     {
-      /* A widget is added, hide the instructions */
-      gtk_widget_hide (paned_box->p->instructions);
-
       gtk_box_pack_start (GTK_BOX (paned_box), widget, TRUE, TRUE, 0);
     }
   else
@@ -647,9 +837,6 @@ gimp_paned_box_remove_widget (GimpPanedBox *paned_box,
        */
       if (gtk_widget_get_parent (widget) != NULL)
         gtk_container_remove (GTK_CONTAINER (paned_box), widget);
-
-      /* The last widget is removed, show the instructions */
-      gtk_widget_show (paned_box->p->instructions);
     }
   else
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]