gtktoolpalette.c 57.4 KB
Newer Older
Johannes Schmid's avatar
Johannes Schmid committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* GtkToolPalette -- A tool palette with categories and DnD support
 * Copyright (C) 2008  Openismus GmbH
 *
 * 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
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Johannes Schmid's avatar
Johannes Schmid committed
16 17 18 19 20
 *
 * Authors:
 *      Mathias Hasselmann
 */

21 22 23 24 25
#include "config.h"

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

Johannes Schmid's avatar
Johannes Schmid committed
26 27
#include "gtktoolpaletteprivate.h"
#include "gtkmarshalers.h"
28
#include "gtktypebuiltins.h"
29
#include "gtkprivate.h"
30
#include "gtkscrollable.h"
31
#include "gtkorientableprivate.h"
32
#include "gtkintl.h"
Johannes Schmid's avatar
Johannes Schmid committed
33 34 35 36 37 38 39 40 41

#define DEFAULT_ICON_SIZE       GTK_ICON_SIZE_SMALL_TOOLBAR
#define DEFAULT_ORIENTATION     GTK_ORIENTATION_VERTICAL
#define DEFAULT_TOOLBAR_STYLE   GTK_TOOLBAR_ICONS

#define DEFAULT_CHILD_EXCLUSIVE FALSE
#define DEFAULT_CHILD_EXPAND    FALSE

/**
42 43 44
 * SECTION:gtktoolpalette
 * @Short_description: A tool palette with categories
 * @Title: GtkToolPalette
Johannes Schmid's avatar
Johannes Schmid committed
45
 *
46
 * A #GtkToolPalette allows you to add #GtkToolItems to a palette-like
47
 * container with different categories and drag and drop support.
Johannes Schmid's avatar
Johannes Schmid committed
48
 *
49
 * A #GtkToolPalette is created with a call to gtk_tool_palette_new().
Johannes Schmid's avatar
Johannes Schmid committed
50
 *
51
 * #GtkToolItems cannot be added directly to a #GtkToolPalette - 
52 53 54
 * instead they are added to a #GtkToolItemGroup which can than be added
 * to a #GtkToolPalette. To add a #GtkToolItemGroup to a #GtkToolPalette,
 * use gtk_container_add().
Johannes Schmid's avatar
Johannes Schmid committed
55
 *
56
 * |[<!-- language="C" -->
Johannes Schmid's avatar
Johannes Schmid committed
57 58 59 60 61 62 63
 * GtkWidget *palette, *group;
 * GtkToolItem *item;
 *
 * palette = gtk_tool_palette_new ();
 * group = gtk_tool_item_group_new (_("Test Category"));
 * gtk_container_add (GTK_CONTAINER (palette), group);
 *
64 65
 * item = gtk_tool_button_new_new (NULL, _("_Open"));
 * gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "document-open");
Johannes Schmid's avatar
Johannes Schmid committed
66 67 68
 * gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (group), item, -1);
 * ]|
 *
69 70 71 72 73
 * The easiest way to use drag and drop with #GtkToolPalette is to call
 * gtk_tool_palette_add_drag_dest() with the desired drag source @palette
 * and the desired drag target @widget. Then gtk_tool_palette_get_drag_item()
 * can be used to get the dragged item in the #GtkWidget::drag-data-received
 * signal handler of the drag target.
Johannes Schmid's avatar
Johannes Schmid committed
74
 *
75
 * |[<!-- language="C" -->
Johannes Schmid's avatar
Johannes Schmid committed
76 77 78 79 80 81 82 83 84 85 86 87 88
 * static void
 * passive_canvas_drag_data_received (GtkWidget        *widget,
 *                                    GdkDragContext   *context,
 *                                    gint              x,
 *                                    gint              y,
 *                                    GtkSelectionData *selection,
 *                                    guint             info,
 *                                    guint             time,
 *                                    gpointer          data)
 * {
 *   GtkWidget *palette;
 *   GtkWidget *item;
 *
89
 *   // Get the dragged item
90 91
 *   palette = gtk_widget_get_ancestor (gtk_drag_get_source_widget (context),
 *                                      GTK_TYPE_TOOL_PALETTE);
Johannes Schmid's avatar
Johannes Schmid committed
92
 *   if (palette != NULL)
93 94
 *     item = gtk_tool_palette_get_drag_item (GTK_TOOL_PALETTE (palette),
 *                                            selection);
Johannes Schmid's avatar
Johannes Schmid committed
95
 *
96
 *   // Do something with item
Johannes Schmid's avatar
Johannes Schmid committed
97 98 99 100 101 102 103 104
 * }
 *
 * GtkWidget *target, palette;
 *
 * palette = gtk_tool_palette_new ();
 * target = gtk_drawing_area_new ();
 *
 * g_signal_connect (G_OBJECT (target), "drag-data-received",
105
 *                   G_CALLBACK (passive_canvas_drag_data_received), NULL);
Johannes Schmid's avatar
Johannes Schmid committed
106 107 108 109 110 111
 * gtk_tool_palette_add_drag_dest (GTK_TOOL_PALETTE (palette), target,
 *                                 GTK_DEST_DEFAULT_ALL,
 *                                 GTK_TOOL_PALETTE_DRAG_ITEMS,
 *                                 GDK_ACTION_COPY);
 * ]|
 *
112 113 114 115
 * # CSS nodes
 *
 * GtkToolPalette has a single CSS node named toolpalette.
 *
116
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
117 118 119 120 121 122 123 124 125
 */

typedef struct _GtkToolItemGroupInfo   GtkToolItemGroupInfo;
typedef struct _GtkToolPaletteDragData GtkToolPaletteDragData;

enum
{
  PROP_NONE,
  PROP_ICON_SIZE,
126
  PROP_ICON_SIZE_SET,
Johannes Schmid's avatar
Johannes Schmid committed
127 128
  PROP_ORIENTATION,
  PROP_TOOLBAR_STYLE,
129
  PROP_HADJUSTMENT,
130 131 132
  PROP_VADJUSTMENT,
  PROP_HSCROLL_POLICY,
  PROP_VSCROLL_POLICY
Johannes Schmid's avatar
Johannes Schmid committed
133 134 135 136 137 138 139 140 141 142 143 144 145
};

enum
{
  CHILD_PROP_NONE,
  CHILD_PROP_EXCLUSIVE,
  CHILD_PROP_EXPAND,
};

struct _GtkToolItemGroupInfo
{
  GtkToolItemGroup *widget;

146
  gulong            notify_collapsed;
147
  guint             pos;
Johannes Schmid's avatar
Johannes Schmid committed
148 149 150 151 152 153
  guint             exclusive : 1;
  guint             expand : 1;
};

struct _GtkToolPalettePrivate
{
154
  GPtrArray* groups;
Johannes Schmid's avatar
Johannes Schmid committed
155 156 157 158 159

  GtkAdjustment        *hadjustment;
  GtkAdjustment        *vadjustment;

  GtkIconSize           icon_size;
160
  gboolean              icon_size_set;
Johannes Schmid's avatar
Johannes Schmid committed
161 162
  GtkOrientation        orientation;
  GtkToolbarStyle       style;
163
  gboolean              style_set;
Johannes Schmid's avatar
Johannes Schmid committed
164 165 166 167

  GtkWidget            *expanding_child;

