Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gimppanedbox.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimppanedbox.c
 * Copyright (C) 2001-2005 Michael Natterer <mitch@gimp.org>
 * Copyright (C) 2009-2011 Martin Nordholts <martinn@src.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/>.
 */


#include "config.h"

#include <gegl.h>
#include <gtk/gtk.h>

#include "libgimpcolor/gimpcolor.h"
#include "libgimpwidgets/gimpwidgets.h"

#include "widgets-types.h"

#include "core/gimp.h"
#include "core/gimpcontext.h"

#include "gimpdialogfactory.h"
#include "gimpdnd.h"
#include "gimpdockable.h"
#include "gimpdockbook.h"
#include "gimpmenudock.h"
#include "gimppanedbox.h"
#include "gimptoolbox.h"
#include "gimpwidgets-utils.h"

#include "gimp-log.h"


/**
 * Defines the size of the area that dockables can be dropped on in
 * 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_HIGHLIGHT_MIN_SIZE         32
#define DROP_HIGHLIGHT_COLOR            "#215d9c"
#define DROP_HIGHLIGHT_OPACITY_ACTIVE   0.8
#define DROP_HIGHLIGHT_OPACITY_INACTIVE 0.4

#define INSERT_INDEX_UNUSED             G_MININT


typedef struct
{
  gboolean      active;
  GeglRectangle area;
  gdouble       opacity;
} GimpPanedBoxHighlight;

struct _GimpPanedBoxPrivate
{
  /* Widgets that are separated by panes */
  GList                  *widgets;

  /* Is the DND highlight shown */
  GimpPanedBoxHighlight   dnd_highlights[3];
  gint                    dnd_n_highlights;
  GdkDragContext         *dnd_context;
  gint                    dnd_paned_position;
  gint                    dnd_idle_id;

  /* The insert index to use on drop */
  gint                    insert_index;

  /* Callback on drop */
  GimpPanedBoxDroppedFunc dropped_cb;
  gpointer                dropped_cb_data;

  /* A drag handler offered to handle drag events */
  GimpPanedBox           *drag_handler;
};


static void      gimp_paned_box_dispose                 (GObject        *object);

static void      gimp_paned_box_drag_leave              (GtkWidget      *widget,
                                                         GdkDragContext *context,
                                                         guint           time);
static gboolean  gimp_paned_box_drag_motion             (GtkWidget      *widget,
                                                         GdkDragContext *context,
                                                         gint            x,
                                                         gint            y,
                                                         guint           time);
static gboolean  gimp_paned_box_drag_drop               (GtkWidget      *widget,
                                                         GdkDragContext *context,
                                                         gint            x,
                                                         gint            y,
                                                         guint           time);
static void      gimp_paned_box_drag_data_received      (GtkWidget      *widget,
                                                         GdkDragContext *context,
                                                         gint            x,
                                                         gint            y,
                                                         GtkSelectionData *data,
                                                         guint           info,
                                                         guint           time);
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_hide_drop_indicator     (GimpPanedBox   *paned_box,
                                                         gint            index);

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)

#define parent_class gimp_paned_box_parent_class

static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_NOTEBOOK_TAB };

static GSList *drop_hints = NULL;


static void
gimp_paned_box_class_init (GimpPanedBoxClass *klass)
{
  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  object_class->dispose            = gimp_paned_box_dispose;

  widget_class->drag_leave         = gimp_paned_box_drag_leave;
  widget_class->drag_motion        = gimp_paned_box_drag_motion;
  widget_class->drag_drop          = gimp_paned_box_drag_drop;
  widget_class->drag_data_received = gimp_paned_box_drag_data_received;
}

