mirror of https://github.com/GNOME/gimp.git
1504 lines
45 KiB
C
1504 lines
45 KiB
C
/* LIBGIMP - The GIMP Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* gimppageselector.c
|
|
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* 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 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "gimpwidgetstypes.h"
|
|
|
|
#include "gimppageselector.h"
|
|
#include "gimppropwidgets.h"
|
|
#include "gimpstock.h"
|
|
#include "gimpwidgets.h"
|
|
|
|
#include "libgimp/libgimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
SELECTION_CHANGED,
|
|
ACTIVATE,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_N_PAGES,
|
|
PROP_TARGET
|
|
};
|
|
|
|
enum
|
|
{
|
|
COLUMN_PAGE_NO,
|
|
COLUMN_THUMBNAIL,
|
|
COLUMN_LABEL,
|
|
COLUMN_LABEL_SET
|
|
};
|
|
|
|
|
|
typedef struct
|
|
{
|
|
gint n_pages;
|
|
GimpPageSelectorTarget target;
|
|
|
|
GtkListStore *store;
|
|
GtkWidget *view;
|
|
|
|
GtkWidget *count_label;
|
|
GtkWidget *range_entry;
|
|
|
|
GdkPixbuf *default_thumbnail;
|
|
|
|
gint default_item_width;
|
|
gint max_item_width;
|
|
guint item_width_idle_id;
|
|
} GimpPageSelectorPrivate;
|
|
|
|
#define GIMP_PAGE_SELECTOR_GET_PRIVATE(obj) \
|
|
((GimpPageSelectorPrivate *) ((GimpPageSelector *) (obj))->priv)
|
|
|
|
|
|
static void gimp_page_selector_dispose (GObject *object);
|
|
static void gimp_page_selector_finalize (GObject *object);
|
|
static void gimp_page_selector_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_page_selector_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_page_selector_style_set (GtkWidget *widget,
|
|
GtkStyle *prev_style);
|
|
|
|
static void gimp_page_selector_selection_changed (GtkIconView *icon_view,
|
|
GimpPageSelector *selector);
|
|
static void gimp_page_selector_item_activated (GtkIconView *icon_view,
|
|
GtkTreePath *path,
|
|
GimpPageSelector *selector);
|
|
static gboolean gimp_page_selector_range_focus_out (GtkEntry *entry,
|
|
GdkEventFocus *fevent,
|
|
GimpPageSelector *selector);
|
|
static void gimp_page_selector_range_activate (GtkEntry *entry,
|
|
GimpPageSelector *selector);
|
|
static gint gimp_page_selector_int_compare (gconstpointer a,
|
|
gconstpointer b);
|
|
static void gimp_page_selector_print_range (GString *string,
|
|
gint start,
|
|
gint end);
|
|
|
|
static void gimp_page_selector_update_item_width (GimpPageSelector *selector);
|
|
static gboolean gimp_page_selector_item_width_idle (GimpPageSelector *selector);
|
|
|
|
static GdkPixbuf * gimp_page_selector_add_frame (GtkWidget *widget,
|
|
GdkPixbuf *pixbuf);
|
|
|
|
|
|
G_DEFINE_TYPE (GimpPageSelector, gimp_page_selector, GTK_TYPE_VBOX)
|
|
|
|
#define parent_class gimp_page_selector_parent_class
|
|
|
|
static guint selector_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
static void
|
|
gimp_page_selector_class_init (GimpPageSelectorClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->dispose = gimp_page_selector_dispose;
|
|
object_class->finalize = gimp_page_selector_finalize;
|
|
object_class->get_property = gimp_page_selector_get_property;
|
|
object_class->set_property = gimp_page_selector_set_property;
|
|
|
|
widget_class->style_set = gimp_page_selector_style_set;
|
|
|
|
klass->selection_changed = NULL;
|
|
klass->activate = NULL;
|
|
|
|
/**
|
|
* GimpPageSelector::selection-changed:
|
|
* @widget: the object which received the signal.
|
|
*
|
|
* This signal is emitted whenever the set of selected pages changes.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
selector_signals[SELECTION_CHANGED] =
|
|
g_signal_new ("selection-changed",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpPageSelectorClass, selection_changed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
/**
|
|
* GimpPageSelector::activate:
|
|
* @widget: the object which received the signal.
|
|
*
|
|
* The "activate" signal on GimpPageSelector is an action signal. It
|
|
* is emitted when a user double-clicks an item in the page selection.
|
|
*
|
|
* Since: GIMP 2.4
|
|
*/
|
|
selector_signals[ACTIVATE] =
|
|
g_signal_new ("activate",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
|
G_STRUCT_OFFSET (GimpPageSelectorClass, activate),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
widget_class->activate_signal = selector_signals[ACTIVATE];
|
|
|
|
/**
|
|
* GimpPageSelector:n-pages:
|
|
*
|
|
* The number of pages of the document to open.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
g_object_class_install_property (object_class, PROP_N_PAGES,
|
|
g_param_spec_int ("n-pages", NULL, NULL,
|
|
0, G_MAXINT, 0,
|
|
GIMP_PARAM_READWRITE));
|
|
|
|
/**
|
|
* GimpPageSelector:target:
|
|
*
|
|
* The target to open the document to.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
g_object_class_install_property (object_class, PROP_TARGET,
|
|
g_param_spec_enum ("target", NULL, NULL,
|
|
GIMP_TYPE_PAGE_SELECTOR_TARGET,
|
|
GIMP_PAGE_SELECTOR_TARGET_LAYERS,
|
|
GIMP_PARAM_READWRITE));
|
|
|
|
g_type_class_add_private (object_class, sizeof (GimpPageSelectorPrivate));
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_init (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkWidget *vbox;
|
|
GtkWidget *sw;
|
|
GtkWidget *hbox;
|
|
GtkWidget *hbbox;
|
|
GtkWidget *button;
|
|
GtkWidget *label;
|
|
GtkWidget *combo;
|
|
|
|
selector->priv = G_TYPE_INSTANCE_GET_PRIVATE (selector,
|
|
GIMP_TYPE_PAGE_SELECTOR,
|
|
GimpPageSelectorPrivate);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
priv->n_pages = 0;
|
|
priv->target = GIMP_PAGE_SELECTOR_TARGET_LAYERS;
|
|
|
|
gtk_box_set_spacing (GTK_BOX (selector), 12);
|
|
|
|
/* Pages */
|
|
|
|
vbox = gtk_vbox_new (FALSE, 2);
|
|
gtk_box_pack_start (GTK_BOX (selector), vbox, TRUE, TRUE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
sw = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
|
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
|
|
gtk_widget_show (sw);
|
|
|
|
priv->store = gtk_list_store_new (4,
|
|
G_TYPE_INT,
|
|
GDK_TYPE_PIXBUF,
|
|
G_TYPE_STRING,
|
|
G_TYPE_BOOLEAN);
|
|
|
|
priv->view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (priv->store));
|
|
gtk_icon_view_set_text_column (GTK_ICON_VIEW (priv->view),
|
|
COLUMN_LABEL);
|
|
gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (priv->view),
|
|
COLUMN_THUMBNAIL);
|
|
gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (priv->view),
|
|
GTK_SELECTION_MULTIPLE);
|
|
gtk_container_add (GTK_CONTAINER (sw), priv->view);
|
|
gtk_widget_show (priv->view);
|
|
|
|
g_signal_connect (priv->view, "selection-changed",
|
|
G_CALLBACK (gimp_page_selector_selection_changed),
|
|
selector);
|
|
g_signal_connect (priv->view, "item-activated",
|
|
G_CALLBACK (gimp_page_selector_item_activated),
|
|
selector);
|
|
|
|
/* Count label */
|
|
|
|
priv->count_label = gtk_label_new (_("Nothing selected"));
|
|
gtk_misc_set_alignment (GTK_MISC (priv->count_label), 0.0, 0.5);
|
|
gimp_label_set_attributes (GTK_LABEL (priv->count_label),
|
|
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
|
|
-1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), priv->count_label, FALSE, FALSE, 0);
|
|
gtk_widget_show (priv->count_label);
|
|
|
|
/* Select all button & range entry */
|
|
|
|
hbox = gtk_hbox_new (FALSE, 6);
|
|
gtk_box_pack_start (GTK_BOX (selector), hbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
hbbox = gtk_hbutton_box_new ();
|
|
gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbbox);
|
|
|
|
button = gtk_button_new_with_mnemonic (_("Select _All"));
|
|
gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
|
|
gtk_widget_show (button);
|
|
|
|
g_signal_connect_swapped (button, "clicked",
|
|
G_CALLBACK (gimp_page_selector_select_all),
|
|
selector);
|
|
|
|
priv->range_entry = gtk_entry_new ();
|
|
gtk_widget_set_size_request (priv->range_entry, 80, -1);
|
|
gtk_box_pack_end (GTK_BOX (hbox), priv->range_entry, TRUE, TRUE, 0);
|
|
gtk_widget_show (priv->range_entry);
|
|
|
|
g_signal_connect (priv->range_entry, "focus-out-event",
|
|
G_CALLBACK (gimp_page_selector_range_focus_out),
|
|
selector);
|
|
g_signal_connect (priv->range_entry, "activate",
|
|
G_CALLBACK (gimp_page_selector_range_activate),
|
|
selector);
|
|
|
|
label = gtk_label_new_with_mnemonic (_("Select _range:"));
|
|
gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->range_entry);
|
|
|
|
/* Target combo */
|
|
|
|
hbox = gtk_hbox_new (FALSE, 6);
|
|
gtk_box_pack_start (GTK_BOX (selector), hbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
label = gtk_label_new_with_mnemonic (_("Open _pages as"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
combo = gimp_prop_enum_combo_box_new (G_OBJECT (selector), "target", -1, -1);
|
|
gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
|
|
gtk_widget_show (combo);
|
|
|
|
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
|
|
|
priv->default_thumbnail = gtk_widget_render_icon (GTK_WIDGET (selector),
|
|
GTK_STOCK_FILE,
|
|
GTK_ICON_SIZE_DND,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_dispose (GObject *object)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
|
|
|
|
if (priv->item_width_idle_id)
|
|
{
|
|
g_source_remove (priv->item_width_idle_id);
|
|
priv->item_width_idle_id = 0;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_finalize (GObject *object)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
|
|
|
|
if (priv->default_thumbnail)
|
|
g_object_unref (priv->default_thumbnail);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_N_PAGES:
|
|
g_value_set_int (value, priv->n_pages);
|
|
break;
|
|
case PROP_TARGET:
|
|
g_value_set_enum (value, priv->target);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpPageSelector *selector = GIMP_PAGE_SELECTOR (object);
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_N_PAGES:
|
|
gimp_page_selector_set_n_pages (selector, g_value_get_int (value));
|
|
break;
|
|
case PROP_TARGET:
|
|
priv->target = g_value_get_enum (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_style_set (GtkWidget *widget,
|
|
GtkStyle *prev_style)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (widget);
|
|
PangoLayout *layout;
|
|
PangoRectangle ink_rect;
|
|
PangoRectangle logical_rect;
|
|
gint focus_line_width;
|
|
gint focus_padding;
|
|
gint item_width;
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->style_set)
|
|
GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
|
|
|
|
layout = gtk_widget_create_pango_layout (widget, _("Page 000"));
|
|
pango_layout_get_extents (layout, &ink_rect, &logical_rect);
|
|
g_object_unref (layout);
|
|
|
|
gtk_widget_style_get (widget,
|
|
"focus-line-width", &focus_line_width,
|
|
"focus-padding", &focus_padding,
|
|
NULL);
|
|
|
|
#define ICON_TEXT_PADDING 3 /* EEK */
|
|
|
|
item_width = MAX (priv->default_thumbnail ?
|
|
gdk_pixbuf_get_width (priv->default_thumbnail) : 0,
|
|
PANGO_PIXELS (MAX (ink_rect.width,
|
|
logical_rect.width)) +
|
|
2 * (focus_line_width + focus_padding +
|
|
ICON_TEXT_PADDING));
|
|
|
|
if (item_width != priv->default_item_width)
|
|
{
|
|
priv->default_item_width = item_width;
|
|
|
|
gtk_icon_view_set_item_width (GTK_ICON_VIEW (priv->view),
|
|
MAX (priv->default_item_width,
|
|
priv->max_item_width));
|
|
}
|
|
}
|
|
|
|
|
|
/* public functions */
|
|
|
|
/**
|
|
* gimp_page_selector_new:
|
|
*
|
|
* Creates a new #GimpPageSelector widget.
|
|
*
|
|
* Returns: Pointer to the new #GimpPageSelector widget.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
GtkWidget *
|
|
gimp_page_selector_new (void)
|
|
{
|
|
GimpPageSelector *selector;
|
|
|
|
selector = g_object_new (GIMP_TYPE_PAGE_SELECTOR, NULL);
|
|
|
|
return GTK_WIDGET (selector);
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_set_n_pages:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @n_pages: The number of pages.
|
|
*
|
|
* Sets the number of pages in the document to open.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_set_n_pages (GimpPageSelector *selector,
|
|
gint n_pages)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
g_return_if_fail (n_pages >= 0);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
if (n_pages != priv->n_pages)
|
|
{
|
|
GtkTreeIter iter;
|
|
gint i;
|
|
|
|
if (n_pages < priv->n_pages)
|
|
{
|
|
for (i = n_pages; i < priv->n_pages; i++)
|
|
{
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, n_pages);
|
|
gtk_list_store_remove (priv->store, &iter);
|
|
}
|
|
|
|
gimp_page_selector_update_item_width (selector);
|
|
}
|
|
else
|
|
{
|
|
for (i = priv->n_pages; i < n_pages; i++)
|
|
{
|
|
gchar *text;
|
|
|
|
text = g_strdup_printf (_("Page %d"), i + 1);
|
|
|
|
gtk_list_store_append (priv->store, &iter);
|
|
gtk_list_store_set (priv->store, &iter,
|
|
COLUMN_PAGE_NO, i,
|
|
COLUMN_THUMBNAIL, priv->default_thumbnail,
|
|
COLUMN_LABEL, text,
|
|
COLUMN_LABEL_SET, FALSE,
|
|
-1);
|
|
|
|
g_free (text);
|
|
}
|
|
}
|
|
|
|
priv->n_pages = n_pages;
|
|
|
|
g_object_notify (G_OBJECT (selector), "n-pages");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_get_n_pages:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
*
|
|
* Returns: the number of pages in the document to open.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
gint
|
|
gimp_page_selector_get_n_pages (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), 0);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
return priv->n_pages;
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_set_target:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @target: How to open the selected pages.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_set_target (GimpPageSelector *selector,
|
|
GimpPageSelectorTarget target)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
g_return_if_fail (target >= GIMP_PAGE_SELECTOR_TARGET_LAYERS &&
|
|
target <= GIMP_PAGE_SELECTOR_TARGET_IMAGES);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
if (target != priv->target)
|
|
{
|
|
priv->target = target;
|
|
|
|
g_object_notify (G_OBJECT (selector), "target");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_get_target:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
*
|
|
* Returns: How the selected pages should be opened.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
GimpPageSelectorTarget
|
|
gimp_page_selector_get_target (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector),
|
|
GIMP_PAGE_SELECTOR_TARGET_LAYERS);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
return priv->target;
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_set_page_thumbnail:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to set the thumbnail for.
|
|
* @thumbnail: The thumbnail pixbuf.
|
|
*
|
|
* Sets the thumbnail for given %page_no. A default "page" icon will
|
|
* be used if no page thumbnail is set.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_set_page_thumbnail (GimpPageSelector *selector,
|
|
gint page_no,
|
|
GdkPixbuf *thumbnail)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
g_return_if_fail (thumbnail == NULL || GDK_IS_PIXBUF (thumbnail));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
|
|
if (! thumbnail)
|
|
{
|
|
thumbnail = g_object_ref (priv->default_thumbnail);
|
|
|
|
gimp_page_selector_update_item_width (selector);
|
|
}
|
|
else
|
|
{
|
|
gint focus_line_width;
|
|
gint focus_padding;
|
|
gint width;
|
|
|
|
thumbnail = gimp_page_selector_add_frame (GTK_WIDGET (selector),
|
|
thumbnail);
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (selector),
|
|
"focus-line-width", &focus_line_width,
|
|
"focus-padding", &focus_padding,
|
|
NULL);
|
|
|
|
width = gdk_pixbuf_get_width (thumbnail) + 2 * (focus_line_width +
|
|
focus_padding);
|
|
|
|
if (width > priv->max_item_width)
|
|
{
|
|
priv->max_item_width = width;
|
|
|
|
gtk_icon_view_set_item_width (GTK_ICON_VIEW (priv->view),
|
|
MAX (priv->default_item_width,
|
|
priv->max_item_width));
|
|
}
|
|
else if (width < priv->max_item_width)
|
|
{
|
|
GdkPixbuf *old;
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
|
|
COLUMN_THUMBNAIL, &old,
|
|
-1);
|
|
|
|
if (old)
|
|
{
|
|
if (gdk_pixbuf_get_width (old) == priv->max_item_width)
|
|
gimp_page_selector_update_item_width (selector);
|
|
|
|
g_object_unref (old);
|
|
}
|
|
}
|
|
}
|
|
|
|
gtk_list_store_set (priv->store, &iter,
|
|
COLUMN_THUMBNAIL, thumbnail,
|
|
-1);
|
|
g_object_unref (thumbnail);
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_get_page_thumbnail:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to get the thumbnail for.
|
|
*
|
|
* Returns: The page's thumbnail, or %NULL if none is set. The returned
|
|
* pixbuf is owned by #GimpPageSelector and must not be
|
|
* unref'ed when no longer needed.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
GdkPixbuf *
|
|
gimp_page_selector_get_page_thumbnail (GimpPageSelector *selector,
|
|
gint page_no)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GdkPixbuf *thumbnail;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, NULL);
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
|
|
COLUMN_THUMBNAIL, &thumbnail,
|
|
-1);
|
|
|
|
if (thumbnail)
|
|
g_object_unref (thumbnail);
|
|
|
|
if (thumbnail == priv->default_thumbnail)
|
|
return NULL;
|
|
|
|
return thumbnail;
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_set_page_label:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to set the label for.
|
|
* @label: The label.
|
|
*
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_set_page_label (GimpPageSelector *selector,
|
|
gint page_no,
|
|
const gchar *label)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkTreeIter iter;
|
|
gchar *tmp;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
|
|
|
|
if (! label)
|
|
tmp = g_strdup_printf (_("Page %d"), page_no + 1);
|
|
else
|
|
tmp = (gchar *) label;
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
gtk_list_store_set (priv->store, &iter,
|
|
COLUMN_LABEL, tmp,
|
|
COLUMN_LABEL_SET, label != NULL,
|
|
-1);
|
|
|
|
if (! label)
|
|
g_free (tmp);
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_get_page_label:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to get the thumbnail for.
|
|
*
|
|
* Returns: The page's label, or %NULL if none is set. This is a newly
|
|
* allocated string that should be g_free()'d when no longer
|
|
* needed.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
gchar *
|
|
gimp_page_selector_get_page_label (GimpPageSelector *selector,
|
|
gint page_no)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkTreeIter iter;
|
|
gchar *label;
|
|
gboolean label_set;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, NULL);
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
|
|
COLUMN_LABEL, &label,
|
|
COLUMN_LABEL_SET, &label_set,
|
|
-1);
|
|
|
|
if (! label_set)
|
|
{
|
|
g_free (label);
|
|
label = NULL;
|
|
}
|
|
|
|
return label;
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_select_all:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
*
|
|
* Selects all pages.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_select_all (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
gtk_icon_view_select_all (GTK_ICON_VIEW (priv->view));
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_unselect_all:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
*
|
|
* Unselects all pages.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_unselect_all (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
gtk_icon_view_unselect_all (GTK_ICON_VIEW (priv->view));
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_select_page:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to select.
|
|
*
|
|
* Adds a page to the selection.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_select_page (GimpPageSelector *selector,
|
|
gint page_no)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
|
|
|
|
gtk_icon_view_select_path (GTK_ICON_VIEW (priv->view), path);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_unselect_page:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to unselect.
|
|
*
|
|
* Removes a page from the selection.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_unselect_page (GimpPageSelector *selector,
|
|
gint page_no)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
|
|
|
|
gtk_icon_view_unselect_path (GTK_ICON_VIEW (priv->view), path);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_page_is_selected:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @page_no: The number of the page to check.
|
|
*
|
|
* Returns: %TRUE if the page is selected, %FALSE otherwise.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
gboolean
|
|
gimp_page_selector_page_is_selected (GimpPageSelector *selector,
|
|
gint page_no)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
gboolean selected;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), FALSE);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, FALSE);
|
|
|
|
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
|
|
&iter, NULL, page_no);
|
|
path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
|
|
|
|
selected = gtk_icon_view_path_is_selected (GTK_ICON_VIEW (priv->view),
|
|
path);
|
|
|
|
gtk_tree_path_free (path);
|
|
|
|
return selected;
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_get_selected_pages:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @n_selected_pages: Returns the number of selected pages.
|
|
*
|
|
* Returns: A sorted array of page numbers of selected pages. Use g_free() if
|
|
* you don't need the array any longer.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
gint *
|
|
gimp_page_selector_get_selected_pages (GimpPageSelector *selector,
|
|
gint *n_selected_pages)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
GList *selected;
|
|
GList *list;
|
|
gint *array;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
|
|
g_return_val_if_fail (n_selected_pages != NULL, NULL);
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->view));
|
|
|
|
*n_selected_pages = g_list_length (selected);
|
|
array = g_new0 (gint, *n_selected_pages);
|
|
|
|
for (list = selected, i = 0; list; list = g_list_next (list), i++)
|
|
{
|
|
gint *indices = gtk_tree_path_get_indices (list->data);
|
|
|
|
array[i] = indices[0];
|
|
}
|
|
|
|
qsort (array, *n_selected_pages, sizeof (gint),
|
|
gimp_page_selector_int_compare);
|
|
|
|
g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
|
|
g_list_free (selected);
|
|
|
|
return array;
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_select_range:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
* @range: A string representing the set of selected pages.
|
|
*
|
|
* Selectes the pages described by %range. The range string is a
|
|
* user-editable list of pages and ranges, e.g. "1,3,5-7,9-12,14".
|
|
* Note that the page numbering in the range string starts with 1,
|
|
* not 0.
|
|
*
|
|
* Invalid pages and ranges will be silently ignored, duplicate and
|
|
* overlapping pages and ranges will be merged.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
void
|
|
gimp_page_selector_select_range (GimpPageSelector *selector,
|
|
const gchar *range)
|
|
{
|
|
GimpPageSelectorPrivate *priv;
|
|
gchar **ranges;
|
|
|
|
g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
|
|
|
|
priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
if (! range)
|
|
range = "";
|
|
|
|
g_signal_handlers_block_by_func (priv->view,
|
|
gimp_page_selector_selection_changed,
|
|
selector);
|
|
|
|
gimp_page_selector_unselect_all (selector);
|
|
|
|
ranges = g_strsplit (range, ",", -1);
|
|
|
|
if (ranges)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; ranges[i] != NULL; i++)
|
|
{
|
|
gchar *range = g_strstrip (ranges[i]);
|
|
gchar *dash;
|
|
|
|
dash = strchr (range, '-');
|
|
|
|
if (dash)
|
|
{
|
|
gchar *from;
|
|
gchar *to;
|
|
gint page_from = -1;
|
|
gint page_to = -1;
|
|
|
|
*dash = '\0';
|
|
|
|
from = g_strstrip (range);
|
|
to = g_strstrip (dash + 1);
|
|
|
|
if (sscanf (from, "%i", &page_from) != 1 && strlen (from) == 0)
|
|
page_from = 1;
|
|
|
|
if (sscanf (to, "%i", &page_to) != 1 && strlen (to) == 0)
|
|
page_to = priv->n_pages;
|
|
|
|
if (page_from > 0 &&
|
|
page_to > 0 &&
|
|
page_from <= page_to &&
|
|
page_from <= priv->n_pages)
|
|
{
|
|
gint page_no;
|
|
|
|
page_from = MAX (page_from, 1) - 1;
|
|
page_to = MIN (page_to, priv->n_pages) - 1;
|
|
|
|
for (page_no = page_from; page_no <= page_to; page_no++)
|
|
gimp_page_selector_select_page (selector, page_no);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gint page_no;
|
|
|
|
if (sscanf (range, "%i", &page_no) == 1 &&
|
|
page_no >= 1 &&
|
|
page_no <= priv->n_pages)
|
|
{
|
|
gimp_page_selector_select_page (selector, page_no - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
g_strfreev (ranges);
|
|
}
|
|
|
|
g_signal_handlers_unblock_by_func (priv->view,
|
|
gimp_page_selector_selection_changed,
|
|
selector);
|
|
|
|
gimp_page_selector_selection_changed (GTK_ICON_VIEW (priv->view), selector);
|
|
}
|
|
|
|
/**
|
|
* gimp_page_selector_get_selected_range:
|
|
* @selector: Pointer to a #GimpPageSelector.
|
|
*
|
|
* Returns: A newly allocated string representing the set of selected
|
|
* pages. See gimp_page_selector_set_selected_range() for the
|
|
* format of the string.
|
|
*
|
|
* Since: GIMP 2.4
|
|
**/
|
|
gchar *
|
|
gimp_page_selector_get_selected_range (GimpPageSelector *selector)
|
|
{
|
|
gint *pages;
|
|
gint n_pages;
|
|
GString *string;
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
|
|
|
|
string = g_string_new ("");
|
|
|
|
pages = gimp_page_selector_get_selected_pages (selector, &n_pages);
|
|
|
|
if (pages)
|
|
{
|
|
gint range_start, range_end;
|
|
gint last_printed;
|
|
gint i;
|
|
|
|
range_start = pages[0];
|
|
range_end = pages[0];
|
|
last_printed = -1;
|
|
|
|
for (i = 1; i < n_pages; i++)
|
|
{
|
|
if (pages[i] > range_end + 1)
|
|
{
|
|
gimp_page_selector_print_range (string,
|
|
range_start, range_end);
|
|
|
|
last_printed = range_end;
|
|
range_start = pages[i];
|
|
}
|
|
|
|
range_end = pages[i];
|
|
}
|
|
|
|
if (range_end != last_printed)
|
|
gimp_page_selector_print_range (string, range_start, range_end);
|
|
|
|
g_free (pages);
|
|
}
|
|
|
|
return g_string_free (string, FALSE);
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
gimp_page_selector_selection_changed (GtkIconView *icon_view,
|
|
GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
GList *selected;
|
|
gint n_selected;
|
|
gchar *range;
|
|
|
|
selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->view));
|
|
n_selected = g_list_length (selected);
|
|
g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
|
|
g_list_free (selected);
|
|
|
|
if (n_selected == 0)
|
|
{
|
|
gtk_label_set_text (GTK_LABEL (priv->count_label),
|
|
_("Nothing selected"));
|
|
}
|
|
else if (n_selected == 1)
|
|
{
|
|
gtk_label_set_text (GTK_LABEL (priv->count_label),
|
|
_("One page selected"));
|
|
}
|
|
else
|
|
{
|
|
gchar *text;
|
|
|
|
if (n_selected == priv->n_pages)
|
|
text = g_strdup_printf (ngettext ("%d page selected",
|
|
"All %d pages selected", n_selected),
|
|
n_selected);
|
|
else
|
|
text = g_strdup_printf (ngettext ("%d page selected",
|
|
"%d pages selected",
|
|
n_selected),
|
|
n_selected);
|
|
|
|
gtk_label_set_text (GTK_LABEL (priv->count_label), text);
|
|
g_free (text);
|
|
}
|
|
|
|
range = gimp_page_selector_get_selected_range (selector);
|
|
gtk_entry_set_text (GTK_ENTRY (priv->range_entry), range);
|
|
g_free (range);
|
|
|
|
gtk_editable_set_position (GTK_EDITABLE (priv->range_entry), -1);
|
|
|
|
g_signal_emit (selector, selector_signals[SELECTION_CHANGED], 0);
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_item_activated (GtkIconView *icon_view,
|
|
GtkTreePath *path,
|
|
GimpPageSelector *selector)
|
|
{
|
|
g_signal_emit (selector, selector_signals[ACTIVATE], 0);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_page_selector_range_focus_out (GtkEntry *entry,
|
|
GdkEventFocus *fevent,
|
|
GimpPageSelector *selector)
|
|
{
|
|
gimp_page_selector_range_activate (entry, selector);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_range_activate (GtkEntry *entry,
|
|
GimpPageSelector *selector)
|
|
{
|
|
gimp_page_selector_select_range (selector, gtk_entry_get_text (entry));
|
|
}
|
|
|
|
static gint
|
|
gimp_page_selector_int_compare (gconstpointer a,
|
|
gconstpointer b)
|
|
{
|
|
return *(gint*)a - *(gint*)b;
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_print_range (GString *string,
|
|
gint start,
|
|
gint end)
|
|
{
|
|
if (string->len != 0)
|
|
g_string_append_c (string, ',');
|
|
|
|
if (start == end)
|
|
g_string_append_printf (string, "%d", start + 1);
|
|
else
|
|
g_string_append_printf (string, "%d-%d", start + 1, end + 1);
|
|
}
|
|
|
|
static void
|
|
gimp_page_selector_update_item_width (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
|
|
if (priv->item_width_idle_id)
|
|
g_source_remove (priv->item_width_idle_id);
|
|
|
|
priv->item_width_idle_id =
|
|
g_idle_add ((GSourceFunc) gimp_page_selector_item_width_idle, selector);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_page_selector_item_width_idle (GimpPageSelector *selector)
|
|
{
|
|
GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
|
|
GtkTreeModel *model = GTK_TREE_MODEL (priv->store);
|
|
GtkTreeIter iter;
|
|
gboolean iter_valid;
|
|
gint focus_line_width;
|
|
gint focus_padding;
|
|
gint max_width = 0;
|
|
|
|
GDK_THREADS_ENTER ();
|
|
|
|
priv->item_width_idle_id = 0;
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (selector),
|
|
"focus-line-width", &focus_line_width,
|
|
"focus-padding", &focus_padding,
|
|
NULL);
|
|
|
|
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
|
|
iter_valid;
|
|
iter_valid = gtk_tree_model_iter_next (model, &iter))
|
|
{
|
|
GdkPixbuf *thumbnail;
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
|
|
COLUMN_THUMBNAIL, &thumbnail,
|
|
-1);
|
|
|
|
if (thumbnail)
|
|
{
|
|
if (thumbnail != priv->default_thumbnail)
|
|
{
|
|
gint width;
|
|
|
|
width = (gdk_pixbuf_get_width (thumbnail) +
|
|
2 * (focus_line_width + focus_padding));
|
|
|
|
if (width > max_width)
|
|
max_width = width;
|
|
}
|
|
|
|
g_object_unref (thumbnail);
|
|
}
|
|
}
|
|
|
|
if (max_width != priv->max_item_width)
|
|
{
|
|
priv->max_item_width = max_width;
|
|
|
|
gtk_icon_view_set_item_width (GTK_ICON_VIEW (priv->view),
|
|
MAX (priv->default_item_width,
|
|
priv->max_item_width));
|
|
}
|
|
|
|
GDK_THREADS_LEAVE ();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
draw_frame_row (GdkPixbuf *frame_image,
|
|
gint target_width,
|
|
gint source_width,
|
|
gint source_v_position,
|
|
gint dest_v_position,
|
|
GdkPixbuf *result_pixbuf,
|
|
gint left_offset,
|
|
gint height)
|
|
{
|
|
gint remaining_width = target_width;
|
|
gint h_offset = 0;
|
|
|
|
while (remaining_width > 0)
|
|
{
|
|
gint slab_width = (remaining_width > source_width ?
|
|
source_width : remaining_width);
|
|
|
|
gdk_pixbuf_copy_area (frame_image,
|
|
left_offset, source_v_position,
|
|
slab_width, height,
|
|
result_pixbuf,
|
|
left_offset + h_offset, dest_v_position);
|
|
|
|
remaining_width -= slab_width;
|
|
h_offset += slab_width;
|
|
}
|
|
}
|
|
|
|
/* utility to draw the middle section of the frame in a loop */
|
|
static void
|
|
draw_frame_column (GdkPixbuf *frame_image,
|
|
gint target_height,
|
|
gint source_height,
|
|
gint source_h_position,
|
|
gint dest_h_position,
|
|
GdkPixbuf *result_pixbuf,
|
|
gint top_offset, int width)
|
|
{
|
|
gint remaining_height = target_height;
|
|
gint v_offset = 0;
|
|
|
|
while (remaining_height > 0)
|
|
{
|
|
gint slab_height = (remaining_height > source_height ?
|
|
source_height : remaining_height);
|
|
|
|
gdk_pixbuf_copy_area (frame_image,
|
|
source_h_position, top_offset,
|
|
width, slab_height,
|
|
result_pixbuf,
|
|
dest_h_position, top_offset + v_offset);
|
|
|
|
remaining_height -= slab_height;
|
|
v_offset += slab_height;
|
|
}
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
stretch_frame_image (GdkPixbuf *frame_image,
|
|
gint left_offset,
|
|
gint top_offset,
|
|
gint right_offset,
|
|
gint bottom_offset,
|
|
gint dest_width,
|
|
gint dest_height)
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
guchar *pixels;
|
|
gint frame_width, frame_height;
|
|
gint row_stride;
|
|
gint target_width, target_frame_width;
|
|
gint target_height, target_frame_height;
|
|
|
|
frame_width = gdk_pixbuf_get_width (frame_image);
|
|
frame_height = gdk_pixbuf_get_height (frame_image );
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
|
|
dest_width, dest_height);
|
|
gdk_pixbuf_fill (pixbuf, 0);
|
|
|
|
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
|
|
target_width = dest_width - left_offset - right_offset;
|
|
target_height = dest_height - top_offset - bottom_offset;
|
|
target_frame_width = frame_width - left_offset - right_offset;
|
|
target_frame_height = frame_height - top_offset - bottom_offset;
|
|
|
|
left_offset += MIN (target_width / 4, target_frame_width / 4);
|
|
right_offset += MIN (target_width / 4, target_frame_width / 4);
|
|
top_offset += MIN (target_height / 4, target_frame_height / 4);
|
|
bottom_offset += MIN (target_height / 4, target_frame_height / 4);
|
|
|
|
target_width = dest_width - left_offset - right_offset;
|
|
target_height = dest_height - top_offset - bottom_offset;
|
|
target_frame_width = frame_width - left_offset - right_offset;
|
|
target_frame_height = frame_height - top_offset - bottom_offset;
|
|
|
|
/* draw the left top corner and top row */
|
|
gdk_pixbuf_copy_area (frame_image,
|
|
0, 0, left_offset, top_offset,
|
|
pixbuf, 0, 0);
|
|
draw_frame_row (frame_image, target_width, target_frame_width,
|
|
0, 0,
|
|
pixbuf,
|
|
left_offset, top_offset);
|
|
|
|
/* draw the right top corner and left column */
|
|
gdk_pixbuf_copy_area (frame_image,
|
|
frame_width - right_offset, 0,
|
|
right_offset, top_offset,
|
|
|
|
pixbuf,
|
|
dest_width - right_offset, 0);
|
|
draw_frame_column (frame_image, target_height, target_frame_height, 0, 0,
|
|
pixbuf, top_offset, left_offset);
|
|
|
|
/* draw the bottom right corner and bottom row */
|
|
gdk_pixbuf_copy_area (frame_image,
|
|
frame_width - right_offset, frame_height - bottom_offset,
|
|
right_offset, bottom_offset,
|
|
pixbuf,
|
|
dest_width - right_offset, dest_height - bottom_offset);
|
|
draw_frame_row (frame_image, target_width, target_frame_width,
|
|
frame_height - bottom_offset, dest_height - bottom_offset,
|
|
pixbuf, left_offset, bottom_offset);
|
|
|
|
/* draw the bottom left corner and the right column */
|
|
gdk_pixbuf_copy_area (frame_image,
|
|
0, frame_height - bottom_offset,
|
|
left_offset, bottom_offset,
|
|
pixbuf,
|
|
0, dest_height - bottom_offset);
|
|
draw_frame_column (frame_image, target_height, target_frame_height,
|
|
frame_width - right_offset, dest_width - right_offset,
|
|
pixbuf, top_offset, right_offset);
|
|
|
|
return pixbuf;
|
|
}
|
|
|
|
#define FRAME_LEFT 2
|
|
#define FRAME_TOP 2
|
|
#define FRAME_RIGHT 4
|
|
#define FRAME_BOTTOM 4
|
|
|
|
static GdkPixbuf *
|
|
gimp_page_selector_add_frame (GtkWidget *widget,
|
|
GdkPixbuf *pixbuf)
|
|
{
|
|
GdkPixbuf *frame;
|
|
gint width, height;
|
|
|
|
width = gdk_pixbuf_get_width (pixbuf);
|
|
height = gdk_pixbuf_get_height (pixbuf);
|
|
|
|
frame = g_object_get_data (G_OBJECT (widget), "frame");
|
|
|
|
if (! frame)
|
|
{
|
|
frame = gtk_widget_render_icon (widget,
|
|
GIMP_STOCK_FRAME,
|
|
GTK_ICON_SIZE_DIALOG, NULL);
|
|
g_object_set_data_full (G_OBJECT (widget), "frame", frame,
|
|
(GDestroyNotify) g_object_unref);
|
|
}
|
|
|
|
frame = stretch_frame_image (frame,
|
|
FRAME_LEFT,
|
|
FRAME_TOP,
|
|
FRAME_RIGHT,
|
|
FRAME_BOTTOM,
|
|
width + FRAME_LEFT + FRAME_RIGHT,
|
|
height + FRAME_TOP + FRAME_BOTTOM);
|
|
|
|
gdk_pixbuf_copy_area (pixbuf, 0, 0, width, height,
|
|
frame, FRAME_LEFT, FRAME_TOP);
|
|
|
|
return frame;
|
|
}
|