  GtkSizeGroup         *text_size_group;
168

Johannes Schmid's avatar
Johannes Schmid committed
169
  guint                 drag_source : 2;
170 171 172 173 174

  /* GtkScrollablePolicy needs to be checked when
   * driving the scrollable adjustment values */
  guint hscroll_policy : 1;
  guint vscroll_policy : 1;
Johannes Schmid's avatar
Johannes Schmid committed
175 176 177 178 179 180 181 182 183 184 185 186 187
};

struct _GtkToolPaletteDragData
{
  GtkToolPalette *palette;
  GtkWidget      *item;
};

static GdkAtom dnd_target_atom_item = GDK_NONE;
static GdkAtom dnd_target_atom_group = GDK_NONE;

static const GtkTargetEntry dnd_targets[] =
{
188 189
  { "application/x-gtk-tool-palette-item", GTK_TARGET_SAME_APP, 0 },
  { "application/x-gtk-tool-palette-group", GTK_TARGET_SAME_APP, 0 },
Johannes Schmid's avatar
Johannes Schmid committed
190 191
};

192 193 194 195 196 197
static void gtk_tool_palette_set_hadjustment (GtkToolPalette *palette,
                                              GtkAdjustment  *adjustment);
static void gtk_tool_palette_set_vadjustment (GtkToolPalette *palette,
                                              GtkAdjustment  *adjustment);


198
G_DEFINE_TYPE_WITH_CODE (GtkToolPalette,
199 200 201 202 203
                         gtk_tool_palette,
                         GTK_TYPE_CONTAINER,
                         G_ADD_PRIVATE (GtkToolPalette)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
Johannes Schmid's avatar
Johannes Schmid committed
204 205 206 207

static void
gtk_tool_palette_init (GtkToolPalette *palette)
{
208
  palette->priv = gtk_tool_palette_get_instance_private (palette);
209
  palette->priv->groups = g_ptr_array_sized_new (4);
210
  g_ptr_array_set_free_func (palette->priv->groups, g_free);
Johannes Schmid's avatar
Johannes Schmid committed
211 212

  palette->priv->icon_size = DEFAULT_ICON_SIZE;
213
  palette->priv->icon_size_set = FALSE;
Johannes Schmid's avatar
Johannes Schmid committed
214 215
  palette->priv->orientation = DEFAULT_ORIENTATION;
  palette->priv->style = DEFAULT_TOOLBAR_STYLE;
216
  palette->priv->style_set = FALSE;
Johannes Schmid's avatar
Johannes Schmid committed
217 218

  palette->priv->text_size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
219 220 221 222 223 224

  if (dnd_target_atom_item == GDK_NONE)
    {
      dnd_target_atom_item = gdk_atom_intern_static_string (dnd_targets[0].target);
      dnd_target_atom_group = gdk_atom_intern_static_string (dnd_targets[1].target);
    }
Johannes Schmid's avatar
Johannes Schmid committed
225 226 227 228 229 230 231
}

static void
gtk_tool_palette_reconfigured (GtkToolPalette *palette)
{
  guint i;

232
  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
233
    {
234
      GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
235 236
      if (info->widget)
        _gtk_tool_item_group_palette_reconfigured (info->widget);
Johannes Schmid's avatar
Johannes Schmid committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    }

  gtk_widget_queue_resize_no_redraw (GTK_WIDGET (palette));
}

static void
gtk_tool_palette_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (object);

  switch (prop_id)
    {
      case PROP_ICON_SIZE:
253
        if (palette->priv->icon_size != g_value_get_enum (value))
Johannes Schmid's avatar
Johannes Schmid committed
254 255 256
          {
            palette->priv->icon_size = g_value_get_enum (value);
            gtk_tool_palette_reconfigured (palette);
257
            g_object_notify_by_pspec (object, pspec);
Johannes Schmid's avatar
Johannes Schmid committed
258 259
          }
        break;
260

261
      case PROP_ICON_SIZE_SET:
262
        if (palette->priv->icon_size_set != g_value_get_boolean (value))
263
          {
264
            palette->priv->icon_size_set = g_value_get_boolean (value);
265
            gtk_tool_palette_reconfigured (palette);
266
            g_object_notify_by_pspec (object, pspec);
267 268
          }
        break;
Johannes Schmid's avatar
Johannes Schmid committed
269 270

      case PROP_ORIENTATION:
271
        if (palette->priv->orientation != g_value_get_enum (value))
Johannes Schmid's avatar
Johannes Schmid committed
272 273
          {
            palette->priv->orientation = g_value_get_enum (value);
274
            _gtk_orientable_set_style_classes (GTK_ORIENTABLE (palette));
Johannes Schmid's avatar
Johannes Schmid committed
275
            gtk_tool_palette_reconfigured (palette);
276
            g_object_notify_by_pspec (object, pspec);
Johannes Schmid's avatar
Johannes Schmid committed
277 278 279 280
          }
        break;

      case PROP_TOOLBAR_STYLE:
281
        if (palette->priv->style != g_value_get_enum (value))
Johannes Schmid's avatar
Johannes Schmid committed
282 283 284
          {
            palette->priv->style = g_value_get_enum (value);
            gtk_tool_palette_reconfigured (palette);
285
            g_object_notify_by_pspec (object, pspec);
Johannes Schmid's avatar
Johannes Schmid committed
286 287 288
          }
        break;

289 290 291 292 293 294 295 296
      case PROP_HADJUSTMENT:
        gtk_tool_palette_set_hadjustment (palette, g_value_get_object (value));
        break;

      case PROP_VADJUSTMENT:
        gtk_tool_palette_set_vadjustment (palette, g_value_get_object (value));
        break;

297
      case PROP_HSCROLL_POLICY:
298 299 300 301 302 303
        if (palette->priv->hscroll_policy != g_value_get_enum (value))
          {
	    palette->priv->hscroll_policy = g_value_get_enum (value);
	    gtk_widget_queue_resize (GTK_WIDGET (palette));
            g_object_notify_by_pspec (object, pspec);
          }
304 305 306
	break;

      case PROP_VSCROLL_POLICY:
307 308 309 310 311 312
        if (palette->priv->vscroll_policy != g_value_get_enum (value))
          {
	    palette->priv->vscroll_policy = g_value_get_enum (value);
	    gtk_widget_queue_resize (GTK_WIDGET (palette));
            g_object_notify_by_pspec (object, pspec);
          }
313 314
	break;

Johannes Schmid's avatar
Johannes Schmid committed
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static void
gtk_tool_palette_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (object);

  switch (prop_id)
    {
      case PROP_ICON_SIZE:
        g_value_set_enum (value, gtk_tool_palette_get_icon_size (palette));
        break;
334

335 336 337
      case PROP_ICON_SIZE_SET:
        g_value_set_boolean (value, palette->priv->icon_size_set);
        break;
Johannes Schmid's avatar
Johannes Schmid committed
338 339

      case PROP_ORIENTATION:
340
        g_value_set_enum (value, palette->priv->orientation);
Johannes Schmid's avatar
Johannes Schmid committed
341 342 343 344 345 346
        break;

      case PROP_TOOLBAR_STYLE:
        g_value_set_enum (value, gtk_tool_palette_get_style (palette));
        break;

347 348 349 350 351 352 353 354
      case PROP_HADJUSTMENT:
        g_value_set_object (value, palette->priv->hadjustment);
        break;

      case PROP_VADJUSTMENT:
        g_value_set_object (value, palette->priv->vadjustment);
        break;

355 356 357 358 359 360 361 362
      case PROP_HSCROLL_POLICY:
	g_value_set_enum (value, palette->priv->hscroll_policy);
	break;

      case PROP_VSCROLL_POLICY:
	g_value_set_enum (value, palette->priv->vscroll_policy);
	break;

Johannes Schmid's avatar
Johannes Schmid committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static void
gtk_tool_palette_dispose (GObject *object)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (object);
  guint i;

  if (palette->priv->hadjustment)
    {
      g_object_unref (palette->priv->hadjustment);
      palette->priv->hadjustment = NULL;
    }

  if (palette->priv->vadjustment)
    {
      g_object_unref (palette->priv->vadjustment);
      palette->priv->vadjustment = NULL;
    }

387
  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
388
    {
389
      GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
Johannes Schmid's avatar
Johannes Schmid committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411

      if (group->notify_collapsed)
        {
          g_signal_handler_disconnect (group->widget, group->notify_collapsed);
          group->notify_collapsed = 0;
        }
    }

  if (palette->priv->text_size_group)
    {
      g_object_unref (palette->priv->text_size_group);
      palette->priv->text_size_group = NULL;
    }

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

static void
gtk_tool_palette_finalize (GObject *object)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (object);

412
  g_ptr_array_free (palette->priv->groups, TRUE);
Johannes Schmid's avatar
Johannes Schmid committed
413 414 415 416 417 418 419 420 421 422

  G_OBJECT_CLASS (gtk_tool_palette_parent_class)->finalize (object);
}

static void
gtk_tool_palette_size_request (GtkWidget      *widget,
                               GtkRequisition *requisition)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (widget);
  GtkRequisition child_requisition;
423
  guint border_width;
Johannes Schmid's avatar
Johannes Schmid committed
424 425
  guint i;

426 427
  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));