static void
gimp_paned_box_init (GimpPanedBox *paned_box)
{
  paned_box->p = gimp_paned_box_get_instance_private (paned_box);

  /* 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
gimp_paned_box_dispose (GObject *object)
{
  GimpPanedBox *paned_box = GIMP_PANED_BOX (object);
  gsize         i;

  for (i = 0; i < G_N_ELEMENTS (paned_box->p->dnd_highlights); i++)
    gimp_paned_box_hide_drop_indicator (paned_box, i);

  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;

      g_object_ref (widget);
      gimp_paned_box_remove_widget (paned_box, widget);
      gtk_widget_destroy (widget);
      g_object_unref (widget);
    }

  gimp_dockbook_remove_drag_callback (
    (GimpDockbookDragCallback) gimp_paned_box_drag_callback,
    paned_box);

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
gimp_paned_box_set_widget_drag_handler (GtkWidget    *widget,
                                        GimpPanedBox *drag_handler)
{
  /* Hook us in for drag events. We could abstract this properly and
   * put gimp_paned_box_will_handle_drag() in an interface for
   * example, but it doesn't feel worth it at this point
   *
   * Note that we don't have 'else if's because a widget can be both a
   * dock and a toolbox for example, in which case we want to set a
   * drag handler in two ways
   *
   * We so need to introduce some abstractions here...
   */


  if (GIMP_IS_DOCKBOOK (widget))
    {
      gimp_dockbook_set_drag_handler (GIMP_DOCKBOOK (widget),
                                      drag_handler);
    }

  if (GIMP_IS_DOCK (widget))
    {
      GimpPanedBox *dock_paned_box = NULL;
      dock_paned_box = GIMP_PANED_BOX (gimp_dock_get_vbox (GIMP_DOCK (widget)));
      gimp_paned_box_set_drag_handler (dock_paned_box, drag_handler);
    }

  if (GIMP_IS_TOOLBOX (widget))
    {
      GimpToolbox *toolbox = GIMP_TOOLBOX (widget);
      gimp_toolbox_set_drag_handler (toolbox, drag_handler);
    }
}

static gint
gimp_paned_box_get_drop_area_size (GimpPanedBox *paned_box)
{
  gint drop_area_size = 0;

  if (! paned_box->p->widgets)
    {
      GtkAllocation  allocation;
      GtkOrientation orientation;

      gtk_widget_get_allocation (GTK_WIDGET (paned_box), &allocation);
      orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));

      if (orientation == GTK_ORIENTATION_HORIZONTAL)
        drop_area_size = allocation.width;
      else if (orientation == GTK_ORIENTATION_VERTICAL)
        drop_area_size = allocation.height;
    }

  drop_area_size = MAX (drop_area_size, DROP_AREA_SIZE);

  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;
    }

  if (gtk_drag_dest_find_target (GTK_WIDGET (paned_box), context, NULL) ==
      GDK_NONE)
    {
      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 gboolean
gimp_paned_box_drop_indicator_draw (GtkWidget *widget,
                                    cairo_t   *cr,
                                    gpointer   data)
{
  GimpPanedBox *paned_box = GIMP_PANED_BOX (widget);
  GeglColor    *color;
  gdouble       rgba[4];
  gsize         i;

  color = gimp_color_parse_hex (DROP_HIGHLIGHT_COLOR);
  gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), rgba);

  for (i = 0; i < G_N_ELEMENTS (paned_box->p->dnd_highlights); i++)
    {
      const GimpPanedBoxHighlight *highlight = &paned_box->p->dnd_highlights[i];

      if (! highlight->active)
        continue;

      rgba[3] = highlight->opacity;
      gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgba);

      gimp_cairo_set_source_color (cr, color, NULL, FALSE, widget);

      cairo_rectangle (cr,
                       highlight->area.x,
                       highlight->area.y,
                       highlight->area.width,
                       highlight->area.height);

      cairo_fill (cr);
    }
  g_object_unref (color);

  return FALSE;
}

static void
gimp_paned_box_position_drop_indicator (GimpPanedBox        *paned_box,
                                        gint                 index,
                                        const GeglRectangle *area,
                                        gdouble              opacity)
{
  GtkWidget *widget = GTK_WIDGET (paned_box);

  paned_box->p->dnd_highlights[index].area    = *area;
  paned_box->p->dnd_highlights[index].opacity = opacity;

  if (! paned_box->p->dnd_highlights[index].active)
    {
      if (paned_box->p->dnd_n_highlights == 0)
        {
          g_signal_connect_after (
            widget, "draw",
            G_CALLBACK (gimp_paned_box_drop_indicator_draw),
            NULL);
        }

      paned_box->p->dnd_highlights[index].active = TRUE;

      paned_box->p->dnd_n_highlights++;
    }

  gtk_widget_queue_draw (widget);
}

