PIKApp/app/tools/pikaalignoptions.c

891 lines
31 KiB
C

/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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 "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikaguide.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikachannel.h"
#include "vectors/pikavectors.h"
#include "widgets/pikapivotselector.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-utils.h"
#include "pikaalignoptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
#define ALIGN_VER_N_BUTTONS 3
#define ALIGN_HOR_N_BUTTONS 3
#define DISTR_VER_N_BUTTONS 2
#define DISTR_HOR_N_BUTTONS 2
enum
{
ALIGN_BUTTON_CLICKED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_ALIGN_REFERENCE,
PROP_ALIGN_LAYERS,
PROP_ALIGN_VECTORS,
PROP_ALIGN_CONTENTS,
PROP_PIVOT_X,
PROP_PIVOT_Y,
};
struct _PikaAlignOptionsPrivate
{
gboolean align_layers;
gboolean align_vectors;
gboolean align_contents;
gdouble pivot_x;
gdouble pivot_y;
GList *selected_guides;
GObject *reference;
GtkWidget *selected_guides_label;
GtkWidget *reference_combo;
GtkWidget *reference_box;
GtkWidget *reference_label;
GtkWidget *pivot_selector;
GtkWidget *align_ver_button[ALIGN_VER_N_BUTTONS];
GtkWidget *align_hor_button[ALIGN_HOR_N_BUTTONS];
GtkWidget *distr_ver_button[DISTR_VER_N_BUTTONS];
GtkWidget *distr_hor_button[DISTR_HOR_N_BUTTONS];
};
static void pika_align_options_finalize (GObject *object);
static void pika_align_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_align_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_align_options_image_changed (PikaContext *context,
PikaImage *image,
PikaAlignOptions *options);
static void pika_align_options_update_area (PikaAlignOptions *options);
static void pika_align_options_guide_removed (PikaImage *image,
PikaGuide *guide,
PikaAlignOptions *options);
static void pika_align_options_reference_removed (GObject *object,
PikaAlignOptions *options);
static void pika_align_options_pivot_changed (PikaPivotSelector *selector,
PikaAlignOptions *options);
G_DEFINE_TYPE_WITH_PRIVATE (PikaAlignOptions, pika_align_options, PIKA_TYPE_TOOL_OPTIONS)
#define parent_class pika_align_options_parent_class
static guint align_options_signals[LAST_SIGNAL] = { 0 };
static void
pika_align_options_class_init (PikaAlignOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_align_options_finalize;
object_class->set_property = pika_align_options_set_property;
object_class->get_property = pika_align_options_get_property;
klass->align_button_clicked = NULL;
align_options_signals[ALIGN_BUTTON_CLICKED] =
g_signal_new ("align-button-clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaAlignOptionsClass,
align_button_clicked),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_ALIGNMENT_TYPE);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_ALIGN_REFERENCE,
"align-reference",
_("Relative to"),
_("Reference object targets will be aligned on"),
PIKA_TYPE_ALIGN_REFERENCE_TYPE,
PIKA_ALIGN_REFERENCE_IMAGE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_LAYERS,
"align-layers",
_("Selected layers"),
_("Selected layers will be aligned or distributed by the tool"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_VECTORS,
"align-vectors",
_("Selected paths"),
_("Selected paths will be aligned or distributed by the tool"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_CONTENTS,
"align-contents",
_("Use extents of layer contents"),
_("Instead of aligning or distributing on layer borders, use its content bounding box"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_PIVOT_X,
"pivot-x",
"X position of the point to align in objects",
NULL,
0.0, 1.0, 0.5,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_PIVOT_Y,
"pivot-y",
"Y position of the point to align in objects",
NULL,
0.0, 1.0, 0.5,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_align_options_init (PikaAlignOptions *options)
{
options->priv = pika_align_options_get_instance_private (options);
options->priv->selected_guides = NULL;
}
static void
pika_align_options_finalize (GObject *object)
{
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (object);
if (PIKA_CONTEXT (options)->pika)
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
NULL, options);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_align_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (object);
switch (property_id)
{
case PROP_ALIGN_REFERENCE:
options->align_reference = g_value_get_enum (value);
pika_align_options_update_area (options);
break;
case PROP_ALIGN_LAYERS:
options->priv->align_layers = g_value_get_boolean (value);
pika_align_options_update_area (options);
break;
case PROP_ALIGN_VECTORS:
options->priv->align_vectors = g_value_get_boolean (value);
pika_align_options_update_area (options);
break;
case PROP_ALIGN_CONTENTS:
options->priv->align_contents = g_value_get_boolean (value);
break;
case PROP_PIVOT_X:
options->priv->pivot_x = g_value_get_double (value);
break;
case PROP_PIVOT_Y:
options->priv->pivot_y = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_align_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (object);
switch (property_id)
{
case PROP_ALIGN_REFERENCE:
g_value_set_enum (value, options->align_reference);
break;
case PROP_ALIGN_LAYERS:
g_value_set_boolean (value, options->priv->align_layers);
break;
case PROP_ALIGN_VECTORS:
g_value_set_boolean (value, options->priv->align_vectors);
break;
case PROP_ALIGN_CONTENTS:
g_value_set_boolean (value, options->priv->align_contents);
break;
case PROP_PIVOT_X:
g_value_set_double (value, options->priv->pivot_x);
break;
case PROP_PIVOT_Y:
g_value_set_double (value, options->priv->pivot_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_align_options_button_clicked (GtkButton *button,
PikaAlignOptions *options)
{
PikaAlignmentType action;
action = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
"align-action"));
g_signal_emit (options, align_options_signals[ALIGN_BUTTON_CLICKED], 0,
action);
}
static GtkWidget *
pika_align_options_button_new (PikaAlignOptions *options,
PikaAlignmentType action,
GtkWidget *parent,
const gchar *tooltip)
{
GtkWidget *button;
GtkWidget *image;
const gchar *icon_name = NULL;
switch (action)
{
case PIKA_ALIGN_LEFT:
icon_name = PIKA_ICON_GRAVITY_WEST;
break;
case PIKA_ALIGN_HCENTER:
icon_name = PIKA_ICON_CENTER_HORIZONTAL;
break;
case PIKA_ALIGN_RIGHT:
icon_name = PIKA_ICON_GRAVITY_EAST;
break;
case PIKA_ALIGN_TOP:
icon_name = PIKA_ICON_GRAVITY_NORTH;
break;
case PIKA_ALIGN_VCENTER:
icon_name = PIKA_ICON_CENTER_VERTICAL;
break;
case PIKA_ALIGN_BOTTOM:
icon_name = PIKA_ICON_GRAVITY_SOUTH;
break;
case PIKA_ARRANGE_HFILL:
icon_name = PIKA_ICON_FILL_HORIZONTAL;
break;
case PIKA_ARRANGE_VFILL:
icon_name = PIKA_ICON_FILL_VERTICAL;
break;
case PIKA_DISTRIBUTE_EVEN_HORIZONTAL_GAP:
icon_name = PIKA_ICON_EVEN_HORIZONTAL_GAP;
break;
case PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP:
icon_name = PIKA_ICON_EVEN_VERTICAL_GAP;
break;
default:
g_return_val_if_reached (NULL);
break;
}
button = gtk_button_new ();
gtk_widget_set_sensitive (button, FALSE);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
gtk_box_pack_start (GTK_BOX (parent), button, FALSE, FALSE, 0);
gtk_widget_show (button);
pika_help_set_help_data (button, tooltip, NULL);
g_object_set_data (G_OBJECT (button), "align-action",
GINT_TO_POINTER (action));
g_signal_connect (button, "clicked",
G_CALLBACK (pika_align_options_button_clicked),
options);
return button;
}
GtkWidget *
pika_align_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (tool_options);
GtkWidget *vbox = pika_tool_options_gui (tool_options);
GtkWidget *widget;
GtkWidget *section_vbox;
GtkWidget *items_grid;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *combo;
gchar *text;
gint n = 0;
/* Selected objects */
frame = pika_frame_new (_("Targets"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), section_vbox);
gtk_widget_show (section_vbox);
items_grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (section_vbox), items_grid);
gtk_widget_show (items_grid);
widget = pika_prop_check_button_new (config, "align-contents", NULL);
widget = pika_prop_expanding_frame_new (config, "align-layers",
NULL, widget, NULL);
gtk_grid_attach (GTK_GRID (items_grid), widget, 0, 0, 1, 1);
widget = pika_prop_check_button_new (config, "align-vectors", NULL);
gtk_grid_attach (GTK_GRID (items_grid), widget, 0, 1, 1, 1);
options->priv->pivot_selector = pika_pivot_selector_new (0.0, 0.0, 1.0, 1.0);
gtk_widget_set_tooltip_text (options->priv->pivot_selector,
_("Set anchor point of targets"));
pika_pivot_selector_set_position (PIKA_PIVOT_SELECTOR (options->priv->pivot_selector),
options->priv->pivot_x, options->priv->pivot_y);
gtk_grid_attach (GTK_GRID (items_grid), options->priv->pivot_selector, 1, 0, 1, 2);
gtk_widget_show (options->priv->pivot_selector);
g_signal_connect (options->priv->pivot_selector, "changed",
G_CALLBACK (pika_align_options_pivot_changed),
options);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
widget = gtk_image_new_from_icon_name (PIKA_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
/* TRANSLATORS: the %s strings are modifiers such as Shift, Alt or Cmd. */
text = g_strdup_printf (_("%s-pick target guides (%s-%s to add more)"),
pika_get_mod_string (GDK_MOD1_MASK),
pika_get_mod_string (pika_get_extend_selection_mask ()),
pika_get_mod_string (GDK_MOD1_MASK));
widget = gtk_label_new (text);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
g_free (text);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (section_vbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
options->priv->selected_guides_label = widget;
/* Align frame */
frame = pika_frame_new (_("Align"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), section_vbox);
gtk_widget_show (section_vbox);
/* Align frame: reference */
combo = pika_prop_enum_combo_box_new (config, "align-reference", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Relative to"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (section_vbox), combo, FALSE, FALSE, 0);
options->priv->reference_combo = combo;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
options->priv->reference_box = hbox;
widget = gtk_image_new_from_icon_name (PIKA_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (_("Select the reference object"));
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (section_vbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
options->priv->reference_label = widget;
/* Align frame: buttons */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->align_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_LEFT, hbox,
_("Align anchor points of targets on left edge of reference"));
options->priv->align_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_HCENTER, hbox,
_("Align anchor points of targets on vertical middle of reference"));
options->priv->align_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_RIGHT, hbox,
_("Align anchor points of targets on right edge of reference"));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->align_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_TOP, hbox,
_("Align anchor points of targets on top edge of reference"));
options->priv->align_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_VCENTER, hbox,
_("Align anchor points of targets on horizontal middle of reference"));
options->priv->align_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_BOTTOM, hbox,
_("Align anchor points of targets on bottom of reference"));
/* Distribute frame */
frame = pika_frame_new (_("Distribute"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), section_vbox);
gtk_widget_show (section_vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->distr_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ARRANGE_HFILL, hbox,
_("Distribute anchor points of targets evenly in the horizontal"));
options->priv->distr_ver_button[n++] =
pika_align_options_button_new (options, PIKA_DISTRIBUTE_EVEN_HORIZONTAL_GAP, hbox,
_("Distribute horizontally with even horizontal gaps"));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->distr_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ARRANGE_VFILL, hbox,
_("Distribute anchor points of targets evenly in the vertical"));
options->priv->distr_hor_button[n++] =
pika_align_options_button_new (options, PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP, hbox,
_("Distribute vertically with even vertical gaps"));
g_signal_connect_object (pika_get_user_context (PIKA_CONTEXT (options)->pika),
"image-changed",
G_CALLBACK (pika_align_options_image_changed),
tool_options, 0);
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika)),
options);
return vbox;
}
GList *
pika_align_options_get_objects (PikaAlignOptions *options)
{
PikaImage *image;
GList *objects = NULL;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
if (image)
{
if (options->priv->align_layers)
{
GList *layers;
layers = pika_image_get_selected_layers (image);
layers = g_list_copy (layers);
objects = g_list_concat (objects, layers);
}
if (options->priv->align_vectors)
{
GList *vectors;
vectors = pika_image_get_selected_vectors (image);
vectors = g_list_copy (vectors);
objects = g_list_concat (objects, vectors);
}
if (options->priv->selected_guides)
{
GList *guides;
guides = g_list_copy (options->priv->selected_guides);
objects = g_list_concat (objects, guides);
}
}
return objects;
}
void
pika_align_options_get_pivot (PikaAlignOptions *options,
gdouble *x,
gdouble *y)
{
pika_pivot_selector_get_position (PIKA_PIVOT_SELECTOR (options->priv->pivot_selector),
x, y);
}
void
pika_align_options_pick_reference (PikaAlignOptions *options,
GObject *object)
{
if (options->priv->reference)
g_signal_handlers_disconnect_by_func (options->priv->reference,
G_CALLBACK (pika_align_options_reference_removed),
options);
g_clear_object (&options->priv->reference);
if (object)
{
options->priv->reference = g_object_ref (object);
/* Both PikaItem and PikaGuide/PikaAuxItem have a "removed" signal with
* similar signature. */
g_signal_connect_object (options->priv->reference,
"removed",
G_CALLBACK (pika_align_options_reference_removed),
options, 0);
}
pika_align_options_update_area (options);
}
GObject *
pika_align_options_get_reference (PikaAlignOptions *options,
gboolean blink_if_none)
{
GObject *reference = NULL;
PikaImage *image;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
if (image)
{
switch (options->align_reference)
{
case PIKA_ALIGN_REFERENCE_IMAGE:
reference = G_OBJECT (image);
break;
case PIKA_ALIGN_REFERENCE_SELECTION:
reference = G_OBJECT (pika_image_get_mask (image));
break;
case PIKA_ALIGN_REFERENCE_PICK:
reference = G_OBJECT (options->priv->reference);
break;
}
if (reference == NULL && blink_if_none)
{
if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
pika_widget_blink (options->priv->reference_box);
else
pika_widget_blink (options->priv->reference_combo);
}
}
return reference;
}
gboolean
pika_align_options_align_contents (PikaAlignOptions *options)
{
return options->priv->align_contents;
}
void
pika_align_options_pick_guide (PikaAlignOptions *options,
PikaGuide *guide,
gboolean extend)
{
if (! extend)
g_clear_pointer (&options->priv->selected_guides, g_list_free);
if (guide)
{
GList *list;
if ((list = g_list_find (options->priv->selected_guides, guide)))
options->priv->selected_guides = g_list_delete_link (options->priv->selected_guides, list);
else
options->priv->selected_guides = g_list_prepend (options->priv->selected_guides, guide);
}
pika_align_options_update_area (options);
}
/* Private functions */
static void
pika_align_options_image_changed (PikaContext *context,
PikaImage *image,
PikaAlignOptions *options)
{
PikaImage *prev_image;
prev_image = g_object_get_data (G_OBJECT (options), "pika-align-options-image");
if (image != prev_image)
{
/* We cannot keep track of selected guides across image changes. */
g_clear_pointer (&options->priv->selected_guides, g_list_free);
pika_align_options_pick_reference (options, NULL);
if (prev_image)
{
g_signal_handlers_disconnect_by_func (prev_image,
G_CALLBACK (pika_align_options_update_area),
options);
g_signal_handlers_disconnect_by_func (prev_image,
G_CALLBACK (pika_align_options_guide_removed),
options);
}
if (image)
{
g_signal_connect_object (image, "selected-channels-changed",
G_CALLBACK (pika_align_options_update_area),
options, G_CONNECT_SWAPPED);
g_signal_connect_object (image, "selected-layers-changed",
G_CALLBACK (pika_align_options_update_area),
options, G_CONNECT_SWAPPED);
g_signal_connect_object (image, "guide-removed",
G_CALLBACK (pika_align_options_guide_removed),
options, 0);
}
g_object_set_data (G_OBJECT (options), "pika-align-options-image", image);
pika_align_options_update_area (options);
}
}
static void
pika_align_options_update_area (PikaAlignOptions *options)
{
PikaImage *image;
GList *layers = NULL;
GList *vectors = NULL;
gboolean enable_ver_align = FALSE;
gboolean enable_hor_align = FALSE;
gboolean enable_ver_distr = FALSE;
gboolean enable_hor_distr = FALSE;
gint n_items = 0;
gchar *text;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
/* GUI not created yet. */
if (! options->priv->reference_combo)
return;
if (image)
{
layers = pika_image_get_selected_layers (image);
vectors = pika_image_get_selected_vectors (image);
if (options->priv->align_layers)
n_items += g_list_length (layers);
if (options->priv->align_vectors)
n_items += g_list_length (vectors);
n_items += g_list_length (options->priv->selected_guides);
}
if (n_items > 0)
{
GObject *reference;
reference = pika_align_options_get_reference (options, FALSE);
enable_ver_align = (reference != NULL &&
(! PIKA_IS_GUIDE (reference) ||
pika_guide_get_orientation (PIKA_GUIDE (reference)) == PIKA_ORIENTATION_VERTICAL));
enable_hor_align = (reference != NULL &&
(! PIKA_IS_GUIDE (reference) ||
pika_guide_get_orientation (PIKA_GUIDE (reference)) == PIKA_ORIENTATION_HORIZONTAL));
enable_ver_distr = enable_hor_distr = (n_items > 2);
}
for (gint i = 0; i < ALIGN_VER_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->align_ver_button[i], enable_ver_align);
for (gint i = 0; i < ALIGN_HOR_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->align_hor_button[i], enable_hor_align);
for (gint i = 0; i < DISTR_VER_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->distr_ver_button[i], enable_ver_distr);
for (gint i = 0; i < DISTR_HOR_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->distr_hor_button[i], enable_hor_distr);
/* Update the guide picking widgets. */
if (options->priv->selected_guides)
{
gchar *tmp_txt;
tmp_txt = g_strdup_printf (ngettext ("1 guide will be aligned or distributed",
"%d guides will be aligned or distributed",
g_list_length (options->priv->selected_guides)),
g_list_length (options->priv->selected_guides));
text = g_strdup_printf ("<i>%s</i>", tmp_txt);
g_free (tmp_txt);
gtk_widget_show (options->priv->selected_guides_label);
}
else
{
text = NULL;
gtk_widget_hide (options->priv->selected_guides_label);
}
gtk_label_set_markup (GTK_LABEL (options->priv->selected_guides_label), text);
g_free (text);
/* Update the reference widgets. */
text = NULL;
if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
{
if (options->priv->reference)
{
gchar *tmp_txt;
if (PIKA_IS_LAYER (options->priv->reference))
tmp_txt = g_strdup_printf (_("Reference layer: %s"),
pika_object_get_name (options->priv->reference));
else if (PIKA_IS_CHANNEL (options->priv->reference))
tmp_txt = g_strdup_printf (_("Reference channel: %s"),
pika_object_get_name (options->priv->reference));
else if (PIKA_IS_VECTORS (options->priv->reference))
tmp_txt = g_strdup_printf (_("Reference path: %s"),
pika_object_get_name (options->priv->reference));
else if (PIKA_IS_GUIDE (options->priv->reference))
tmp_txt = g_strdup (_("Reference guide"));
else
g_return_if_reached ();
text = g_strdup_printf ("<i>%s</i>", tmp_txt);
g_free (tmp_txt);
}
gtk_widget_show (options->priv->reference_box);
}
else
{
gtk_widget_hide (options->priv->reference_box);
}
gtk_label_set_markup (GTK_LABEL (options->priv->reference_label), text);
g_free (text);
}
static void
pika_align_options_guide_removed (PikaImage *image,
PikaGuide *guide,
PikaAlignOptions *options)
{
GList *list;
if ((list = g_list_find (options->priv->selected_guides, guide)))
options->priv->selected_guides = g_list_delete_link (options->priv->selected_guides, list);
if (G_OBJECT (guide) == options->priv->reference)
pika_align_options_pick_reference (options, NULL);
pika_align_options_update_area (options);
}
static void
pika_align_options_reference_removed (GObject *object,
PikaAlignOptions *options)
{
if (G_OBJECT (object) == options->priv->reference)
pika_align_options_pick_reference (options, NULL);
}
static void
pika_align_options_pivot_changed (PikaPivotSelector *selector,
PikaAlignOptions *options)
{
gdouble x;
gdouble y;
pika_pivot_selector_get_position (selector, &x, &y);
g_object_set (options,
"pivot-x", x,
"pivot-y", y,
NULL);
}