Johannes Schmid's avatar
Johannes Schmid committed
428 429 430
  requisition->width = 0;
  requisition->height = 0;

431
  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
432
    {
433
      GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
Johannes Schmid's avatar
Johannes Schmid committed
434 435 436 437

      if (!group->widget)
        continue;

438 439
      gtk_widget_get_preferred_size (GTK_WIDGET (group->widget),
                                     &child_requisition, NULL);
Johannes Schmid's avatar
Johannes Schmid committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

      if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
        {
          requisition->width = MAX (requisition->width, child_requisition.width);
          requisition->height += child_requisition.height;
        }
      else
        {
          requisition->width += child_requisition.width;
          requisition->height = MAX (requisition->height, child_requisition.height);
        }
    }

  requisition->width += border_width * 2;
  requisition->height += border_width * 2;
}

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
static void
gtk_tool_palette_get_preferred_width (GtkWidget *widget,
				      gint      *minimum,
				      gint      *natural)
{
  GtkRequisition requisition;

  gtk_tool_palette_size_request (widget, &requisition);

  *minimum = *natural = requisition.width;
}

static void
gtk_tool_palette_get_preferred_height (GtkWidget *widget,
				       gint      *minimum,
				       gint      *natural)
{
  GtkRequisition requisition;

  gtk_tool_palette_size_request (widget, &requisition);

  *minimum = *natural = requisition.height;
}


Johannes Schmid's avatar
Johannes Schmid committed
482 483 484 485 486 487 488 489 490 491 492 493
static void
gtk_tool_palette_size_allocate (GtkWidget     *widget,
                                GtkAllocation *allocation)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (widget);
  GtkAdjustment *adjustment = NULL;
  GtkAllocation child_allocation;

  gint n_expand_groups = 0;
  gint remaining_space = 0;
  gint expand_space = 0;

494
  gint total_size, page_size;
Johannes Schmid's avatar
Johannes Schmid committed
495 496
  gint offset = 0;
  guint i;
497
  guint border_width;
Johannes Schmid's avatar
Johannes Schmid committed
498 499 500 501 502

  gint min_offset = -1, max_offset = -1;

  gint x;

503
  gint *group_sizes = g_newa (gint, palette->priv->groups->len);
504
  GtkTextDirection direction;
Johannes Schmid's avatar
Johannes Schmid committed
505

506
  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
507
  direction = gtk_widget_get_direction (widget);
Johannes Schmid's avatar
Johannes Schmid committed
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538

  GTK_WIDGET_CLASS (gtk_tool_palette_parent_class)->size_allocate (widget, allocation);

  if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
    {
      adjustment = palette->priv->vadjustment;
      page_size = allocation->height;
    }
  else
    {
      adjustment = palette->priv->hadjustment;
      page_size = allocation->width;
    }

  if (adjustment)
    offset = gtk_adjustment_get_value (adjustment);
  if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
      GTK_TEXT_DIR_RTL == direction)
    offset = -offset;

  if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
    child_allocation.width = allocation->width - border_width * 2;
  else
    child_allocation.height = allocation->height - border_width * 2;

  if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
    remaining_space = allocation->height;
  else
    remaining_space = allocation->width;

  /* figure out the required size of all groups to be able to distribute the
539 540
   * remaining space on allocation
   */
541
  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
542
    {
543
      GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
Johannes Schmid's avatar
Johannes Schmid committed
544 545
      gint size;

546 547
      group_sizes[i] = 0;

Johannes Schmid's avatar
Johannes Schmid committed
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
      if (!group->widget)
        continue;

      widget = GTK_WIDGET (group->widget);

      if (gtk_tool_item_group_get_n_items (group->widget))
        {
          if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
            size = _gtk_tool_item_group_get_height_for_width (group->widget, child_allocation.width);
          else
            size = _gtk_tool_item_group_get_width_for_height (group->widget, child_allocation.height);

          if (group->expand && !gtk_tool_item_group_get_collapsed (group->widget))
            n_expand_groups += 1;
        }
      else
        size = 0;

      remaining_space -= size;
      group_sizes[i] = size;

569 570 571
      /* if the widget is currently expanding an offset which allows to
       * display as much of the widget as possible is calculated
       */
Johannes Schmid's avatar
Johannes Schmid committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
      if (widget == palette->priv->expanding_child)
        {
          gint limit =
            GTK_ORIENTATION_VERTICAL == palette->priv->orientation ?
            child_allocation.width : child_allocation.height;

          gint real_size;
          guint j;

          min_offset = 0;

          for (j = 0; j < i; ++j)
            min_offset += group_sizes[j];

          max_offset = min_offset + group_sizes[i];

          real_size = _gtk_tool_item_group_get_size_for_limit
            (GTK_TOOL_ITEM_GROUP (widget), limit,
             GTK_ORIENTATION_VERTICAL == palette->priv->orientation,
             FALSE);

          if (size == real_size)
            palette->priv->expanding_child = NULL;
        }
    }

  if (n_expand_groups > 0)
    {
      remaining_space = MAX (0, remaining_space);
      expand_space = remaining_space / n_expand_groups;
    }

  if (max_offset != -1)
    {
      gint limit =
        GTK_ORIENTATION_VERTICAL == palette->priv->orientation ?
        allocation->height : allocation->width;

      offset = MIN (MAX (offset, max_offset - limit), min_offset);
    }

  if (remaining_space > 0)
    offset = 0;

  x = border_width;
  child_allocation.y = border_width;

  if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
    child_allocation.y -= offset;
  else
    x -= offset;

  /* allocate all groups at the calculated positions */