static void
gimp_paned_box_hide_drop_indicator (GimpPanedBox *paned_box,
                                    gint          index)
{
  GtkWidget *widget = GTK_WIDGET (paned_box);

  if (paned_box->p->dnd_highlights[index].active)
    {
      paned_box->p->dnd_highlights[index].active = FALSE;

      paned_box->p->dnd_n_highlights--;

      if (paned_box->p->dnd_n_highlights == 0)
        {
          g_signal_handlers_disconnect_by_func (
            widget,
            gimp_paned_box_drop_indicator_draw,
            NULL);
        }
    }

  gtk_widget_queue_draw (widget);
}

static void
gimp_paned_box_drag_leave (GtkWidget      *widget,
                           GdkDragContext *context,
                           guint           time)
{
  gimp_paned_box_hide_drop_indicator (GIMP_PANED_BOX (widget), 0);
}

static gboolean
gimp_paned_box_drag_motion (GtkWidget      *widget,
                            GdkDragContext *context,
                            gint            x,
                            gint            y,
                            guint           time)
{
  GimpPanedBox  *paned_box = GIMP_PANED_BOX (widget);
  gint           insert_index;
  GeglRectangle  area;
  gboolean       handle;

  handle = gimp_paned_box_get_handle_drag (paned_box, context, x, y, time,
                                           &insert_index, &area);

  /* If we are at the edge, show a highlight to communicate that a
   * drop will create a new dock column
   */

  if (handle)
    {
      gimp_paned_box_position_drop_indicator (paned_box,
                                              0,
                                              &area,
                                              DROP_HIGHLIGHT_OPACITY_ACTIVE);
    }
  else
    {
      gimp_paned_box_hide_drop_indicator (paned_box, 0);
    }

  /* Save the insert index for drag-drop */
  paned_box->p->insert_index = insert_index;

  gdk_drag_status (context, handle ? GDK_ACTION_MOVE : 0, time);

  /* Return TRUE so drag_leave() is called */
  return handle;
}

static gboolean
gimp_paned_box_drag_drop (GtkWidget      *widget,
                          GdkDragContext *context,
                          gint            x,
                          gint            y,
                          guint           time)
{
  GimpPanedBox *paned_box = GIMP_PANED_BOX (widget);
  GdkAtom       target;

  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
                                       widget,
                                       context,
                                       x, y,
                                       time))
    {
      return FALSE;
    }

  target = gtk_drag_dest_find_target (widget, context, NULL);

  if (target == GDK_NONE)
    return FALSE;

  gtk_drag_get_data (widget, context, target, time);

  return TRUE;
}

static void
gimp_paned_box_drag_data_received (GtkWidget        *widget,
                                   GdkDragContext   *context,
                                   gint              x,
                                   gint              y,
                                   GtkSelectionData *data,
                                   guint             info,
                                   guint             time)
{
  GimpPanedBox  *paned_box = GIMP_PANED_BOX (widget);
  GtkWidget     *notebook  = gtk_drag_get_source_widget (context);
  GtkWidget    **child     = (gpointer) gtk_selection_data_get_data (data);
  gboolean      dropped    = FALSE;

  if (paned_box->p->dropped_cb)
    {
      dropped = paned_box->p->dropped_cb (notebook,
                                          *child,
                                          paned_box->p->insert_index,
                                          paned_box->p->dropped_cb_data);
    }

  gtk_drag_finish (context, dropped, TRUE, time);
}

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,                                 \
          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);

  /* apparently, we can be called multiple times when beginning a drag
   * (possibly a gtk bug); make sure not to leak the idle.
   *
   * see issue #4895.
   */

  if (begin && ! paned_box->p->dnd_context)
    {
      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 (! begin && paned_box->p->dnd_context)
    {
      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,
                    gint           spacing,
                    GtkOrientation orientation)
{
  return g_object_new (GIMP_TYPE_PANED_BOX,
                       "homogeneous",  homogeneous,
                       "spacing",      0,
                       "orientation",  orientation,
                       NULL);
}

void
gimp_paned_box_set_dropped_cb (GimpPanedBox            *paned_box,
                               GimpPanedBoxDroppedFunc  dropped_cb,
                               gpointer                 dropped_cb_data)
{
  g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));

  paned_box->p->dropped_cb      = dropped_cb;
  paned_box->p->dropped_cb_data = dropped_cb_data;
}

