PIKApp/app/tools/pikarectangleoptions.c

1263 lines
55 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-1999 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 <string.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/pikaimage.h"
#include "core/pikatooloptions.h"
#include "widgets/pikapropwidgets.h"
#include "pikarectangleoptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
#define SB_WIDTH 7
enum
{
COLUMN_LEFT_NUMBER,
COLUMN_RIGHT_NUMBER,
COLUMN_TEXT,
N_COLUMNS
};
/* local function prototypes */
static void pika_rectangle_options_fixed_rule_changed (GtkWidget *widget,
PikaRectangleOptionsPrivate *private);
static void pika_rectangle_options_string_current_updates (PikaNumberPairEntry *entry,
GParamSpec *param,
PikaRectangleOptions *rectangle_options);
static void pika_rectangle_options_setup_ratio_completion (PikaRectangleOptions *rectangle_options,
GtkWidget *entry,
GtkListStore *history);
static gboolean pika_number_pair_entry_history_select (GtkEntryCompletion *completion,
GtkTreeModel *model,
GtkTreeIter *iter,
PikaNumberPairEntry *entry);
static void pika_number_pair_entry_history_add (GtkWidget *entry,
GtkTreeModel *model);
G_DEFINE_INTERFACE (PikaRectangleOptions, pika_rectangle_options, PIKA_TYPE_TOOL_OPTIONS)
static void
pika_rectangle_options_default_init (PikaRectangleOptionsInterface *iface)
{
g_object_interface_install_property (iface,
g_param_spec_boolean ("auto-shrink",
NULL,
_("Automatically shrink to the nearest "
"rectangular shape in a layer"),
FALSE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_boolean ("shrink-merged",
_("Shrink merged"),
_("Use all visible layers when shrinking "
"the selection"),
FALSE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_enum ("guide",
NULL,
_("Composition guides such as rule of thirds"),
PIKA_TYPE_GUIDES_TYPE,
PIKA_GUIDES_NONE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("x",
NULL,
_("X coordinate of top left corner"),
-PIKA_MAX_IMAGE_SIZE,
PIKA_MAX_IMAGE_SIZE,
0.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_double ("y",
NULL,
_("Y coordinate of top left corner"),
-PIKA_MAX_IMAGE_SIZE,
PIKA_MAX_IMAGE_SIZE,
0.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_double ("width",
NULL,
_("Width of selection"),
0.0, PIKA_MAX_IMAGE_SIZE,
0.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_double ("height",
NULL,
_("Height of selection"),
0.0, PIKA_MAX_IMAGE_SIZE,
0.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
pika_param_spec_unit ("position-unit",
NULL,
_("Unit of top left corner coordinate"),
TRUE, TRUE,
PIKA_UNIT_PIXEL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
pika_param_spec_unit ("size-unit",
NULL,
_("Unit of selection size"),
TRUE, TRUE,
PIKA_UNIT_PIXEL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_boolean ("fixed-rule-active",
NULL,
_("Enable lock of aspect ratio, "
"width, height or size"),
FALSE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_enum ("fixed-rule",
NULL,
_("Choose what has to be locked"),
PIKA_TYPE_RECTANGLE_FIXED_RULE,
PIKA_RECTANGLE_FIXED_ASPECT,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("desired-fixed-width",
NULL,
_("Custom fixed width"),
0.0, PIKA_MAX_IMAGE_SIZE,
100.0,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("desired-fixed-height",
NULL,
_("Custom fixed height"),
0.0, PIKA_MAX_IMAGE_SIZE,
100.0,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("desired-fixed-size-width",
NULL, NULL,
0.0, PIKA_MAX_IMAGE_SIZE,
100.0,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("desired-fixed-size-height",
NULL, NULL,
0.0, PIKA_MAX_IMAGE_SIZE,
100.0,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("default-fixed-size-width",
NULL, NULL,
0.0, PIKA_MAX_IMAGE_SIZE,
100.0,
PIKA_PARAM_READWRITE |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("default-fixed-size-height",
NULL, NULL,
0.0, PIKA_MAX_IMAGE_SIZE,
100.0,
PIKA_PARAM_READWRITE |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_boolean ("overridden-fixed-size",
NULL, NULL,
FALSE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("aspect-numerator",
NULL, NULL,
0.0, PIKA_MAX_IMAGE_SIZE,
1.0,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("aspect-denominator",
NULL, NULL,
0.0, PIKA_MAX_IMAGE_SIZE,
1.0,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_double ("default-aspect-numerator",
NULL, NULL,
0.001, PIKA_MAX_IMAGE_SIZE,
1.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_double ("default-aspect-denominator",
NULL, NULL,
0.001, PIKA_MAX_IMAGE_SIZE,
1.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_boolean ("overridden-fixed-aspect",
NULL, NULL,
FALSE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
g_param_spec_boolean ("use-string-current",
NULL, NULL,
FALSE,
PIKA_PARAM_READWRITE |
PIKA_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
pika_param_spec_unit ("fixed-unit",
NULL,
_("Unit of fixed width, height or size"),
TRUE, TRUE,
PIKA_UNIT_PIXEL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_interface_install_property (iface,
g_param_spec_boolean ("fixed-center",
_("Expand from center"),
_("Expand selection from center outwards"),
FALSE,
PIKA_CONFIG_PARAM_FLAGS |
PIKA_PARAM_STATIC_STRINGS));
}
static void
pika_rectangle_options_private_finalize (PikaRectangleOptionsPrivate *private)
{
g_clear_object (&private->aspect_history);
g_clear_object (&private->size_history);
g_slice_free (PikaRectangleOptionsPrivate, private);
}
PikaRectangleOptionsPrivate *
pika_rectangle_options_get_private (PikaRectangleOptions *options)
{
PikaRectangleOptionsPrivate *private;
static GQuark private_key = 0;
g_return_val_if_fail (PIKA_IS_RECTANGLE_OPTIONS (options), NULL);
if (! private_key)
private_key = g_quark_from_static_string ("pika-rectangle-options-private");
private = g_object_get_qdata (G_OBJECT (options), private_key);
if (! private)
{
private = g_slice_new0 (PikaRectangleOptionsPrivate);
private->aspect_history = gtk_list_store_new (N_COLUMNS,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE,
G_TYPE_STRING);
private->size_history = gtk_list_store_new (N_COLUMNS,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE,
G_TYPE_STRING);
g_object_set_qdata_full (G_OBJECT (options), private_key, private,
(GDestroyNotify) pika_rectangle_options_private_finalize);
}
return private;
}
/**
* pika_rectangle_options_install_properties:
* @klass: the class structure for a type deriving from #GObject
*
* Installs the necessary properties for a class implementing
* #PikaRectangleOptions. A #PikaRectangleOptionsProp property is installed
* for each property, using the values from the #PikaRectangleOptionsProp
* enumeration. The caller must make sure itself that the enumeration
* values don't collide with some other property values they
* are using (that's what %PIKA_RECTANGLE_OPTIONS_PROP_LAST is good for).
**/
void
pika_rectangle_options_install_properties (GObjectClass *klass)
{
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_AUTO_SHRINK,
"auto-shrink");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_SHRINK_MERGED,
"shrink-merged");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_GUIDE,
"guide");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_X,
"x");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_Y,
"y");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_WIDTH,
"width");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_HEIGHT,
"height");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_POSITION_UNIT,
"position-unit");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_SIZE_UNIT,
"size-unit");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_FIXED_RULE_ACTIVE,
"fixed-rule-active");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_FIXED_RULE,
"fixed-rule");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_WIDTH,
"desired-fixed-width");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_HEIGHT,
"desired-fixed-height");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_SIZE_WIDTH,
"desired-fixed-size-width");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_SIZE_HEIGHT,
"desired-fixed-size-height");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_FIXED_SIZE_WIDTH,
"default-fixed-size-width");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_FIXED_SIZE_HEIGHT,
"default-fixed-size-height");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_OVERRIDDEN_FIXED_SIZE,
"overridden-fixed-size");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_ASPECT_NUMERATOR,
"aspect-numerator");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_ASPECT_DENOMINATOR,
"aspect-denominator");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_ASPECT_NUMERATOR,
"default-aspect-numerator");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_ASPECT_DENOMINATOR,
"default-aspect-denominator");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_OVERRIDDEN_FIXED_ASPECT,
"overridden-fixed-aspect");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_USE_STRING_CURRENT,
"use-string-current");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_FIXED_UNIT,
"fixed-unit");
g_object_class_override_property (klass,
PIKA_RECTANGLE_OPTIONS_PROP_FIXED_CENTER,
"fixed-center");
}
void
pika_rectangle_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaRectangleOptions *options = PIKA_RECTANGLE_OPTIONS (object);
PikaRectangleOptionsPrivate *private;
private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (options);
switch (property_id)
{
case PIKA_RECTANGLE_OPTIONS_PROP_AUTO_SHRINK:
private->auto_shrink = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_SHRINK_MERGED:
private->shrink_merged = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_HIGHLIGHT:
private->highlight = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_HIGHLIGHT_OPACITY:
private->highlight_opacity = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_GUIDE:
private->guide = g_value_get_enum (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_X:
private->x = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_Y:
private->y = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_WIDTH:
private->width = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_HEIGHT:
private->height = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_POSITION_UNIT:
private->position_unit = g_value_get_int (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_SIZE_UNIT:
private->size_unit = g_value_get_int (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_RULE_ACTIVE:
private->fixed_rule_active = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_RULE:
private->fixed_rule = g_value_get_enum (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_WIDTH:
private->desired_fixed_width = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_HEIGHT:
private->desired_fixed_height = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_SIZE_WIDTH:
private->desired_fixed_size_width = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_SIZE_HEIGHT:
private->desired_fixed_size_height = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_FIXED_SIZE_WIDTH:
private->default_fixed_size_width = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_FIXED_SIZE_HEIGHT:
private->default_fixed_size_height = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_OVERRIDDEN_FIXED_SIZE:
private->overridden_fixed_size = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_ASPECT_NUMERATOR:
private->aspect_numerator = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_ASPECT_DENOMINATOR:
private->aspect_denominator = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_ASPECT_NUMERATOR:
private->default_aspect_numerator = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_ASPECT_DENOMINATOR:
private->default_aspect_denominator = g_value_get_double (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_OVERRIDDEN_FIXED_ASPECT:
private->overridden_fixed_aspect = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_USE_STRING_CURRENT:
private->use_string_current = g_value_get_boolean (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_UNIT:
private->fixed_unit = g_value_get_int (value);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_CENTER:
private->fixed_center = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
void
pika_rectangle_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaRectangleOptions *options = PIKA_RECTANGLE_OPTIONS (object);
PikaRectangleOptionsPrivate *private;
private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (options);
switch (property_id)
{
case PIKA_RECTANGLE_OPTIONS_PROP_AUTO_SHRINK:
g_value_set_boolean (value, private->auto_shrink);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_SHRINK_MERGED:
g_value_set_boolean (value, private->shrink_merged);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_HIGHLIGHT:
g_value_set_boolean (value, private->highlight);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_HIGHLIGHT_OPACITY:
g_value_set_double (value, private->highlight_opacity);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_GUIDE:
g_value_set_enum (value, private->guide);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_X:
g_value_set_double (value, private->x);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_Y:
g_value_set_double (value, private->y);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_WIDTH:
g_value_set_double (value, private->width);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_HEIGHT:
g_value_set_double (value, private->height);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_POSITION_UNIT:
g_value_set_int (value, private->position_unit);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_SIZE_UNIT:
g_value_set_int (value, private->size_unit);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_RULE_ACTIVE:
g_value_set_boolean (value, private->fixed_rule_active);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_RULE:
g_value_set_enum (value, private->fixed_rule);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_WIDTH:
g_value_set_double (value, private->desired_fixed_width);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_HEIGHT:
g_value_set_double (value, private->desired_fixed_height);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_SIZE_WIDTH:
g_value_set_double (value, private->desired_fixed_size_width);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DESIRED_FIXED_SIZE_HEIGHT:
g_value_set_double (value, private->desired_fixed_size_height);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_FIXED_SIZE_WIDTH:
g_value_set_double (value, private->default_fixed_size_width);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_FIXED_SIZE_HEIGHT:
g_value_set_double (value, private->default_fixed_size_height);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_OVERRIDDEN_FIXED_SIZE:
g_value_set_boolean (value, private->overridden_fixed_size);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_ASPECT_NUMERATOR:
g_value_set_double (value, private->aspect_numerator);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_ASPECT_DENOMINATOR:
g_value_set_double (value, private->aspect_denominator);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_ASPECT_NUMERATOR:
g_value_set_double (value, private->default_aspect_numerator);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_DEFAULT_ASPECT_DENOMINATOR:
g_value_set_double (value, private->default_aspect_denominator);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_OVERRIDDEN_FIXED_ASPECT:
g_value_set_boolean (value, private->overridden_fixed_aspect);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_USE_STRING_CURRENT:
g_value_set_boolean (value, private->use_string_current);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_UNIT:
g_value_set_int (value, private->fixed_unit);
break;
case PIKA_RECTANGLE_OPTIONS_PROP_FIXED_CENTER:
g_value_set_boolean (value, private->fixed_center);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* pika_rectangle_options_get_size_entry:
* @rectangle_options:
*
* Returns: GtkEntry used to enter desired size of rectangle. For
* testing purposes.
**/
GtkWidget *
pika_rectangle_options_get_size_entry (PikaRectangleOptions *rectangle_options)
{
PikaRectangleOptionsPrivate *private;
private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (rectangle_options);
return private->size_entry;
}
/**
* pika_rectangle_options_fixed_rule_changed:
* @widget:
* @private:
*
* Updates tool options widgets depending on current fixed rule state.
*/
static void
pika_rectangle_options_fixed_rule_changed (GtkWidget *widget,
PikaRectangleOptionsPrivate *private)
{
/* Update fixed_rule_active if checkbox was changed */
if (GTK_IS_TOGGLE_BUTTON (widget))
private->fixed_rule_active =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
/* Setup sensitivity for Width and Height entries */
gtk_widget_set_sensitive (pika_size_entry_get_help_widget (
PIKA_SIZE_ENTRY (private->size_entry), 0),
! (private->fixed_rule_active &&
(private->fixed_rule ==
PIKA_RECTANGLE_FIXED_WIDTH ||
private->fixed_rule ==
PIKA_RECTANGLE_FIXED_SIZE)));
gtk_widget_set_sensitive (pika_size_entry_get_help_widget (
PIKA_SIZE_ENTRY (private->size_entry), 1),
! (private->fixed_rule_active &&
(private->fixed_rule ==
PIKA_RECTANGLE_FIXED_HEIGHT ||
private->fixed_rule ==
PIKA_RECTANGLE_FIXED_SIZE)));
/* Setup current fixed rule entries */
gtk_widget_hide (private->fixed_width_entry);
gtk_widget_hide (private->fixed_height_entry);
gtk_widget_hide (private->fixed_aspect_hbox);
gtk_widget_hide (private->fixed_size_hbox);
switch (private->fixed_rule)
{
case PIKA_RECTANGLE_FIXED_ASPECT:
gtk_widget_show (private->fixed_aspect_hbox);
break;
case PIKA_RECTANGLE_FIXED_WIDTH:
gtk_widget_show (private->fixed_width_entry);
break;
case PIKA_RECTANGLE_FIXED_HEIGHT:
gtk_widget_show (private->fixed_height_entry);
break;
case PIKA_RECTANGLE_FIXED_SIZE:
gtk_widget_show (private->fixed_size_hbox);
break;
}
}
static void
pika_rectangle_options_string_current_updates (PikaNumberPairEntry *entry,
GParamSpec *param,
PikaRectangleOptions *rectangle_options)
{
PikaRectangleOptionsPrivate *private;
gboolean user_override;
private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (rectangle_options);
user_override = pika_number_pair_entry_get_user_override (entry);
pika_number_pair_entry_set_default_text (entry,
private->use_string_current ?
/* Current, as in what is currently in use. */
_("Current") : NULL);
gtk_widget_set_sensitive (private->aspect_button_box,
! private->use_string_current || user_override);
}
static GtkWidget *
pika_rectangle_options_prop_dimension_frame_new (GObject *config,
const gchar *x_property_name,
const gchar *y_property_name,
const gchar *unit_property_name,
const gchar *table_label,
GtkSizeGroup *label_group,
GtkWidget **entry)
{
PikaUnit unit_value;
GtkWidget *frame;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *menu;
GtkWidget *spinbutton;
GtkAdjustment *adjustment;
g_object_get (config,
unit_property_name, &unit_value,
NULL);
frame = pika_frame_new (NULL);
/* title */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
gtk_frame_set_label_widget (GTK_FRAME (frame), hbox);
gtk_widget_show (hbox);
label = gtk_label_new (table_label);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_size_group_add_widget (label_group, label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
menu = pika_prop_unit_combo_box_new (config, unit_property_name);
gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
/* content */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_container_add (GTK_CONTAINER (frame), hbox);
gtk_widget_show (hbox);
adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinbutton = pika_spin_button_new (adjustment, 1.0, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH);
gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
gtk_widget_show (spinbutton);
*entry = pika_size_entry_new (1, unit_value, "%a", TRUE, TRUE, FALSE,
SB_WIDTH, PIKA_SIZE_ENTRY_UPDATE_SIZE);
gtk_grid_set_column_spacing (GTK_GRID (*entry), 0);
pika_size_entry_show_unit_menu (PIKA_SIZE_ENTRY (*entry), FALSE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (*entry),
GTK_SPIN_BUTTON (spinbutton), NULL);
gtk_box_pack_start (GTK_BOX (hbox), *entry, FALSE, FALSE, 0);
gtk_widget_show (*entry);
pika_prop_coordinates_connect (config,
x_property_name, y_property_name,
unit_property_name,
*entry, NULL, 300, 300);
return frame;
}
GtkWidget *
pika_rectangle_options_gui (PikaToolOptions *tool_options)
{
PikaRectangleOptionsPrivate *private;
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_tool_options_gui (tool_options);
GtkWidget *button;
GtkWidget *combo;
GtkWidget *frame;
GtkSizeGroup *label_group;
private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (tool_options);
/* Fixed Center */
button = pika_prop_check_button_new (config, "fixed-center", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* Rectangle fixed-rules (e.g. aspect or width). */
{
GtkWidget *vbox2;
GtkWidget *hbox;
GtkWidget *entry;
GtkSizeGroup *size_group;
GList *children;
frame = pika_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Setup frame title widgets */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_frame_set_label_widget (GTK_FRAME (frame), hbox);
gtk_widget_show (hbox);
button = pika_prop_check_button_new (config, "fixed-rule-active", NULL);
gtk_widget_destroy (gtk_bin_get_child (GTK_BIN (button)));
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_rectangle_options_fixed_rule_changed),
private);
combo = pika_prop_enum_combo_box_new (config, "fixed-rule", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Fixed"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
g_signal_connect (combo, "changed",
G_CALLBACK (pika_rectangle_options_fixed_rule_changed),
private);
/* Setup frame content */
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), vbox2);
gtk_widget_show (vbox2);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
/* Fixed aspect entry/buttons */
g_set_weak_pointer (&private->fixed_aspect_hbox,
gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2));
gtk_box_pack_start (GTK_BOX (vbox2), private->fixed_aspect_hbox,
FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, private->fixed_aspect_hbox);
g_object_unref (size_group);
/* don't show */
entry = pika_prop_number_pair_entry_new (config,
"aspect-numerator",
"aspect-denominator",
"default-aspect-numerator",
"default-aspect-denominator",
"overridden-fixed-aspect",
FALSE, TRUE,
":/" "xX*",
TRUE,
0.001, PIKA_MAX_IMAGE_SIZE);
gtk_box_pack_start (GTK_BOX (private->fixed_aspect_hbox), entry,
TRUE, TRUE, 0);
g_signal_connect (entry, "notify::user-override",
G_CALLBACK (pika_rectangle_options_string_current_updates),
config);
g_signal_connect_swapped (config, "notify::use-string-current",
G_CALLBACK (pika_rectangle_options_string_current_updates),
entry);
pika_rectangle_options_setup_ratio_completion (PIKA_RECTANGLE_OPTIONS (tool_options),
entry,
private->aspect_history);
g_set_weak_pointer (&private->aspect_button_box,
pika_prop_enum_icon_box_new (G_OBJECT (entry),
"aspect", "pika", -1, -1));
gtk_box_pack_start (GTK_BOX (private->fixed_aspect_hbox),
private->aspect_button_box, FALSE, FALSE, 0);
/* hide "square" */
children =
gtk_container_get_children (GTK_CONTAINER (private->aspect_button_box));
gtk_widget_hide (children->data);
g_list_free (children);
/* Fixed width entry */
g_set_weak_pointer (&private->fixed_width_entry,
pika_prop_size_entry_new (config,
"desired-fixed-width",
TRUE, "fixed-unit", "%a",
PIKA_SIZE_ENTRY_UPDATE_SIZE,
300));
gtk_box_pack_start (GTK_BOX (vbox2), private->fixed_width_entry,
FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, private->fixed_width_entry);
gtk_widget_hide (private->fixed_width_entry);
/* Fixed height entry */
g_set_weak_pointer (&private->fixed_height_entry,
pika_prop_size_entry_new (config,
"desired-fixed-height",
TRUE, "fixed-unit", "%a",
PIKA_SIZE_ENTRY_UPDATE_SIZE,
300));
gtk_box_pack_start (GTK_BOX (vbox2), private->fixed_height_entry,
FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, private->fixed_height_entry);
gtk_widget_hide (private->fixed_height_entry);
/* Fixed size entry */
g_set_weak_pointer (&private->fixed_size_hbox,
gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2));
gtk_box_pack_start (GTK_BOX (vbox2), private->fixed_size_hbox,
FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, private->fixed_size_hbox);
gtk_widget_hide (private->fixed_size_hbox);
entry = pika_prop_number_pair_entry_new (config,
"desired-fixed-size-width",
"desired-fixed-size-height",
"default-fixed-size-width",
"default-fixed-size-height",
"overridden-fixed-size",
TRUE, FALSE,
"xX*" ":/",
FALSE,
1, PIKA_MAX_IMAGE_SIZE);
gtk_box_pack_start (GTK_BOX (private->fixed_size_hbox), entry,
TRUE, TRUE, 0);
pika_rectangle_options_setup_ratio_completion (PIKA_RECTANGLE_OPTIONS (tool_options),
entry,
private->size_history);
private->size_button_box =
pika_prop_enum_icon_box_new (G_OBJECT (entry),
"aspect", "pika", -1, -1);
gtk_box_pack_start (GTK_BOX (private->fixed_size_hbox),
private->size_button_box, FALSE, FALSE, 0);
/* hide "square" */
children =
gtk_container_get_children (GTK_CONTAINER (private->size_button_box));
gtk_widget_hide (children->data);
g_list_free (children);
}
label_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* X, Y */
frame = pika_rectangle_options_prop_dimension_frame_new (config,
"x", "y",
"position-unit",
_("Position:"),
label_group,
&private->position_entry);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Width, Height */
frame = pika_rectangle_options_prop_dimension_frame_new (config,
"width", "height",
"size-unit",
_("Size:"),
label_group,
&private->size_entry);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
g_object_unref (label_group);
/* the Highlight frame */
{
GtkWidget *scale;
scale = pika_prop_spin_scale_new (config, "highlight-opacity",
0.01, 0.1, 0);
pika_prop_widget_set_factor (scale, 100.0, 1.0, 10.0, 1);
frame = pika_prop_expanding_frame_new (config, "highlight", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
}
/* Guide */
combo = pika_prop_enum_combo_box_new (config, "guide",
PIKA_GUIDES_NONE,
PIKA_GUIDES_DIAGONALS);
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
/* Auto Shrink */
g_set_weak_pointer (&private->auto_shrink_button,
gtk_button_new_with_label (_("Auto Shrink")));
gtk_box_pack_start (GTK_BOX (vbox), private->auto_shrink_button,
FALSE, FALSE, 0);
gtk_widget_set_sensitive (private->auto_shrink_button, FALSE);
gtk_widget_show (private->auto_shrink_button);
button = pika_prop_check_button_new (config, "shrink-merged", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* Setup initial fixed rule widgets */
pika_rectangle_options_fixed_rule_changed (NULL, private);
return vbox;
}
void
pika_rectangle_options_connect (PikaRectangleOptions *options,
PikaImage *image,
GCallback shrink_callback,
gpointer shrink_object)
{
PikaRectangleOptionsPrivate *options_private;
gdouble xres;
gdouble yres;
g_return_if_fail (PIKA_IS_RECTANGLE_OPTIONS (options));
g_return_if_fail (PIKA_IS_IMAGE (image));
g_return_if_fail (shrink_callback != NULL);
g_return_if_fail (shrink_object != NULL);
options_private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (options);
pika_image_get_resolution (image, &xres, &yres);
if (options_private->fixed_width_entry)
{
GtkWidget *entry = options_private->fixed_width_entry;
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0, xres, FALSE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (entry), 0,
0, pika_image_get_width (image));
}
if (options_private->fixed_height_entry)
{
GtkWidget *entry = options_private->fixed_height_entry;
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0, yres, FALSE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (entry), 0,
0, pika_image_get_height (image));
}
if (options_private->position_entry)
{
GtkWidget *entry = options_private->position_entry;
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0, xres, FALSE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (entry), 0,
0, pika_image_get_width (image));
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 1, yres, FALSE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (entry), 1,
0, pika_image_get_height (image));
}
if (options_private->size_entry)
{
GtkWidget *entry = options_private->size_entry;
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0, xres, FALSE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (entry), 0,
0, pika_image_get_width (image));
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 1, yres, FALSE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (entry), 1,
0, pika_image_get_height (image));
}
if (options_private->auto_shrink_button)
{
g_signal_connect_swapped (options_private->auto_shrink_button, "clicked",
shrink_callback,
shrink_object);
gtk_widget_set_sensitive (options_private->auto_shrink_button, TRUE);
}
}
void
pika_rectangle_options_disconnect (PikaRectangleOptions *options,
GCallback shrink_callback,
gpointer shrink_object)
{
PikaRectangleOptionsPrivate *options_private;
g_return_if_fail (PIKA_IS_RECTANGLE_OPTIONS (options));
g_return_if_fail (shrink_callback != NULL);
g_return_if_fail (shrink_object != NULL);
options_private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (options);
if (options_private->auto_shrink_button)
{
gtk_widget_set_sensitive (options_private->auto_shrink_button, FALSE);
g_signal_handlers_disconnect_by_func (options_private->auto_shrink_button,
shrink_callback,
shrink_object);
}
}
/**
* pika_rectangle_options_fixed_rule_active:
* @rectangle_options:
* @fixed_rule:
*
* Returns: %TRUE if @fixed_rule is active, %FALSE otherwise.
*/
gboolean
pika_rectangle_options_fixed_rule_active (PikaRectangleOptions *rectangle_options,
PikaRectangleFixedRule fixed_rule)
{
PikaRectangleOptionsPrivate *private;
g_return_val_if_fail (PIKA_IS_RECTANGLE_OPTIONS (rectangle_options), FALSE);
private = PIKA_RECTANGLE_OPTIONS_GET_PRIVATE (rectangle_options);
return private->fixed_rule_active &&
private->fixed_rule == fixed_rule;
}
static void
pika_rectangle_options_setup_ratio_completion (PikaRectangleOptions *rectangle_options,
GtkWidget *entry,
GtkListStore *history)
{
GtkEntryCompletion *completion;
completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION,
"model", history,
"inline-completion", TRUE,
NULL);
gtk_entry_completion_set_text_column (completion, COLUMN_TEXT);
gtk_entry_set_completion (GTK_ENTRY (entry), completion);
g_object_unref (completion);
g_signal_connect (entry, "ratio-changed",
G_CALLBACK (pika_number_pair_entry_history_add),
history);
g_signal_connect (completion, "match-selected",
G_CALLBACK (pika_number_pair_entry_history_select),
entry);
}
static gboolean
pika_number_pair_entry_history_select (GtkEntryCompletion *completion,
GtkTreeModel *model,
GtkTreeIter *iter,
PikaNumberPairEntry *entry)
{
gdouble left_number;
gdouble right_number;
gtk_tree_model_get (model, iter,
COLUMN_LEFT_NUMBER, &left_number,
COLUMN_RIGHT_NUMBER, &right_number,
-1);
pika_number_pair_entry_set_values (entry, left_number, right_number);
return TRUE;
}
static void
pika_number_pair_entry_history_add (GtkWidget *entry,
GtkTreeModel *model)
{
GValue value = G_VALUE_INIT;
GtkTreeIter iter;
gboolean iter_valid;
gdouble left_number;
gdouble right_number;
const gchar *text;
text = gtk_entry_get_text (GTK_ENTRY (entry));
pika_number_pair_entry_get_values (PIKA_NUMBER_PAIR_ENTRY (entry),
&left_number,
&right_number);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gtk_tree_model_get_value (model, &iter, COLUMN_TEXT, &value);
if (strcmp (text, g_value_get_string (&value)) == 0)
{
g_value_unset (&value);
break;
}
g_value_unset (&value);
}
if (iter_valid)
{
gtk_list_store_move_after (GTK_LIST_STORE (model), &iter, NULL);
}
else
{
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
COLUMN_LEFT_NUMBER, left_number,
COLUMN_RIGHT_NUMBER, right_number,
COLUMN_TEXT, text,
-1);
/* FIXME: limit the size of the history */
}
}