625
  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
626
    {
627
      GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
Johannes Schmid's avatar
Johannes Schmid committed
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652

      if (!group->widget)
        continue;

      if (gtk_tool_item_group_get_n_items (group->widget))
        {
          gint size = group_sizes[i];

          if (group->expand && !gtk_tool_item_group_get_collapsed (group->widget))
            {
              size += MIN (expand_space, remaining_space);
              remaining_space -= expand_space;
            }

          if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
            child_allocation.height = size;
          else
            child_allocation.width = size;

          if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
              GTK_TEXT_DIR_RTL == direction)
            child_allocation.x = allocation->width - x - child_allocation.width;
          else
            child_allocation.x = x;

653 654
          gtk_widget_size_allocate (GTK_WIDGET (group->widget), &child_allocation);
          gtk_widget_show (GTK_WIDGET (group->widget));
Johannes Schmid's avatar
Johannes Schmid committed
655 656 657 658 659 660 661

          if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
            child_allocation.y += child_allocation.height;
          else
            x += child_allocation.width;
        }
      else
662
        gtk_widget_hide (GTK_WIDGET (group->widget));
Johannes Schmid's avatar
Johannes Schmid committed
663 664 665 666 667 668 669
    }

  if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
    {
      child_allocation.y += border_width;
      child_allocation.y += offset;

670
      total_size = child_allocation.y;
Johannes Schmid's avatar
Johannes Schmid committed
671 672 673 674 675 676
    }
  else
    {
      x += border_width;
      x += offset;

677
      total_size = x;
Johannes Schmid's avatar
Johannes Schmid committed
678 679 680 681 682
    }

  /* update the scrollbar to match the displayed adjustment */
  if (adjustment)
    {
683 684 685 686
      gdouble lower, upper;

      total_size = MAX (0, total_size);
      page_size = MIN (total_size, page_size);
Johannes Schmid's avatar
Johannes Schmid committed
687 688 689 690

      if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation ||
          GTK_TEXT_DIR_LTR == direction)
        {
691
          lower = 0;
692
          upper = total_size;
Johannes Schmid's avatar
Johannes Schmid committed
693 694 695
        }
      else
        {
696
          lower = page_size - total_size;
697
          upper = page_size;
Johannes Schmid's avatar
Johannes Schmid committed
698 699 700 701

          offset = -offset;
        }

702
      gtk_adjustment_configure (adjustment,
703
                                offset,
704 705 706 707 708
                                lower,
                                upper,
                                page_size * 0.1,
                                page_size * 0.9,
                                page_size);
Johannes Schmid's avatar
Johannes Schmid committed
709 710 711 712 713 714
    }
}

static void
gtk_tool_palette_realize (GtkWidget *widget)
{
715 716
  GtkAllocation allocation;
  GdkWindow *window;
Johannes Schmid's avatar
Johannes Schmid committed
717
  GdkWindowAttr attributes;
718
  gint attributes_mask;
719 720
  guint border_width;

721 722
  gtk_widget_set_realized (widget, TRUE);

723
  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
Johannes Schmid's avatar
Johannes Schmid committed
724

725 726
  gtk_widget_get_allocation (widget, &allocation);

Johannes Schmid's avatar
Johannes Schmid committed
727
  attributes.window_type = GDK_WINDOW_CHILD;
728 729 730 731
  attributes.x = allocation.x + border_width;
  attributes.y = allocation.y + border_width;
  attributes.width = allocation.width - border_width * 2;
  attributes.height = allocation.height - border_width * 2;
Johannes Schmid's avatar
Johannes Schmid committed
732 733
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
734
  attributes.event_mask = gtk_widget_get_events (widget)
735
                         | GDK_VISIBILITY_NOTIFY_MASK
736
                         | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
737 738 739
                         | GDK_BUTTON_MOTION_MASK
                         | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK
                         | GDK_TOUCH_MASK;
740
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
Johannes Schmid's avatar
Johannes Schmid committed
741

742 743
  window = gdk_window_new (gtk_widget_get_parent_window (widget),
                           &attributes, attributes_mask);
744
  gtk_widget_set_window (widget, window);
745
  gtk_widget_register_window (widget, window);
Johannes Schmid's avatar
Johannes Schmid committed
746 747 748

  gtk_container_forall (GTK_CONTAINER (widget),
                        (GtkCallback) gtk_widget_set_parent_window,
749
                        window);
Johannes Schmid's avatar
Johannes Schmid committed
750 751 752 753 754

  gtk_widget_queue_resize_no_redraw (widget);
}

static void
Johannes Schmid's avatar
Johannes Schmid committed
755
gtk_tool_palette_adjustment_value_changed (GtkAdjustment *adjustment,
Johannes Schmid's avatar
Johannes Schmid committed
756 757
                                           gpointer       data)
{
758
  GtkAllocation allocation;
Johannes Schmid's avatar
Johannes Schmid committed
759
  GtkWidget *widget = GTK_WIDGET (data);
760 761 762

  gtk_widget_get_allocation (widget, &allocation);
  gtk_tool_palette_size_allocate (widget, &allocation);
Johannes Schmid's avatar
Johannes Schmid committed
763 764
}

765 766 767 768 769 770 771 772 773 774 775 776
static gboolean
gtk_tool_palette_draw (GtkWidget *widget,
                       cairo_t   *cr)
{
  gtk_render_background (gtk_widget_get_style_context (widget), cr,
                         0, 0,
                         gtk_widget_get_allocated_width (widget),
                         gtk_widget_get_allocated_height (widget));

  return GTK_WIDGET_CLASS (gtk_tool_palette_parent_class)->draw (widget, cr);
}

Johannes Schmid's avatar
Johannes Schmid committed
777 778 779 780 781
static void
gtk_tool_palette_add (GtkContainer *container,
                      GtkWidget    *child)
{
  GtkToolPalette *palette;
782
  GtkToolItemGroupInfo *info = g_new0(GtkToolItemGroupInfo, 1);
783

Johannes Schmid's avatar
Johannes Schmid committed
784 785 786 787 788
  g_return_if_fail (GTK_IS_TOOL_PALETTE (container));
  g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (child));

  palette = GTK_TOOL_PALETTE (container);

789 790 791
  g_ptr_array_add (palette->priv->groups, info);
  info->pos = palette->priv->groups->len - 1;
  info->widget = g_object_ref_sink (child);
Johannes Schmid's avatar
Johannes Schmid committed
792 793 794 795 796 797 798 799 800 801 802 803 804 805

  gtk_widget_set_parent (child, GTK_WIDGET (palette));
}

static void
gtk_tool_palette_remove (GtkContainer *container,
                         GtkWidget    *child)
{
  GtkToolPalette *palette;
  guint i;

  g_return_if_fail (GTK_IS_TOOL_PALETTE (container));
  palette = GTK_TOOL_PALETTE (container);

806 807
  for (i = 0; i < palette->priv->groups->len; ++i)
    {
808
      GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
809 810 811 812
      if (GTK_WIDGET(info->widget) == child)
        {
          g_object_unref (child);
          gtk_widget_unparent (child);
Johannes Schmid's avatar
Johannes Schmid committed
813

814 815 816
          g_ptr_array_remove_index (palette->priv->groups, i);
        }
    }
Johannes Schmid's avatar
Johannes Schmid committed
817 818 819 820
}