/**
 * gimp_paned_box_add_widget:
 * @paned_box: A #GimpPanedBox
 * @widget:    The #GtkWidget to add
 * @index:     Where to add the @widget
 *
 * Add a #GtkWidget to the #GimpPanedBox in a hierarchy of #GtkPaned:s
 * so the space can be manually distributed between the widgets.
 **/

void
gimp_paned_box_add_widget (GimpPanedBox *paned_box,
                           GtkWidget    *widget,
                           gint          index)
{
  gint old_length = 0;

  g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));
  g_return_if_fail (GTK_IS_WIDGET (widget));

  GIMP_LOG (DND, "Adding GtkWidget %p to GimpPanedBox %p", widget, paned_box);

  /* Calculate length */
  old_length = g_list_length (paned_box->p->widgets);

  /* If index is invalid append at the end */
  if (index >= old_length || index < 0)
    {
      index = old_length;
    }

  /* Insert into the list */
  paned_box->p->widgets = g_list_insert (paned_box->p->widgets, widget, index);

  /* Hook us in for drag events. We could abstract this but it doesn't
   * seem worth it at this point
   */

  gimp_paned_box_set_widget_drag_handler (widget, 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);
      drop_hints = g_slist_remove (drop_hints, paned_box);

      gtk_box_pack_start (GTK_BOX (paned_box), widget, TRUE, TRUE, 0);
    }
  else
    {
      GtkWidget      *old_widget;
      GtkWidget      *parent;
      GtkWidget      *paned;
      GtkOrientation  orientation;

      /* Figure out what widget to detach */
      if (index == 0)
        {
          old_widget = g_list_nth_data (paned_box->p->widgets, index + 1);
        }
      else
        {
          old_widget = g_list_nth_data (paned_box->p->widgets, index - 1);
        }

      parent = gtk_widget_get_parent (old_widget);

      if (old_length > 1 && index > 0)
        {
          GtkWidget *grandparent = gtk_widget_get_parent (parent);

          old_widget = parent;
          parent     = grandparent;
        }

      /* Detach the widget and build up a new hierarchy */
      g_object_ref (old_widget);
      gtk_container_remove (GTK_CONTAINER (parent), old_widget);

      /* GtkPaned is abstract :( */
      orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
      paned = gtk_paned_new (orientation);
      gtk_paned_set_wide_handle (GTK_PANED (paned), TRUE);

      if (GTK_IS_PANED (parent))
        {
          gtk_paned_pack1 (GTK_PANED (parent), paned, TRUE, FALSE);
        }
      else
        {
          gtk_box_pack_start (GTK_BOX (parent), paned, TRUE, TRUE, 0);
        }
      gtk_widget_show (paned);

      if (index == 0)
        {
          gtk_paned_pack1 (GTK_PANED (paned), widget,
                           TRUE, FALSE);
          gtk_paned_pack2 (GTK_PANED (paned), old_widget,
                           TRUE, FALSE);
        }
      else
        {
          gtk_paned_pack1 (GTK_PANED (paned), old_widget,
                           TRUE, FALSE);
          gtk_paned_pack2 (GTK_PANED (paned), widget,
                           TRUE, FALSE);
        }

      g_object_unref (old_widget);
    }
}

/**
 * gimp_paned_box_remove_widget:
 * @paned_box: A #GimpPanedBox
 * @widget:    The #GtkWidget to remove
 *
 * Remove a #GtkWidget from a #GimpPanedBox added with
 * gimp_widgets_add_paned_widget().
 **/

