As seen in the Welcome Dialog, if you have multi-selection in place for a ListBox and try to Ctrl-click another row, the call to gtk_list_box_select_row () will deselect the prior row unless you click on an area that's not covered by GimpRow. This patch removes the forced selection, with the assumption that the click will bubble through as normal to GtkListBox.
903 lines
26 KiB
C
903 lines
26 KiB
C
/* GIMP - The GNU Image Manipulation Program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* gimprow.c
|
|
* Copyright (C) 2025 Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gegl.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "widgets-types.h"
|
|
|
|
#include "core/gimpcontext.h"
|
|
#include "core/gimpviewable.h"
|
|
|
|
#include "gimpdnd.h"
|
|
#include "gimpeditor.h"
|
|
#include "gimprow.h"
|
|
#include "gimprow-utils.h"
|
|
#include "gimpview.h"
|
|
#include "gimpviewrenderer.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
EDIT_NAME,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_CONTEXT,
|
|
PROP_VIEWABLE,
|
|
PROP_VIEW_SIZE,
|
|
PROP_VIEW_BORDER_WIDTH,
|
|
N_PROPS
|
|
};
|
|
|
|
static GParamSpec *obj_props[N_PROPS] = { NULL, };
|
|
|
|
|
|
typedef struct _GimpRowPrivate GimpRowPrivate;
|
|
|
|
struct _GimpRowPrivate
|
|
{
|
|
GimpContext *context;
|
|
GimpViewable *viewable;
|
|
|
|
gint view_size;
|
|
gint view_border_width;
|
|
|
|
GtkWidget *box;
|
|
|
|
GtkWidget *icon;
|
|
GtkWidget *view;
|
|
GtkWidget *label;
|
|
|
|
GtkWidget *rename_popover;
|
|
GtkGesture *rename_long_press;
|
|
};
|
|
|
|
#define GET_PRIVATE(obj) \
|
|
((GimpRowPrivate *) gimp_row_get_instance_private ((GimpRow *) obj))
|
|
|
|
|
|
static void gimp_row_constructed (GObject *object);
|
|
static void gimp_row_dispose (GObject *object);
|
|
static void gimp_row_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_row_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static gboolean gimp_row_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *bevent);
|
|
static void gimp_row_style_updated (GtkWidget *widget);
|
|
static gboolean gimp_row_query_tooltip (GtkWidget *widget,
|
|
gint x,
|
|
gint y,
|
|
gboolean keyboard_tooltip,
|
|
GtkTooltip *tooltip);
|
|
|
|
static void gimp_row_real_set_context (GimpRow *row,
|
|
GimpContext *context);
|
|
static void gimp_row_real_set_viewable (GimpRow *row,
|
|
GimpViewable *viewable);
|
|
static void gimp_row_real_set_view_size (GimpRow *row);
|
|
static void gimp_row_real_icon_changed (GimpRow *row);
|
|
static void gimp_row_real_name_changed (GimpRow *row);
|
|
static void gimp_row_real_monitor_changed (GimpRow *row);
|
|
static void gimp_row_real_edit_name (GimpRow *row);
|
|
static gboolean gimp_row_real_name_edited (GimpRow *row,
|
|
const gchar *new_name);
|
|
|
|
static void gimp_row_icon_changed (GimpViewable *viewable,
|
|
const GParamSpec *pspec,
|
|
GimpRow *row);
|
|
static void gimp_row_name_changed (GimpViewable *viewable,
|
|
GimpRow *row);
|
|
|
|
static void gimp_row_label_long_pressed (GtkGesture *gesture,
|
|
gdouble x,
|
|
gdouble y,
|
|
GimpRow *row);
|
|
static void gimp_row_rename_entry_activate (GtkEntry *entry,
|
|
GimpRow *row);
|
|
|
|
static GimpViewable *
|
|
gimp_row_drag_viewable (GtkWidget *widget,
|
|
GimpContext **context,
|
|
gpointer data);
|
|
static GdkPixbuf *gimp_row_drag_pixbuf (GtkWidget *widget,
|
|
gpointer data);
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpRow, gimp_row, GTK_TYPE_LIST_BOX_ROW)
|
|
|
|
#define parent_class gimp_row_parent_class
|
|
|
|
static guint row_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
static void
|
|
gimp_row_class_init (GimpRowClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
GtkBindingSet *binding_set;
|
|
|
|
object_class->constructed = gimp_row_constructed;
|
|
object_class->dispose = gimp_row_dispose;
|
|
object_class->set_property = gimp_row_set_property;
|
|
object_class->get_property = gimp_row_get_property;
|
|
|
|
widget_class->button_press_event = gimp_row_button_press_event;
|
|
widget_class->style_updated = gimp_row_style_updated;
|
|
widget_class->query_tooltip = gimp_row_query_tooltip;
|
|
|
|
klass->set_context = gimp_row_real_set_context;
|
|
klass->set_viewable = gimp_row_real_set_viewable;
|
|
klass->set_view_size = gimp_row_real_set_view_size;
|
|
klass->icon_changed = gimp_row_real_icon_changed;
|
|
klass->name_changed = gimp_row_real_name_changed;
|
|
klass->monitor_changed = gimp_row_real_monitor_changed;
|
|
klass->edit_name = gimp_row_real_edit_name;
|
|
klass->name_edited = gimp_row_real_name_edited;
|
|
|
|
row_signals[EDIT_NAME] =
|
|
g_signal_new ("edit-name",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
G_STRUCT_OFFSET (GimpRowClass, edit_name),
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
|
|
binding_set = gtk_binding_set_by_class (klass);
|
|
|
|
gtk_binding_entry_add_signal (binding_set, GDK_KEY_F2, 0,
|
|
"edit-name", 0);
|
|
|
|
obj_props[PROP_CONTEXT] =
|
|
g_param_spec_object ("context",
|
|
NULL, NULL,
|
|
GIMP_TYPE_CONTEXT,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT);
|
|
|
|
obj_props[PROP_VIEWABLE] =
|
|
g_param_spec_object ("viewable",
|
|
NULL, NULL,
|
|
GIMP_TYPE_VIEWABLE,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT);
|
|
|
|
obj_props[PROP_VIEW_SIZE] =
|
|
g_param_spec_int ("view-size",
|
|
NULL, NULL,
|
|
1, GIMP_VIEWABLE_MAX_PREVIEW_SIZE,
|
|
GIMP_VIEW_SIZE_MEDIUM,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT);
|
|
|
|
obj_props[PROP_VIEW_BORDER_WIDTH] =
|
|
g_param_spec_int ("view-border-width",
|
|
NULL, NULL,
|
|
0, GIMP_VIEW_MAX_BORDER_WIDTH,
|
|
1,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
|
}
|
|
|
|
static void
|
|
gimp_row_init (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
GtkWidget *ebox;
|
|
|
|
gtk_widget_set_has_tooltip (GTK_WIDGET (row), TRUE);
|
|
|
|
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
|
gtk_container_add (GTK_CONTAINER (row), priv->box);
|
|
gtk_widget_set_visible (priv->box, TRUE);
|
|
|
|
priv->icon = gtk_image_new_from_icon_name (NULL, GTK_ICON_SIZE_BUTTON);
|
|
gtk_box_pack_start (GTK_BOX (priv->box), priv->icon, FALSE, FALSE, 0);
|
|
gtk_widget_set_visible (priv->icon, TRUE);
|
|
|
|
ebox = gtk_event_box_new ();
|
|
gtk_box_pack_end (GTK_BOX (priv->box), ebox, TRUE, TRUE, 0);
|
|
gtk_widget_show (ebox);
|
|
|
|
priv->label = gtk_label_new (NULL);
|
|
gtk_label_set_xalign (GTK_LABEL (priv->label), 0.0);
|
|
gtk_container_add (GTK_CONTAINER (ebox), priv->label);
|
|
gtk_widget_set_visible (priv->label, TRUE);
|
|
|
|
priv->rename_long_press = gtk_gesture_long_press_new (ebox);
|
|
gtk_event_controller_set_propagation_phase
|
|
(GTK_EVENT_CONTROLLER (priv->rename_long_press),
|
|
GTK_PHASE_TARGET);
|
|
|
|
g_signal_connect (priv->rename_long_press, "pressed",
|
|
G_CALLBACK (gimp_row_label_long_pressed),
|
|
row);
|
|
}
|
|
|
|
static void
|
|
gimp_row_constructed (GObject *object)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (object);
|
|
gboolean preview = FALSE;
|
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
|
|
priv->view = gimp_view_new (priv->context,
|
|
priv->viewable,
|
|
priv->view_size,
|
|
priv->view_border_width,
|
|
FALSE);
|
|
GIMP_VIEW (priv->view)->eat_button_events = FALSE;
|
|
GIMP_VIEW (priv->view)->show_popup = TRUE;
|
|
gtk_box_pack_start (GTK_BOX (priv->box), priv->view, FALSE, FALSE, 0);
|
|
|
|
if (priv->viewable)
|
|
preview = gimp_viewable_has_preview (priv->viewable);
|
|
|
|
gtk_widget_set_visible (priv->icon, ! preview);
|
|
gtk_widget_set_visible (priv->view, preview);
|
|
}
|
|
|
|
static void
|
|
gimp_row_dispose (GObject *object)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (object);
|
|
|
|
gimp_row_set_viewable (GIMP_ROW (object), NULL);
|
|
|
|
g_clear_pointer (&priv->rename_popover, gtk_widget_destroy);
|
|
g_clear_object (&priv->rename_long_press);
|
|
|
|
gimp_row_set_context (GIMP_ROW (object), NULL);
|
|
gimp_row_set_viewable (GIMP_ROW (object), NULL);
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gimp_row_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpRow *row = GIMP_ROW (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_CONTEXT:
|
|
gimp_row_set_context (row, g_value_get_object (value));
|
|
break;
|
|
case PROP_VIEWABLE:
|
|
gimp_row_set_viewable (row, g_value_get_object (value));
|
|
break;
|
|
case PROP_VIEW_SIZE:
|
|
case PROP_VIEW_BORDER_WIDTH:
|
|
{
|
|
gint size;
|
|
gint border = 0;
|
|
|
|
size = gimp_row_get_view_size (row, &border);
|
|
|
|
if (property_id == PROP_VIEW_SIZE)
|
|
size = g_value_get_int (value);
|
|
else
|
|
border = g_value_get_int (value);
|
|
|
|
gimp_row_set_view_size (row, size, border);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_row_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpRow *row = GIMP_ROW (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_CONTEXT:
|
|
g_value_set_object (value, gimp_row_get_context (row));
|
|
break;
|
|
case PROP_VIEWABLE:
|
|
g_value_set_object (value, gimp_row_get_viewable (row));
|
|
break;
|
|
case PROP_VIEW_SIZE:
|
|
case PROP_VIEW_BORDER_WIDTH:
|
|
{
|
|
gint size;
|
|
gint border = 0;
|
|
|
|
size = gimp_row_get_view_size (row, &border);
|
|
|
|
if (property_id == PROP_VIEW_SIZE)
|
|
g_value_set_int (value, size);
|
|
else
|
|
g_value_set_int (value, border);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gimp_row_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *bevent)
|
|
{
|
|
GdkEvent *event = (GdkEvent *) bevent;
|
|
gboolean context_menu;
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, bevent);
|
|
|
|
context_menu = gdk_event_triggers_context_menu (event);
|
|
|
|
if (bevent->button == 1 || context_menu)
|
|
{
|
|
GtkWidget *list_box = gtk_widget_get_parent (widget);
|
|
|
|
if (GTK_IS_LIST_BOX (list_box))
|
|
{
|
|
if (context_menu)
|
|
{
|
|
GtkWidget *editor = gtk_widget_get_ancestor (widget,
|
|
GIMP_TYPE_EDITOR);
|
|
|
|
if (editor)
|
|
{
|
|
return gimp_editor_popup_menu_at_pointer (GIMP_EDITOR (editor),
|
|
event);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_row_style_updated (GtkWidget *widget)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (widget);
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
|
|
|
|
if (priv->view)
|
|
gimp_view_renderer_invalidate (GIMP_VIEW (priv->view)->renderer);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_row_query_tooltip (GtkWidget *widget,
|
|
gint x,
|
|
gint y,
|
|
gboolean keyboard_tooltip,
|
|
GtkTooltip *tooltip)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (widget);
|
|
gboolean show_tip = FALSE;
|
|
|
|
if (priv->viewable)
|
|
{
|
|
gchar *desc;
|
|
gchar *tip;
|
|
|
|
desc = gimp_viewable_get_description (priv->viewable, &tip);
|
|
|
|
if (tip)
|
|
{
|
|
gtk_tooltip_set_text (tooltip, tip);
|
|
|
|
show_tip = TRUE;
|
|
|
|
g_free (tip);
|
|
}
|
|
|
|
g_free (desc);
|
|
}
|
|
|
|
return show_tip;
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_set_context (GimpRow *row,
|
|
GimpContext *context)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_set_object (&priv->context, context);
|
|
|
|
if (priv->view)
|
|
gimp_view_renderer_set_context (GIMP_VIEW (priv->view)->renderer,
|
|
priv->context);
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_set_viewable (GimpRow *row,
|
|
GimpViewable *viewable)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
GType viewable_type = G_TYPE_NONE;
|
|
gboolean preview = FALSE;
|
|
|
|
if (viewable)
|
|
viewable_type = G_TYPE_FROM_INSTANCE (viewable);
|
|
|
|
if (priv->viewable)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (priv->viewable,
|
|
gimp_row_icon_changed,
|
|
row);
|
|
g_signal_handlers_disconnect_by_func (priv->viewable,
|
|
gimp_row_name_changed,
|
|
row);
|
|
|
|
if (! viewable)
|
|
{
|
|
if (gimp_dnd_viewable_source_remove (GTK_WIDGET (row),
|
|
G_TYPE_FROM_INSTANCE (priv->viewable)))
|
|
{
|
|
if (gimp_viewable_get_size (priv->viewable, NULL, NULL))
|
|
gimp_dnd_pixbuf_source_remove (GTK_WIDGET (row));
|
|
|
|
gtk_drag_source_unset (GTK_WIDGET (row));
|
|
}
|
|
}
|
|
}
|
|
else if (viewable)
|
|
{
|
|
if (gimp_dnd_drag_source_set_by_type (GTK_WIDGET (row),
|
|
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
|
|
viewable_type,
|
|
GDK_ACTION_COPY))
|
|
{
|
|
gimp_dnd_viewable_source_add (GTK_WIDGET (row),
|
|
viewable_type,
|
|
gimp_row_drag_viewable,
|
|
NULL);
|
|
|
|
if (gimp_viewable_get_size (viewable, NULL, NULL))
|
|
gimp_dnd_pixbuf_source_add (GTK_WIDGET (row),
|
|
gimp_row_drag_pixbuf,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
g_set_weak_pointer (&priv->viewable, viewable);
|
|
|
|
if (priv->viewable)
|
|
{
|
|
g_signal_connect (priv->viewable,
|
|
GIMP_VIEWABLE_GET_CLASS (viewable)->name_changed_signal,
|
|
G_CALLBACK (gimp_row_name_changed),
|
|
row);
|
|
g_signal_connect (priv->viewable, "notify::icon-name",
|
|
G_CALLBACK (gimp_row_icon_changed),
|
|
row);
|
|
|
|
preview = gimp_viewable_has_preview (priv->viewable);
|
|
}
|
|
|
|
gimp_row_name_changed (priv->viewable, row);
|
|
|
|
gtk_widget_set_visible (priv->icon, ! preview);
|
|
gimp_row_icon_changed (priv->viewable, NULL, row);
|
|
|
|
if (priv->view)
|
|
{
|
|
gtk_widget_set_visible (priv->view, preview);
|
|
gimp_view_set_viewable (GIMP_VIEW (priv->view), priv->viewable);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_set_view_size (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
gtk_image_set_pixel_size (GTK_IMAGE (priv->icon),
|
|
priv->view_size);
|
|
|
|
if (priv->view)
|
|
gimp_view_renderer_set_size (GIMP_VIEW (priv->view)->renderer,
|
|
priv->view_size,
|
|
priv->view_border_width);
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_icon_changed (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
const gchar *icon_name = NULL;
|
|
|
|
if (priv->viewable)
|
|
icon_name = gimp_viewable_get_icon_name (priv->viewable);
|
|
|
|
gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon), icon_name,
|
|
GTK_ICON_SIZE_BUTTON);
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_name_changed (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
const gchar *description = NULL;
|
|
|
|
if (priv->viewable)
|
|
description = gimp_viewable_get_description (priv->viewable, NULL);
|
|
|
|
gtk_label_set_text (GTK_LABEL (priv->label), description);
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_monitor_changed (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
if (priv->view)
|
|
gimp_view_renderer_free_color_transform (GIMP_VIEW (priv->view)->renderer);
|
|
}
|
|
|
|
static void
|
|
gimp_row_real_edit_name (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
GtkWidget *box;
|
|
GtkWidget *label;
|
|
GtkWidget *entry;
|
|
const gchar *default_name;
|
|
gchar *title;
|
|
|
|
if (! priv->viewable ||
|
|
! gimp_viewable_is_name_editable (priv->viewable))
|
|
{
|
|
gtk_widget_error_bell (GTK_WIDGET (row));
|
|
return;
|
|
}
|
|
|
|
priv->rename_popover = gtk_popover_new (priv->label);
|
|
gtk_popover_set_modal (GTK_POPOVER (priv->rename_popover), TRUE);
|
|
|
|
g_object_add_weak_pointer (G_OBJECT (priv->rename_popover),
|
|
(gpointer) &priv->rename_popover);
|
|
|
|
g_signal_connect (priv->rename_popover, "closed",
|
|
G_CALLBACK (gtk_widget_destroy),
|
|
NULL);
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
|
gtk_container_add (GTK_CONTAINER (priv->rename_popover), box);
|
|
gtk_widget_show (box);
|
|
|
|
default_name = GIMP_VIEWABLE_GET_CLASS (priv->viewable)->default_name;
|
|
|
|
title = g_strdup_printf (_("Rename %s"), default_name);
|
|
label = gtk_label_new (title);
|
|
g_free (title);
|
|
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
entry = gtk_entry_new ();
|
|
gtk_entry_set_text (GTK_ENTRY (entry), gimp_object_get_name (priv->viewable));
|
|
gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 0);
|
|
gtk_widget_show (entry);
|
|
|
|
g_signal_connect (entry, "activate",
|
|
G_CALLBACK (gimp_row_rename_entry_activate),
|
|
row);
|
|
|
|
gtk_popover_popup (GTK_POPOVER (priv->rename_popover));
|
|
}
|
|
|
|
static gboolean
|
|
gimp_row_real_name_edited (GimpRow *row,
|
|
const gchar *new_name)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
gimp_object_set_name (GIMP_OBJECT (priv->viewable), new_name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* public functions */
|
|
|
|
GtkWidget *
|
|
gimp_row_new (GimpContext *context,
|
|
GimpViewable *viewable,
|
|
gint view_size,
|
|
gint view_border_width)
|
|
{
|
|
GType row_type;
|
|
|
|
g_return_val_if_fail (context == NULL || GIMP_IS_CONTEXT (context), NULL);
|
|
g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL);
|
|
g_return_val_if_fail (view_size > 0 &&
|
|
view_size <= GIMP_VIEWABLE_MAX_PREVIEW_SIZE, NULL);
|
|
g_return_val_if_fail (view_border_width >= 0 &&
|
|
view_border_width <= GIMP_VIEW_MAX_BORDER_WIDTH,
|
|
NULL);
|
|
|
|
row_type = gimp_row_type_from_viewable (viewable);
|
|
|
|
return g_object_new (row_type,
|
|
"context", context,
|
|
"viewable", viewable,
|
|
"view-size", view_size,
|
|
"view-border-width", view_border_width,
|
|
NULL);
|
|
}
|
|
|
|
void
|
|
gimp_row_set_context (GimpRow *row,
|
|
GimpContext *context)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_if_fail (GIMP_IS_ROW (row));
|
|
g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
|
|
|
|
if (context != priv->context)
|
|
{
|
|
GIMP_ROW_GET_CLASS (row)->set_context (row, context);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (row), obj_props[PROP_CONTEXT]);
|
|
}
|
|
}
|
|
|
|
GimpContext *
|
|
gimp_row_get_context (GimpRow *row)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), NULL);
|
|
|
|
return GET_PRIVATE (row)->context;
|
|
}
|
|
|
|
void
|
|
gimp_row_set_viewable (GimpRow *row,
|
|
GimpViewable *viewable)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_if_fail (GIMP_IS_ROW (row));
|
|
g_return_if_fail (viewable == NULL || GIMP_IS_VIEWABLE (viewable));
|
|
|
|
if (viewable != priv->viewable)
|
|
{
|
|
GIMP_ROW_GET_CLASS (row)->set_viewable (row, viewable);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (row), obj_props[PROP_VIEWABLE]);
|
|
}
|
|
}
|
|
|
|
GimpViewable *
|
|
gimp_row_get_viewable (GimpRow *row)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), NULL);
|
|
|
|
return GET_PRIVATE (row)->viewable;
|
|
}
|
|
|
|
void
|
|
gimp_row_set_view_size (GimpRow *row,
|
|
gint view_size,
|
|
gint view_border_width)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_if_fail (GIMP_IS_ROW (row));
|
|
g_return_if_fail (view_size > 0 &&
|
|
view_size <= GIMP_VIEWABLE_MAX_PREVIEW_SIZE);
|
|
g_return_if_fail (view_border_width >= 0 &&
|
|
view_border_width <= GIMP_VIEW_MAX_BORDER_WIDTH);
|
|
|
|
if (priv->view_size != view_size ||
|
|
priv->view_border_width != view_border_width)
|
|
{
|
|
priv->view_size = view_size;
|
|
priv->view_border_width = view_border_width;
|
|
|
|
GIMP_ROW_GET_CLASS (row)->set_view_size (row);
|
|
|
|
g_object_freeze_notify (G_OBJECT (row));
|
|
g_object_notify_by_pspec (G_OBJECT (row), obj_props[PROP_VIEW_SIZE]);
|
|
g_object_notify_by_pspec (G_OBJECT (row), obj_props[PROP_VIEW_BORDER_WIDTH]);
|
|
g_object_thaw_notify (G_OBJECT (row));
|
|
}
|
|
}
|
|
|
|
gint
|
|
gimp_row_get_view_size (GimpRow *row,
|
|
gint *view_border_width)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), 1);
|
|
|
|
if (view_border_width)
|
|
*view_border_width = priv->view_border_width;
|
|
|
|
return priv->view_size;
|
|
}
|
|
|
|
void
|
|
gimp_row_monitor_changed (GimpRow *row)
|
|
{
|
|
g_return_if_fail (GIMP_IS_ROW (row));
|
|
|
|
GIMP_ROW_GET_CLASS (row)->monitor_changed (row);
|
|
}
|
|
|
|
GtkWidget *
|
|
_gimp_row_get_box (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), NULL);
|
|
|
|
return priv->box;
|
|
}
|
|
|
|
GtkWidget *
|
|
_gimp_row_get_icon (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), NULL);
|
|
|
|
return priv->icon;
|
|
}
|
|
|
|
GtkWidget *
|
|
_gimp_row_get_view (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), NULL);
|
|
|
|
return priv->view;
|
|
}
|
|
|
|
GtkWidget *
|
|
_gimp_row_get_label (GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
|
|
g_return_val_if_fail (GIMP_IS_ROW (row), NULL);
|
|
|
|
return priv->label;
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
gimp_row_icon_changed (GimpViewable *viewable,
|
|
const GParamSpec *pspec,
|
|
GimpRow *row)
|
|
{
|
|
GIMP_ROW_GET_CLASS (row)->icon_changed (row);
|
|
}
|
|
|
|
static void
|
|
gimp_row_name_changed (GimpViewable *viewable,
|
|
GimpRow *row)
|
|
{
|
|
GIMP_ROW_GET_CLASS (row)->name_changed (row);
|
|
}
|
|
|
|
static void
|
|
gimp_row_label_long_pressed (GtkGesture *gesture,
|
|
gdouble x,
|
|
gdouble y,
|
|
GimpRow *row)
|
|
{
|
|
g_signal_emit (row, row_signals[EDIT_NAME], 0);
|
|
}
|
|
|
|
static void
|
|
gimp_row_rename_entry_activate (GtkEntry *entry,
|
|
GimpRow *row)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (row);
|
|
const gchar *old_name;
|
|
gchar *new_name;
|
|
|
|
old_name = gimp_object_get_name (priv->viewable);
|
|
|
|
/* Dup the new name, and popdown before renaming, because it can
|
|
* destroy the row and the popup.
|
|
*/
|
|
new_name = g_strdup (gtk_entry_get_text (entry));
|
|
gtk_popover_popdown (GTK_POPOVER (priv->rename_popover));
|
|
|
|
if (g_strcmp0 (old_name, new_name))
|
|
{
|
|
if (! GIMP_ROW_GET_CLASS (row)->name_edited (row, new_name))
|
|
{
|
|
gtk_widget_error_bell (GTK_WIDGET (row));
|
|
}
|
|
}
|
|
|
|
g_free (new_name);
|
|
}
|
|
|
|
static GimpViewable *
|
|
gimp_row_drag_viewable (GtkWidget *widget,
|
|
GimpContext **context,
|
|
gpointer data)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (widget);
|
|
|
|
if (context)
|
|
*context = priv->context;
|
|
|
|
return priv->viewable;
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
gimp_row_drag_pixbuf (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
GimpRowPrivate *priv = GET_PRIVATE (widget);
|
|
gint width;
|
|
gint height;
|
|
|
|
g_printerr ("drag pixbuf\n");
|
|
|
|
if (priv->viewable &&
|
|
gimp_viewable_get_size (priv->viewable, &width, &height))
|
|
{
|
|
return gimp_viewable_get_new_pixbuf (priv->viewable,
|
|
priv->context,
|
|
width, height, NULL);
|
|
}
|
|
|
|
g_printerr ("failed\n");
|
|
|
|
return NULL;
|
|
}
|