static void
gtk_tool_palette_forall (GtkContainer *container,
Johannes Schmid's avatar
Johannes Schmid committed
821
                         gboolean      internals,
Johannes Schmid's avatar
Johannes Schmid committed
822 823 824 825
                         GtkCallback   callback,
                         gpointer      callback_data)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (container);
826
  guint i, len;
827 828

  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
829
    {
830
      GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
831 832 833

      len = palette->priv->groups->len;

834 835 836
      if (info->widget)
        callback (GTK_WIDGET (info->widget),
                  callback_data);
837 838 839 840

      /* At destroy time, 'callback' results in removing a widget,
       * here we just reset the current index to account for the removed widget. */
      i -= (len - palette->priv->groups->len);
Johannes Schmid's avatar
Johannes Schmid committed
841 842 843 844
    }
}

static GType
Johannes Schmid's avatar
Johannes Schmid committed
845
gtk_tool_palette_child_type (GtkContainer *container)
Johannes Schmid's avatar
Johannes Schmid committed
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
{
  return GTK_TYPE_TOOL_ITEM_GROUP;
}

static void
gtk_tool_palette_set_child_property (GtkContainer *container,
                                     GtkWidget    *child,
                                     guint         prop_id,
                                     const GValue *value,
                                     GParamSpec   *pspec)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (container);

  switch (prop_id)
    {
      case CHILD_PROP_EXCLUSIVE:
862 863
        gtk_tool_palette_set_exclusive (palette, GTK_TOOL_ITEM_GROUP (child), 
          g_value_get_boolean (value));
Johannes Schmid's avatar
Johannes Schmid committed
864 865 866
        break;

      case CHILD_PROP_EXPAND:
867 868
        gtk_tool_palette_set_expand (palette, GTK_TOOL_ITEM_GROUP (child), 
          g_value_get_boolean (value));
Johannes Schmid's avatar
Johannes Schmid committed
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
        break;

      default:
        GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
        break;
    }
}

static void
gtk_tool_palette_get_child_property (GtkContainer *container,
                                     GtkWidget    *child,
                                     guint         prop_id,
                                     GValue       *value,
                                     GParamSpec   *pspec)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (container);

  switch (prop_id)
    {
      case CHILD_PROP_EXCLUSIVE:
889 890
        g_value_set_boolean (value, 
          gtk_tool_palette_get_exclusive (palette, GTK_TOOL_ITEM_GROUP (child)));
Johannes Schmid's avatar
Johannes Schmid committed
891 892 893
        break;

      case CHILD_PROP_EXPAND:
894 895
        g_value_set_boolean (value, 
          gtk_tool_palette_get_expand (palette, GTK_TOOL_ITEM_GROUP (child)));
Johannes Schmid's avatar
Johannes Schmid committed
896 897 898 899 900 901 902 903
        break;

      default:
        GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
        break;
    }
}

904 905 906 907 908 909 910 911 912 913
static void
gtk_tool_palette_screen_changed (GtkWidget *widget,
                                 GdkScreen *previous_screen)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (widget);

  gtk_tool_palette_reconfigured (palette);
}