void
gimp_paned_box_remove_widget (GimpPanedBox *paned_box,
                              GtkWidget    *widget)
{
  gint       old_length   = 0;
  gint       index        = 0;
  GtkWidget *other_widget = NULL;
  GtkWidget *parent       = NULL;
  GtkWidget *grandparent  = NULL;

  g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));
  g_return_if_fail (GTK_IS_WIDGET (widget));

  GIMP_LOG (DND, "Removing GtkWidget %p from GimpPanedBox %p", widget, paned_box);

  /* Calculate length and index */
  old_length = g_list_length (paned_box->p->widgets);
  index      = g_list_index (paned_box->p->widgets, widget);

  /* Remove from list */
  paned_box->p->widgets = g_list_remove (paned_box->p->widgets, widget);

  /* Reset the drag events hook */
  gimp_paned_box_set_widget_drag_handler (widget, NULL);

  /* Remove from widget hierarchy */
  if (old_length == 1)
    {
      /* The widget might already be parent-less if we are in
       * destruction, .e.g when closing a dock window.
       */

      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);
      drop_hints = g_slist_prepend (drop_hints, paned_box);
    }
  else
    {
      g_object_ref (widget);

      parent      = gtk_widget_get_parent (GTK_WIDGET (widget));
      grandparent = gtk_widget_get_parent (parent);

      if (index == 0)
        other_widget = gtk_paned_get_child2 (GTK_PANED (parent));
      else
        other_widget = gtk_paned_get_child1 (GTK_PANED (parent));

      g_object_ref (other_widget);

      gtk_container_remove (GTK_CONTAINER (parent), other_widget);
      gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (widget));

      gtk_container_remove (GTK_CONTAINER (grandparent), parent);

      if (GTK_IS_PANED (grandparent))
        gtk_paned_pack1 (GTK_PANED (grandparent), other_widget, TRUE, FALSE);
      else
        gtk_box_pack_start (GTK_BOX (paned_box), other_widget, TRUE, TRUE, 0);

      g_object_unref (other_widget);

      g_object_unref (widget);
    }
}

/**
 * gimp_paned_box_will_handle_drag:
 * @paned_box: A #GimpPanedBox
 * @widget:    The widget that got the drag event
 * @context:   Context from drag event
 * @x:         x from drag event
 * @y:         y from drag event
 * @time:      time from drag event
 *
 * Returns: %TRUE if the drag event on @widget will be handled by
 *          @paned_box.
 **/

gboolean
gimp_paned_box_will_handle_drag (GimpPanedBox   *paned_box,
                                 GtkWidget      *widget,
                                 GdkDragContext *context,
                                 gint            x,
                                 gint            y,
                                 gint            time)
{
  gint           paned_box_x    = 0;
  gint           paned_box_y    = 0;
  GtkAllocation  allocation     = { 0, };
  GtkOrientation orientation    = 0;
  gboolean       will_handle    = FALSE;
  gint           drop_area_size = 0;

  g_return_val_if_fail (paned_box == NULL ||
                        GIMP_IS_PANED_BOX (paned_box), FALSE);

  /* Check for NULL to allow cleaner client code */
  if (paned_box == NULL)
    return FALSE;

  /* Our handler might handle it */
  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
                                       widget,
                                       context,
                                       x, y,
                                       time))
    {
      /* Return TRUE so the client will pass on the drag event */
      return TRUE;
    }

  /* If we don't have a common ancenstor we will not handle it */
  if (! gtk_widget_translate_coordinates (widget,
                                          GTK_WIDGET (paned_box),
                                          x, y,
                                          &paned_box_x, &paned_box_y))
    {
      /* Return FALSE so the client can take care of the drag event */
      return FALSE;
    }

  /* We now have paned_box coordinates, see if the paned_box will
   * handle the event
   */

  gtk_widget_get_allocation (GTK_WIDGET (paned_box), &allocation);
  orientation    = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
  drop_area_size = gimp_paned_box_get_drop_area_size (paned_box);
  if (orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      will_handle = (paned_box_x < drop_area_size ||
                     paned_box_x > allocation.width - drop_area_size);
    }
  else /*if (orientation = GTK_ORIENTATION_VERTICAL)*/
    {
      will_handle = (paned_box_y < drop_area_size ||
                     paned_box_y > allocation.height - drop_area_size);
    }

  return will_handle;
}

void
gimp_paned_box_set_drag_handler (GimpPanedBox *paned_box,
                                 GimpPanedBox *drag_handler)
{
  g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));

  paned_box->p->drag_handler = drag_handler;
}

Messung
CHZG
82999993

¤ Dauer der Verarbeitung: 0.17 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417313