Johannes Schmid's avatar
Johannes Schmid committed
914 915 916 917 918 919 920 921 922 923 924 925
static void
gtk_tool_palette_class_init (GtkToolPaletteClass *cls)
{
  GObjectClass      *oclass   = G_OBJECT_CLASS (cls);
  GtkWidgetClass    *wclass   = GTK_WIDGET_CLASS (cls);
  GtkContainerClass *cclass   = GTK_CONTAINER_CLASS (cls);

  oclass->set_property        = gtk_tool_palette_set_property;
  oclass->get_property        = gtk_tool_palette_get_property;
  oclass->dispose             = gtk_tool_palette_dispose;
  oclass->finalize            = gtk_tool_palette_finalize;

926 927
  wclass->get_preferred_width = gtk_tool_palette_get_preferred_width;
  wclass->get_preferred_height= gtk_tool_palette_get_preferred_height;
Johannes Schmid's avatar
Johannes Schmid committed
928 929
  wclass->size_allocate       = gtk_tool_palette_size_allocate;
  wclass->realize             = gtk_tool_palette_realize;
930
  wclass->draw                = gtk_tool_palette_draw;
Johannes Schmid's avatar
Johannes Schmid committed
931 932 933 934 935 936 937 938

  cclass->add                 = gtk_tool_palette_add;
  cclass->remove              = gtk_tool_palette_remove;
  cclass->forall              = gtk_tool_palette_forall;
  cclass->child_type          = gtk_tool_palette_child_type;
  cclass->set_child_property  = gtk_tool_palette_set_child_property;
  cclass->get_child_property  = gtk_tool_palette_get_child_property;

939
  /* Handle screen-changed so we can update our configuration.
940 941
   */
  wclass->screen_changed      = gtk_tool_palette_screen_changed;
942

943
  g_object_class_override_property (oclass, PROP_ORIENTATION,    "orientation");
944

945 946 947 948
  g_object_class_override_property (oclass, PROP_HADJUSTMENT,    "hadjustment");
  g_object_class_override_property (oclass, PROP_VADJUSTMENT,    "vadjustment");
  g_object_class_override_property (oclass, PROP_HSCROLL_POLICY, "hscroll-policy");
  g_object_class_override_property (oclass, PROP_VSCROLL_POLICY, "vscroll-policy");
949

950
  /**
951 952
   * GtkToolPalette:icon-size:
   *
953 954
   * The size of the icons in a tool palette. When this property is set,
   * it overrides the default setting.
955
   *
956 957
   * This should only be used for special-purpose tool palettes, normal
   * application tool palettes should respect the user preferences for the
958 959
   * size of icons.
   *
960
   * Since: 2.20
961 962 963
   */
  g_object_class_install_property (oclass,
                                   PROP_ICON_SIZE,
Johannes Schmid's avatar
Johannes Schmid committed
964
                                   g_param_spec_enum ("icon-size",
965 966
                                                      P_("Icon size"),
                                                      P_("Size of icons in this tool palette"),
Johannes Schmid's avatar
Johannes Schmid committed
967 968
                                                      GTK_TYPE_ICON_SIZE,
                                                      DEFAULT_ICON_SIZE,
969
                                                      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
Johannes Schmid's avatar
Johannes Schmid committed
970

971
  /**
Matthias Clasen's avatar
Matthias Clasen committed
972
   * GtkToolPalette:icon-size-set:
973
   *
974
   * Is %TRUE if the #GtkToolPalette:icon-size property has been set.
975
   *
976
   * Since: 2.20
977 978 979 980
   */
  g_object_class_install_property (oclass,
                                   PROP_ICON_SIZE_SET,
                                   g_param_spec_boolean ("icon-size-set",
981 982 983 984
                                                         P_("Icon size set"),
                                                         P_("Whether the icon-size property has been set"),
                                                         FALSE,
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
985

986 987 988 989 990 991 992
  /**
   * GtkToolPalette:toolbar-style:
   *
   * The style of items in the tool palette.
   *
   * Since: 2.20
   */
Johannes Schmid's avatar
Johannes Schmid committed
993 994 995 996 997 998
  g_object_class_install_property (oclass, PROP_TOOLBAR_STYLE,
                                   g_param_spec_enum ("toolbar-style",
                                                      P_("Toolbar Style"),
                                                      P_("Style of items in the tool palette"),
                                                      GTK_TYPE_TOOLBAR_STYLE,
                                                      DEFAULT_TOOLBAR_STYLE,
999
                                                      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
1000

Johannes Schmid's avatar
Johannes Schmid committed
1001

1002 1003 1004 1005 1006 1007 1008 1009
  /**
   * GtkToolPalette:exclusive:
   *
   * Whether the item group should be the only one that is expanded
   * at a given time.
   *
   * Since: 2.20
   */
Johannes Schmid's avatar
Johannes Schmid committed
1010 1011 1012 1013 1014
  gtk_container_class_install_child_property (cclass, CHILD_PROP_EXCLUSIVE,
                                              g_param_spec_boolean ("exclusive",
                                                                    P_("Exclusive"),
                                                                    P_("Whether the item group should be the only expanded at a given time"),
                                                                    DEFAULT_CHILD_EXCLUSIVE,
1015
                                                                    GTK_PARAM_READWRITE));
Johannes Schmid's avatar
Johannes Schmid committed
1016

1017 1018 1019 1020 1021 1022 1023 1024
  /**
   * GtkToolPalette:expand:
   *
   * Whether the item group should receive extra space when the palette grows.
   * at a given time.
   *
   * Since: 2.20
   */
Johannes Schmid's avatar
Johannes Schmid committed
1025 1026 1027 1028 1029
  gtk_container_class_install_child_property (cclass, CHILD_PROP_EXPAND,
                                              g_param_spec_boolean ("expand",
                                                                    P_("Expand"),
                                                                    P_("Whether the item group should receive extra space when the palette grows"),
                                                                    DEFAULT_CHILD_EXPAND,
1030
                                                                    GTK_PARAM_READWRITE));
1031 1032

  gtk_widget_class_set_css_name (wclass, "toolpalette");
Johannes Schmid's avatar
Johannes Schmid committed
1033 1034 1035 1036 1037 1038 1039
}

/**
 * gtk_tool_palette_new:
 *
 * Creates a new tool palette.
 *
1040
 * Returns: a new #GtkToolPalette
Johannes Schmid's avatar
Johannes Schmid committed
1041
 *
1042
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1043 1044 1045 1046 1047 1048 1049 1050 1051
 */
GtkWidget*
gtk_tool_palette_new (void)
{
  return g_object_new (GTK_TYPE_TOOL_PALETTE, NULL);
}

/**
 * gtk_tool_palette_set_icon_size:
1052
 * @palette: a #GtkToolPalette
1053 1054
 * @icon_size: (type int): the #GtkIconSize that icons in the tool
 *     palette shall have
Johannes Schmid's avatar
Johannes Schmid committed
1055 1056 1057
 *
 * Sets the size of icons in the tool palette.
 *
1058
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1059 1060 1061 1062 1063
 */
void
gtk_tool_palette_set_icon_size (GtkToolPalette *palette,
                                GtkIconSize     icon_size)
{
1064
  GtkToolPalettePrivate *priv;
1065

Johannes Schmid's avatar
Johannes Schmid committed
1066
  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1067 1068 1069
  g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);

  priv = palette->priv;
1070

1071 1072
  if (!priv->icon_size_set)
    {
1073
      priv->icon_size_set = TRUE;
1074 1075
      g_object_notify (G_OBJECT (palette), "icon-size-set");
    }
Johannes Schmid's avatar
Johannes Schmid committed
1076

1077 1078
  if (priv->icon_size == icon_size)
    return;
1079

1080 1081
  priv->icon_size = icon_size;
  g_object_notify (G_OBJECT (palette), "icon-size");
1082

1083
  gtk_tool_palette_reconfigured (palette);
1084

1085 1086 1087
  gtk_widget_queue_resize (GTK_WIDGET (palette));
}

Johannes Schmid's avatar
Johannes Schmid committed
1088
/**
1089
 * gtk_tool_palette_unset_icon_size:
1090
 * @palette: a #GtkToolPalette
1091
 *
1092 1093
 * Unsets the tool palette icon size set with gtk_tool_palette_set_icon_size(),
 * so that user preferences will be used to determine the icon size.
1094
 *
1095
 * Since: 2.20
1096 1097 1098 1099 1100 1101
 */
void
gtk_tool_palette_unset_icon_size (GtkToolPalette *palette)
{
  GtkToolPalettePrivate* priv = palette->priv;
  GtkIconSize size;
1102

1103
  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1104

1105 1106
  if (palette->priv->icon_size_set)
    {
1107
      size = DEFAULT_ICON_SIZE;
1108

1109 1110 1111
      if (size != palette->priv->icon_size)
      {
        gtk_tool_palette_set_icon_size (palette, size);
1112
        g_object_notify (G_OBJECT (palette), "icon-size");
1113
      }
1114

1115
      priv->icon_size_set = FALSE;
1116
      g_object_notify (G_OBJECT (palette), "icon-size-set");
1117 1118 1119 1120
    }
}

/* Set the "toolbar-style" property and do appropriate things.
1121 1122
 * GtkToolbar does this by emitting a signal instead of just
 * calling a function...
1123 1124
 */
static void
1125 1126
gtk_tool_palette_change_style (GtkToolPalette  *palette,
                               GtkToolbarStyle  style)
1127 1128
{
  GtkToolPalettePrivate* priv = palette->priv;
1129

1130 1131 1132
  if (priv->style != style)
    {
      priv->style = style;
1133

1134
      gtk_tool_palette_reconfigured (palette);
1135

1136 1137 1138 1139 1140 1141 1142 1143
      gtk_widget_queue_resize (GTK_WIDGET (palette));
      g_object_notify (G_OBJECT (palette), "toolbar-style");
    }
}


/**
 * gtk_tool_palette_set_style:
1144 1145
 * @palette: a #GtkToolPalette
 * @style: the #GtkToolbarStyle that items in the tool palette shall have
Johannes Schmid's avatar
Johannes Schmid committed
1146 1147 1148
 *
 * Sets the style (text, icons or both) of items in the tool palette.
 *
1149
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1150 1151 1152 1153 1154 1155 1156
 */
void
gtk_tool_palette_set_style (GtkToolPalette  *palette,
                            GtkToolbarStyle  style)
{
  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));

1157
  palette->priv->style_set = TRUE;
1158 1159 1160 1161 1162 1163
  gtk_tool_palette_change_style (palette, style);
}


/**
 * gtk_tool_palette_unset_style:
1164 1165 1166 1167
 * @palette: a #GtkToolPalette
 *
 * Unsets a toolbar style set with gtk_tool_palette_set_style(),
 * so that user preferences will be used to determine the toolbar style.
1168
 *
1169 1170
 * Since: 2.20
 */
1171 1172 1173 1174 1175
void
gtk_tool_palette_unset_style (GtkToolPalette *palette)
{
  GtkToolPalettePrivate* priv = palette->priv;
  GtkToolbarStyle style;
1176

1177
  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1178

1179 1180
  if (priv->style_set)
    {
1181
      style = DEFAULT_TOOLBAR_STYLE;
1182

1183 1184
      if (style != priv->style)
        gtk_tool_palette_change_style (palette, style);
1185

1186 1187
      priv->style_set = FALSE;
    }
Johannes Schmid's avatar
Johannes Schmid committed
1188 1189 1190 1191
}

/**
 * gtk_tool_palette_get_icon_size:
1192
 * @palette: a #GtkToolPalette
Johannes Schmid's avatar
Johannes Schmid committed
1193
 *
1194 1195
 * Gets the size of icons in the tool palette.
 * See gtk_tool_palette_set_icon_size().
1196
 *
1197
 * Returns: (type int): the #GtkIconSize of icons in the tool palette
Johannes Schmid's avatar
Johannes Schmid committed
1198
 *
1199
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1200 1201 1202 1203 1204
 */
GtkIconSize
gtk_tool_palette_get_icon_size (GtkToolPalette *palette)
{
  g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_ICON_SIZE);
1205

Johannes Schmid's avatar
Johannes Schmid committed
1206 1207 1208 1209 1210
  return palette->priv->icon_size;
}

/**
 * gtk_tool_palette_get_style:
1211
 * @palette: a #GtkToolPalette
Johannes Schmid's avatar
Johannes Schmid committed
1212 1213 1214 1215 1216
 *
 * Gets the style (icons, text or both) of items in the tool palette.
 *
 * Returns: the #GtkToolbarStyle of items in the tool palette.
 *
1217
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1218 1219 1220 1221 1222
 */
GtkToolbarStyle
gtk_tool_palette_get_style (GtkToolPalette *palette)
{
  g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_TOOLBAR_STYLE);
1223

Johannes Schmid's avatar
Johannes Schmid committed
1224 1225 1226
  return palette->priv->style;
}

1227 1228 1229
static gint
gtk_tool_palette_compare_groups (gconstpointer a,
                                 gconstpointer b)
1230 1231 1232 1233 1234 1235 1236
{
  const GtkToolItemGroupInfo *group_a = a;
  const GtkToolItemGroupInfo *group_b = b;

  return group_a->pos - group_b->pos;
}

Johannes Schmid's avatar
Johannes Schmid committed
1237 1238
/**
 * gtk_tool_palette_set_group_position:
1239 1240 1241
 * @palette: a #GtkToolPalette
 * @group: a #GtkToolItemGroup which is a child of palette
 * @position: a new index for group
Johannes Schmid's avatar
Johannes Schmid committed
1242 1243 1244 1245 1246
 *
 * Sets the position of the group as an index of the tool palette.
 * If position is 0 the group will become the first child, if position is
 * -1 it will become the last child.
 *
1247
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1248 1249
 */
void
1250 1251 1252
gtk_tool_palette_set_group_position (GtkToolPalette   *palette,
                                     GtkToolItemGroup *group,
                                     gint             position)
Johannes Schmid's avatar
Johannes Schmid committed
1253
{
1254
  GtkToolItemGroupInfo *group_new;
1255
  GtkToolItemGroupInfo *group_old;
Johannes Schmid's avatar
Johannes Schmid committed
1256 1257 1258 1259 1260 1261 1262
  gint old_position;

  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
  g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group));
  g_return_if_fail (position >= -1);

  if (-1 == position)
1263
    position = palette->priv->groups->len - 1;
Johannes Schmid's avatar
Johannes Schmid committed
1264

1265
  g_return_if_fail ((guint) position < palette->priv->groups->len);
Johannes Schmid's avatar
Johannes Schmid committed
1266

1267
  group_new = g_ptr_array_index (palette->priv->groups, position);
1268

1269
  if (GTK_TOOL_ITEM_GROUP (group) == group_new->widget)
Johannes Schmid's avatar
Johannes Schmid committed
1270 1271
    return;

1272
  old_position = gtk_tool_palette_get_group_position (palette, group);
Johannes Schmid's avatar
Johannes Schmid committed
1273 1274
  g_return_if_fail (old_position >= 0);

1275
  group_old = g_ptr_array_index (palette->priv->groups, old_position);
Johannes Schmid's avatar
Johannes Schmid committed
1276

1277 1278
  group_new->pos = position;
  group_old->pos = old_position;
Johannes Schmid's avatar
Johannes Schmid committed
1279

1280
  g_ptr_array_sort (palette->priv->groups, gtk_tool_palette_compare_groups);
Johannes Schmid's avatar
Johannes Schmid committed
1281 1282 1283 1284 1285 1286

  gtk_widget_queue_resize (GTK_WIDGET (palette));
}

static void
gtk_tool_palette_group_notify_collapsed (GtkToolItemGroup *group,
Johannes Schmid's avatar
Johannes Schmid committed
1287
                                         GParamSpec       *pspec,
Johannes Schmid's avatar
Johannes Schmid committed
1288 1289 1290 1291 1292 1293 1294 1295
                                         gpointer          data)
{
  GtkToolPalette *palette = GTK_TOOL_PALETTE (data);
  guint i;

  if (gtk_tool_item_group_get_collapsed (group))
    return;

1296
  for (i = 0; i < palette->priv->groups->len; ++i)
Johannes Schmid's avatar
Johannes Schmid committed
1297
    {
1298 1299
      GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
      GtkToolItemGroup *current_group = info->widget;
Johannes Schmid's avatar
Johannes Schmid committed
1300 1301

      if (current_group && current_group != group)
1302
        gtk_tool_item_group_set_collapsed (current_group, TRUE);
Johannes Schmid's avatar
Johannes Schmid committed
1303 1304 1305 1306 1307
    }
}

/**
 * gtk_tool_palette_set_exclusive:
1308 1309 1310
 * @palette: a #GtkToolPalette
 * @group: a #GtkToolItemGroup which is a child of palette
 * @exclusive: whether the group should be exclusive or not
Johannes Schmid's avatar
Johannes Schmid committed
1311
 *
1312 1313
 * Sets whether the group should be exclusive or not.
 * If an exclusive group is expanded all other groups are collapsed.
Johannes Schmid's avatar
Johannes Schmid committed
1314
 *
1315
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1316 1317
 */
void
1318 1319 1320
gtk_tool_palette_set_exclusive (GtkToolPalette   *palette,
                                GtkToolItemGroup *group,
                                gboolean          exclusive)
Johannes Schmid's avatar
Johannes Schmid committed
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
{
  GtkToolItemGroupInfo *group_info;
  gint position;

  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
  g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group));

  position = gtk_tool_palette_get_group_position (palette, group);
  g_return_if_fail (position >= 0);

1331
  group_info = g_ptr_array_index (palette->priv->groups, position);
Johannes Schmid's avatar
Johannes Schmid committed
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354

  if (exclusive == group_info->exclusive)
    return;

  group_info->exclusive = exclusive;

  if (group_info->exclusive != (0 != group_info->notify_collapsed))
    {
      if (group_info->exclusive)
        {
          group_info->notify_collapsed =
            g_signal_connect (group, "notify::collapsed",
                              G_CALLBACK (gtk_tool_palette_group_notify_collapsed),
                              palette);
        }
      else
        {
          g_signal_handler_disconnect (group, group_info->notify_collapsed);
          group_info->notify_collapsed = 0;
        }
    }

  gtk_tool_palette_group_notify_collapsed (group_info->widget, NULL, palette);
1355
  gtk_widget_child_notify (GTK_WIDGET (group), "exclusive");
Johannes Schmid's avatar
Johannes Schmid committed
1356 1357 1358 1359
}

/**
 * gtk_tool_palette_set_expand:
1360 1361 1362
 * @palette: a #GtkToolPalette
 * @group: a #GtkToolItemGroup which is a child of palette
 * @expand: whether the group should be given extra space
Johannes Schmid's avatar
Johannes Schmid committed
1363 1364 1365
 *
 * Sets whether the group should be given extra space.
 *
1366
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1367 1368
 */
void
1369 1370
gtk_tool_palette_set_expand (GtkToolPalette   *palette,
                             GtkToolItemGroup *group,
Johannes Schmid's avatar
Johannes Schmid committed
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
                             gboolean        expand)
{
  GtkToolItemGroupInfo *group_info;
  gint position;

  g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
  g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group));

  position = gtk_tool_palette_get_group_position (palette, group);
  g_return_if_fail (position >= 0);

1382
  group_info = g_ptr_array_index (palette->priv->groups, position);
Johannes Schmid's avatar
Johannes Schmid committed
1383 1384 1385 1386 1387

  if (expand != group_info->expand)
    {
      group_info->expand = expand;
      gtk_widget_queue_resize (GTK_WIDGET (palette));
1388
      gtk_widget_child_notify (GTK_WIDGET (group), "expand");
Johannes Schmid's avatar
Johannes Schmid committed
1389 1390 1391 1392 1393
    }
}

/**
 * gtk_tool_palette_get_group_position:
1394 1395
 * @palette: a #GtkToolPalette
 * @group: a #GtkToolItemGroup
Johannes Schmid's avatar
Johannes Schmid committed
1396
 *
1397 1398
 * Gets the position of @group in @palette as index.
 * See gtk_tool_palette_set_group_position().
Johannes Schmid's avatar
Johannes Schmid committed
1399
 *
1400
 * Returns: the index of group or -1 if @group is not a child of @palette
Johannes Schmid's avatar
Johannes Schmid committed
1401
 *
1402
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1403 1404
 */
gint
1405 1406
gtk_tool_palette_get_group_position (GtkToolPalette   *palette,
                                     GtkToolItemGroup *group)
Johannes Schmid's avatar
Johannes Schmid committed
1407 1408 1409 1410 1411 1412
{
  guint i;

  g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), -1);
  g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), -1);

1413 1414 1415 1416 1417 1418
  for (i = 0; i < palette->priv->groups->len; ++i)
    {
      GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
      if ((gpointer) group == info->widget)
        return i;
    }
Johannes Schmid's avatar
Johannes Schmid committed
1419 1420 1421 1422 1423 1424

  return -1;
}

/**
 * gtk_tool_palette_get_exclusive:
1425 1426
 * @palette: a #GtkToolPalette
 * @group: a #GtkToolItemGroup which is a child of palette
Johannes Schmid's avatar
Johannes Schmid committed
1427
 *
1428 1429
 * Gets whether @group is exclusive or not.
 * See gtk_tool_palette_set_exclusive().
Johannes Schmid's avatar
Johannes Schmid committed
1430
 *
1431
 * Returns: %TRUE if @group is exclusive
Johannes Schmid's avatar
Johannes Schmid committed
1432
 *
1433
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1434 1435
 */
gboolean
1436 1437
gtk_tool_palette_get_exclusive (GtkToolPalette   *palette,
                                GtkToolItemGroup *group)
Johannes Schmid's avatar
Johannes Schmid committed
1438 1439
{
  gint position;
1440
  GtkToolItemGroupInfo *info;
Johannes Schmid's avatar
Johannes Schmid committed
1441 1442 1443 1444 1445 1446 1447

  g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_CHILD_EXCLUSIVE);
  g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), DEFAULT_CHILD_EXCLUSIVE);

  position = gtk_tool_palette_get_group_position (palette, group);
  g_return_val_if_fail (position >= 0, DEFAULT_CHILD_EXCLUSIVE);

1448
  info = g_ptr_array_index (palette->priv->groups, position);
1449

1450
  return info->exclusive;
Johannes Schmid's avatar
Johannes Schmid committed
1451 1452 1453 1454
}

/**
 * gtk_tool_palette_get_expand:
1455 1456
 * @palette: a #GtkToolPalette
 * @group: a #GtkToolItemGroup which is a child of palette
Johannes Schmid's avatar
Johannes Schmid committed
1457
 *
1458 1459
 * Gets whether group should be given extra space.
 * See gtk_tool_palette_set_expand().
Johannes Schmid's avatar
Johannes Schmid committed
1460
 *
1461
 * Returns: %TRUE if group should be given extra space, %FALSE otherwise
Johannes Schmid's avatar
Johannes Schmid committed
1462
 *
1463
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1464 1465
 */
gboolean
1466 1467
gtk_tool_palette_get_expand (GtkToolPalette   *palette,
                             GtkToolItemGroup *group)
Johannes Schmid's avatar
Johannes Schmid committed
1468 1469
{
  gint position;
1470
  GtkToolItemGroupInfo *info;
Johannes Schmid's avatar
Johannes Schmid committed
1471 1472 1473 1474 1475 1476 1477

  g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_CHILD_EXPAND);
  g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), DEFAULT_CHILD_EXPAND);

  position = gtk_tool_palette_get_group_position (palette, group);
  g_return_val_if_fail (position >= 0, DEFAULT_CHILD_EXPAND);

1478
  info = g_ptr_array_index (palette->priv->groups, position);
1479

1480
  return info->expand;
Johannes Schmid's avatar
Johannes Schmid committed
1481 1482 1483 1484
}

/**
 * gtk_tool_palette_get_drop_item:
1485 1486 1487
 * @palette: a #GtkToolPalette
 * @x: the x position
 * @y: the y position
Johannes Schmid's avatar
Johannes Schmid committed
1488
 *
1489 1490
 * Gets the item at position (x, y).
 * See gtk_tool_palette_get_drop_group().
Johannes Schmid's avatar
Johannes Schmid committed
1491
 *
1492
 * Returns: (transfer none): the #GtkToolItem at position or %NULL if there is no such item
Johannes Schmid's avatar
Johannes Schmid committed
1493
 *
1494
 * Since: 2.20
Johannes Schmid's avatar
Johannes Schmid committed
1495 1496 1497 1498 1499 1500
 */
GtkToolItem*
gtk_tool_palette_get_drop_item (GtkToolPalette *palette,
                                gint            x,
                                gint            y)
{
1501
  GtkAllocation allocation;
1502 1503
  GtkToolItemGroup *group = gtk_tool_palette_get_drop_group (palette, x, y);
  GtkWidget *widget = GTK_WIDGET (group);
Johannes Schmid's avatar
Johannes Schmid committed
1504 1505

  if (group)
1506 1507 1508 1509 1510 1511
    {
      gtk_widget_get_allocation (widget, &allocation);
      return gtk_tool_item_group_get_drop_item (group,
                                                x - allocation.x,
                                                y - allocation.y);
    }
Johannes Schmid's avatar
Johannes Schmid committed
1512 1513 1514 1515 1516 1517

  return NULL;
}

/**
 * gtk_tool_palette_get_drop_group: