diff --git a/app/core/core-enums.c b/app/core/core-enums.c index d414e467710b4772264b02688cd989a9f9717d93..12f49e93113c34d60bb0dfa52552ea3d95c10fe7 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -55,6 +55,10 @@ gimp_alignment_type_get_type (void) { GIMP_ARRANGE_VFILL, "GIMP_ARRANGE_VFILL", "arrange-vfill" }, { GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP, "GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP", "distribute-even-horizontal-gap" }, { GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP, "GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP", "distribute-even-vertical-gap" }, + { GIMP_SHIFT_FROM_TOP, "GIMP_SHIFT_FROM_TOP", "shift-from-top" }, + { GIMP_SHIFT_FROM_BOTTOM, "GIMP_SHIFT_FROM_BOTTOM", "shift-from-bottom" }, + { GIMP_SHIFT_FROM_LEFT, "GIMP_SHIFT_FROM_LEFT", "shift-from-left" }, + { GIMP_SHIFT_FROM_RIGHT, "GIMP_SHIFT_FROM_RIGHT", "shift-from-right" }, { 0, NULL, NULL } }; @@ -70,6 +74,10 @@ gimp_alignment_type_get_type (void) { GIMP_ARRANGE_VFILL, NC_("alignment-type", "Distribute anchor points vertically evenly"), NULL }, { GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP, NC_("alignment-type", "Distribute horizontally with even horizontal gaps"), NULL }, { GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP, NC_("alignment-type", "Distribute vertically with even vertical gaps"), NULL }, + { GIMP_SHIFT_FROM_TOP, NC_("alignment-type", "Align to the top and distribute vertically with offset"), NULL }, + { GIMP_SHIFT_FROM_BOTTOM, NC_("alignment-type", "Align to the bottom and distribute vertically with offset"), NULL }, + { GIMP_SHIFT_FROM_LEFT, NC_("alignment-type", "Align to the left and distribute horizontally with offset"), NULL }, + { GIMP_SHIFT_FROM_RIGHT, NC_("alignment-type", "Align to the right and distribute horizontally with offset"), NULL }, { 0, NULL, NULL } }; diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 32fdb59122bf6ccfbfa809688b31b30b31a5fcaa..813da69f57bbaba13dc42f386f4ec259e01c03b8 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -52,16 +52,20 @@ GType gimp_alignment_type_get_type (void) G_GNUC_CONST; typedef enum /*< pdb-skip >*/ { - GIMP_ALIGN_LEFT, /*< desc="Align to the left" >*/ - GIMP_ALIGN_HCENTER, /*< desc="Center horizontally" >*/ - GIMP_ALIGN_RIGHT, /*< desc="Align to the right" >*/ - GIMP_ALIGN_TOP, /*< desc="Align to the top" >*/ - GIMP_ALIGN_VCENTER, /*< desc="Center vertically" >*/ - GIMP_ALIGN_BOTTOM, /*< desc="Align to the bottom" >*/ - GIMP_ARRANGE_HFILL, /*< desc="Distribute anchor points horizontally evenly" >*/ - GIMP_ARRANGE_VFILL, /*< desc="Distribute anchor points vertically evenly" >*/ - GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP, /*< desc="Distribute horizontally with even horizontal gaps" >*/ - GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP, /*< desc="Distribute vertically with even vertical gaps" >*/ + GIMP_ALIGN_LEFT, /*< desc="Align to the left" >*/ + GIMP_ALIGN_HCENTER, /*< desc="Center horizontally" >*/ + GIMP_ALIGN_RIGHT, /*< desc="Align to the right" >*/ + GIMP_ALIGN_TOP, /*< desc="Align to the top" >*/ + GIMP_ALIGN_VCENTER, /*< desc="Center vertically" >*/ + GIMP_ALIGN_BOTTOM, /*< desc="Align to the bottom" >*/ + GIMP_ARRANGE_HFILL, /*< desc="Distribute anchor points horizontally evenly" >*/ + GIMP_ARRANGE_VFILL, /*< desc="Distribute anchor points vertically evenly" >*/ + GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP, /*< desc="Distribute horizontally with even horizontal gaps" >*/ + GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP, /*< desc="Distribute vertically with even vertical gaps" >*/ + GIMP_SHIFT_FROM_TOP, /*< desc="Align to the top and distribute vertically with offset" >*/ + GIMP_SHIFT_FROM_BOTTOM, /*< desc="Align to the bottom and distribute vertically with offset" >*/ + GIMP_SHIFT_FROM_LEFT, /*< desc="Align to the left and distribute horizontally with offset" >*/ + GIMP_SHIFT_FROM_RIGHT, /*< desc="Align to the right and distribute horizontally with offset" >*/ } GimpAlignmentType; diff --git a/app/core/gimpimage-arrange.c b/app/core/gimpimage-arrange.c index 038d1784fdcc004b904fc29e3ea23fea13e1f7b5..d0083a36d976e6742ec5f79ae9af3cc99ea3e67e 100644 --- a/app/core/gimpimage-arrange.c +++ b/app/core/gimpimage-arrange.c @@ -52,24 +52,24 @@ static gint offset_compare (gconstpointer a, /** * gimp_image_arrange_objects: - * @image: The #GimpImage to which the objects belong. - * @list: A #GList of objects to be aligned. - * @align_x: Relative X coordinate of point on each target object to bring into alignment. - * @align_y: Relative Y coordinate of point on each target object to bring into alignment. - * @reference: The #GObject to align the targets with, or %NULL. - * @reference_alignment: The point on the reference object to align the target item with.. - * @align_contents: Take into account non-empty contents rather than item borders. + * @image: The #GimpImage to which the objects belong. + * @list: A #GList of objects to be aligned. + * @align_x: Relative X coordinate of point on each target object to bring into alignment. + * @align_y: Relative Y coordinate of point on each target object to bring into alignment. + * @reference: The #GObject to align the targets with, or %NULL. + * @align_type: The type of alignment or distribution. + * @align_contents: Take into account non-empty contents rather than item borders. * * This function shifts the positions of a set of target objects, * which can be "items" or guides, to bring them into a specified type * of alignment with a reference object, which can be an item, guide, - * or image. If the requested alignment does not make sense (i.e., + * or image. If the requested alignment does not make sense (e.g. * trying to align a vertical guide vertically), nothing happens and * no error message is generated. * * The objects in the list are sorted into increasing order before * being arranged, where the order is defined by the type of alignment - * being requested. If the @reference argument is %NULL, then the + * being requested. If the @reference argument is %NULL, then the * first object in the sorted list is used as reference. */ void @@ -78,8 +78,9 @@ gimp_image_arrange_objects (GimpImage *image, gdouble align_x, gdouble align_y, GObject *reference, - GimpAlignmentType reference_alignment, - gboolean align_contents) + GimpAlignmentType align_type, + gboolean align_contents, + gint offset) { gdouble reference_x = 0.0; gdouble reference_y = 0.0; @@ -115,7 +116,7 @@ gimp_image_arrange_objects (GimpImage *image, } /* get offsets used for sorting */ - switch (reference_alignment) + switch (align_type) { /* order vertically for horizontal alignment */ case GIMP_ALIGN_LEFT: @@ -124,13 +125,15 @@ gimp_image_arrange_objects (GimpImage *image, if (GIMP_IS_GUIDE (reference) && gimp_guide_get_orientation (GIMP_GUIDE (reference)) == GIMP_ORIENTATION_HORIZONTAL) return; + case GIMP_SHIFT_FROM_LEFT: + case GIMP_SHIFT_FROM_RIGHT: use_obj_x_offset = TRUE; use_ref_x_offset = TRUE; - if (reference_alignment == GIMP_ALIGN_HCENTER) + if (align_type == GIMP_ALIGN_HCENTER) reference_x = 0.5; - else if (reference_alignment == GIMP_ALIGN_RIGHT) + else if (align_type == GIMP_ALIGN_RIGHT) reference_x = 1.0; do_x = TRUE; @@ -152,10 +155,12 @@ gimp_image_arrange_objects (GimpImage *image, if (GIMP_IS_GUIDE (reference) && gimp_guide_get_orientation (GIMP_GUIDE (reference)) == GIMP_ORIENTATION_VERTICAL) return; + case GIMP_SHIFT_FROM_TOP: + case GIMP_SHIFT_FROM_BOTTOM: - if (reference_alignment == GIMP_ALIGN_VCENTER) + if (align_type == GIMP_ALIGN_VCENTER) reference_y = 0.5; - else if (reference_alignment == GIMP_ALIGN_BOTTOM) + else if (align_type == GIMP_ALIGN_BOTTOM) reference_y = 1.0; do_y = TRUE; @@ -200,10 +205,10 @@ gimp_image_arrange_objects (GimpImage *image, gint n; gdouble fill_offset = 0; - if (reference_alignment == GIMP_ARRANGE_HFILL || - reference_alignment == GIMP_ARRANGE_VFILL || - reference_alignment == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP || - reference_alignment == GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP) + if (align_type == GIMP_ARRANGE_HFILL || + align_type == GIMP_ARRANGE_VFILL || + align_type == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP || + align_type == GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP) { /* Distribution does not use the reference. Extreme coordinate items * are used instead. @@ -214,14 +219,14 @@ gimp_image_arrange_objects (GimpImage *image, z0 = GPOINTER_TO_INT (g_object_get_data (object_list->data, "align-offset")); distr_length = GPOINTER_TO_INT (g_object_get_data (last_object->data, "align-offset")) - z0; - if (reference_alignment == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP || - reference_alignment == GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP) + if (align_type == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP || + align_type == GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP) { for (list = object_list; list && list->next; list = g_list_next (list)) { gint obj_len; - if (reference_alignment == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP) + if (align_type == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP) obj_len = GPOINTER_TO_INT (g_object_get_data (list->data, "align-width")); else obj_len = GPOINTER_TO_INT (g_object_get_data (list->data, "align-height")); @@ -242,6 +247,29 @@ gimp_image_arrange_objects (GimpImage *image, object_list = g_list_delete_link (object_list, last_object); object_list = g_list_delete_link (object_list, object_list); } + else if (align_type == GIMP_SHIFT_FROM_TOP || + align_type == GIMP_SHIFT_FROM_LEFT) + { + z0 = GPOINTER_TO_INT (g_object_get_data (object_list->data, "align-offset")); + fill_offset = offset; + + /* First object won't move. */ + object_list = g_list_delete_link (object_list, object_list); + } + else if (align_type == GIMP_SHIFT_FROM_BOTTOM || + align_type == GIMP_SHIFT_FROM_RIGHT) + { + GList *last_object = g_list_last (object_list); + + z0 = GPOINTER_TO_INT (g_object_get_data (last_object->data, "align-offset")); + fill_offset = -offset; + + /* Last object won't move. */ + object_list = g_list_delete_link (object_list, last_object); + + /* Start from the end. */ + object_list = g_list_reverse (object_list); + } else { if (reference == NULL) @@ -270,15 +298,15 @@ gimp_image_arrange_objects (GimpImage *image, z1 = GPOINTER_TO_INT (g_object_get_data (target, "align-offset")); - if (reference_alignment == GIMP_ARRANGE_HFILL) + if (align_type == GIMP_ARRANGE_HFILL) { xtranslate = ROUND (z0 - z1 + n * fill_offset); } - else if (reference_alignment == GIMP_ARRANGE_VFILL) + else if (align_type == GIMP_ARRANGE_VFILL) { ytranslate = ROUND (z0 - z1 + n * fill_offset); } - else if (reference_alignment == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP) + else if (align_type == GIMP_DISTRIBUTE_EVEN_HORIZONTAL_GAP) { gint obj_len; @@ -287,7 +315,7 @@ gimp_image_arrange_objects (GimpImage *image, obj_len = GPOINTER_TO_INT (g_object_get_data (target, "align-width")); z0 = z0 + fill_offset + obj_len; } - else if (reference_alignment == GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP) + else if (align_type == GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP) { gint obj_len; @@ -296,6 +324,16 @@ gimp_image_arrange_objects (GimpImage *image, obj_len = GPOINTER_TO_INT (g_object_get_data (target, "align-height")); z0 = z0 + fill_offset + obj_len; } + else if (align_type == GIMP_SHIFT_FROM_TOP || + align_type == GIMP_SHIFT_FROM_BOTTOM) + { + ytranslate = ROUND (z0 - z1 + n * fill_offset); + } + else if (align_type == GIMP_SHIFT_FROM_LEFT || + align_type == GIMP_SHIFT_FROM_RIGHT) + { + xtranslate = ROUND (z0 - z1 + n * fill_offset); + } else /* the normal computing, when we don't depend on the * width or height of the reference object */ diff --git a/app/core/gimpimage-arrange.h b/app/core/gimpimage-arrange.h index e494a947cd75a6f02a19e46a3e50226e9443e6fe..fac1c7d9ff10071c071230709ac4c41eb473f796 100644 --- a/app/core/gimpimage-arrange.h +++ b/app/core/gimpimage-arrange.h @@ -24,4 +24,5 @@ void gimp_image_arrange_objects (GimpImage *image, gdouble align_y, GObject *reference, GimpAlignmentType reference_alignment, - gboolean align_contents); + gboolean align_contents, + gint offset); diff --git a/app/tools/gimpalignoptions.c b/app/tools/gimpalignoptions.c index 775f9c733c7418b3e0805955bd0bad792a8c991a..8e65e58fb0330c7c005dd6e7d4738831bddae998 100644 --- a/app/tools/gimpalignoptions.c +++ b/app/tools/gimpalignoptions.c @@ -44,10 +44,12 @@ #include "gimp-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 +#define ALIGN_VER_N_BUTTONS 3 +#define ALIGN_HOR_N_BUTTONS 3 +#define DISTR_VER_N_BUTTONS 2 +#define DISTR_HOR_N_BUTTONS 2 +#define ALIGN_DISTR_VER_N_BUTTONS 2 +#define ALIGN_DISTR_HOR_N_BUTTONS 2 enum @@ -62,9 +64,11 @@ enum PROP_ALIGN_REFERENCE, PROP_ALIGN_LAYERS, PROP_ALIGN_PATHS, + PROP_ALIGN_GUIDES, PROP_ALIGN_CONTENTS, PROP_PIVOT_X, PROP_PIVOT_Y, + PROP_SHIFT_OFFSET, }; struct _GimpAlignOptionsPrivate @@ -73,9 +77,11 @@ struct _GimpAlignOptionsPrivate gboolean align_layers; gboolean align_paths; + gboolean align_guides; gboolean align_contents; gdouble pivot_x; gdouble pivot_y; + gint shift_offset; GList *selected_guides; GObject *reference; @@ -85,11 +91,14 @@ struct _GimpAlignOptionsPrivate GtkWidget *reference_box; GtkWidget *reference_label; GtkWidget *pivot_selector; + GtkWidget *anchor_label; 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]; + GtkWidget *offset_ver_button[ALIGN_DISTR_VER_N_BUTTONS]; + GtkWidget *offset_hor_button[ALIGN_DISTR_HOR_N_BUTTONS]; }; @@ -116,6 +125,8 @@ static void gimp_align_options_reference_removed (GObject *objec static void gimp_align_options_pivot_changed (GimpPivotSelector *selector, GimpAlignOptions *options); +static const gchar * gimp_align_options_get_anchor_text (GimpAlignOptions *options); + G_DEFINE_TYPE_WITH_PRIVATE (GimpAlignOptions, gimp_align_options, GIMP_TYPE_TOOL_OPTIONS) @@ -165,6 +176,12 @@ gimp_align_options_class_init (GimpAlignOptionsClass *klass) _("Selected paths will be aligned or distributed by the tool"), FALSE, GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_GUIDES, + "align-guides", + _("Pick guides"), + _("Picked guides will be aligned or distributed by the tool"), + FALSE, + GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_CONTENTS, "align-contents", _("Use extents of layer contents"), @@ -185,6 +202,13 @@ gimp_align_options_class_init (GimpAlignOptionsClass *klass) NULL, 0.0, 1.0, 0.5, GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_INT (object_class, PROP_SHIFT_OFFSET, + "shift-offset", + "Offset in pixels when shifting", + NULL, + -G_MAXINT, G_MAXINT, 10, + GIMP_PARAM_STATIC_STRINGS); } static void @@ -230,6 +254,12 @@ gimp_align_options_set_property (GObject *object, options->priv->align_paths = g_value_get_boolean (value); gimp_align_options_update_area (options); break; + case PROP_ALIGN_GUIDES: + options->priv->align_guides = g_value_get_boolean (value); + if (! options->priv->align_guides) + g_clear_pointer (&options->priv->selected_guides, g_list_free); + gimp_align_options_update_area (options); + break; case PROP_ALIGN_CONTENTS: options->priv->align_contents = g_value_get_boolean (value); @@ -242,6 +272,10 @@ gimp_align_options_set_property (GObject *object, options->priv->pivot_y = g_value_get_double (value); break; + case PROP_SHIFT_OFFSET: + options->priv->shift_offset = g_value_get_int (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -268,6 +302,9 @@ gimp_align_options_get_property (GObject *object, case PROP_ALIGN_PATHS: g_value_set_boolean (value, options->priv->align_paths); break; + case PROP_ALIGN_GUIDES: + g_value_set_boolean (value, options->priv->align_guides); + break; case PROP_ALIGN_CONTENTS: g_value_set_boolean (value, options->priv->align_contents); @@ -280,6 +317,10 @@ gimp_align_options_get_property (GObject *object, g_value_set_double (value, options->priv->pivot_y); break; + case PROP_SHIFT_OFFSET: + g_value_set_int (value, options->priv->shift_offset); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -312,21 +353,25 @@ gimp_align_options_button_new (GimpAlignOptions *options, switch (action) { case GIMP_ALIGN_LEFT: + case GIMP_SHIFT_FROM_LEFT: icon_name = GIMP_ICON_GRAVITY_WEST; break; case GIMP_ALIGN_HCENTER: icon_name = GIMP_ICON_CENTER_HORIZONTAL; break; case GIMP_ALIGN_RIGHT: + case GIMP_SHIFT_FROM_RIGHT: icon_name = GIMP_ICON_GRAVITY_EAST; break; case GIMP_ALIGN_TOP: + case GIMP_SHIFT_FROM_TOP: icon_name = GIMP_ICON_GRAVITY_NORTH; break; case GIMP_ALIGN_VCENTER: icon_name = GIMP_ICON_CENTER_VERTICAL; break; case GIMP_ALIGN_BOTTOM: + case GIMP_SHIFT_FROM_BOTTOM: icon_name = GIMP_ICON_GRAVITY_SOUTH; break; case GIMP_ARRANGE_HFILL: @@ -375,21 +420,19 @@ gimp_align_options_gui (GimpToolOptions *tool_options) GimpAlignOptions *options = GIMP_ALIGN_OPTIONS (tool_options); GtkWidget *vbox = gimp_tool_options_gui (tool_options); GtkWidget *widget; + GtkWidget *popover; GtkWidget *section_vbox; GtkWidget *items_grid; + GtkWidget *guide_box; GtkWidget *hbox; GtkWidget *frame; GtkWidget *combo; gchar *text; gint n = 0; - /* Selected objects */ - frame = gimp_frame_new (_("Targets")); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); - gtk_widget_show (frame); - + /* SECTION: Objects */ section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_container_add (GTK_CONTAINER (frame), section_vbox); + gtk_container_add (GTK_CONTAINER (vbox), section_vbox); gtk_widget_show (section_vbox); items_grid = gtk_grid_new (); @@ -404,20 +447,14 @@ gimp_align_options_gui (GimpToolOptions *tool_options) widget = gimp_prop_check_button_new (config, "align-paths", NULL); gtk_grid_attach (GTK_GRID (items_grid), widget, 0, 1, 1, 1); - options->priv->pivot_selector = gimp_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")); - gimp_pivot_selector_set_position (GIMP_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 (gimp_align_options_pivot_changed), - options); + guide_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1); + widget = gimp_prop_expanding_frame_new (config, "align-guides", + NULL, guide_box, NULL); + gtk_grid_attach (GTK_GRID (items_grid), widget, 0, 2, 1, 1); + gtk_widget_show (widget); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (guide_box), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); widget = gtk_image_new_from_icon_name (GIMP_ICON_CURSOR, GTK_ICON_SIZE_BUTTON); @@ -437,11 +474,49 @@ gimp_align_options_gui (GimpToolOptions *tool_options) gtk_widget_show (widget); widget = gtk_label_new (NULL); - gtk_box_pack_start (GTK_BOX (section_vbox), widget, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (guide_box), widget, FALSE, FALSE, 0); gtk_widget_show (widget); options->priv->selected_guides_label = widget; - /* Align frame */ + 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_button_new_from_icon_name (GIMP_ICON_LAYER_ANCHOR, GTK_ICON_SIZE_BUTTON); + gtk_widget_set_tooltip_text (widget, _("Set which point in each item will be aligned or distributed")); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + /* The popup for the anchor point selection */ + popover = gtk_popover_new (widget); + options->priv->pivot_selector = gimp_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")); + gimp_pivot_selector_set_position (GIMP_PIVOT_SELECTOR (options->priv->pivot_selector), + options->priv->pivot_x, options->priv->pivot_y); + gtk_container_add (GTK_CONTAINER (popover), options->priv->pivot_selector); + gtk_widget_show (options->priv->pivot_selector); + + g_signal_connect_swapped (widget, "clicked", + G_CALLBACK (gtk_popover_popup), + popover); + + /* The anchor point label */ + text = g_strdup_printf (_("Anchor point: %s"), + gimp_align_options_get_anchor_text (options)); + 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); + options->priv->anchor_label = widget; + + g_signal_connect (options->priv->pivot_selector, "changed", + G_CALLBACK (gimp_align_options_pivot_changed), + options); + + /* SECTION: Align */ frame = gimp_frame_new (_("Align")); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); @@ -511,7 +586,7 @@ gimp_align_options_gui (GimpToolOptions *tool_options) gimp_align_options_button_new (options, GIMP_ALIGN_BOTTOM, hbox, _("Align anchor points of targets on bottom of reference")); - /* Distribute frame */ + /* SECTION: Distribute */ frame = gimp_frame_new (_("Distribute")); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); @@ -544,6 +619,39 @@ gimp_align_options_gui (GimpToolOptions *tool_options) gimp_align_options_button_new (options, GIMP_DISTRIBUTE_EVEN_VERTICAL_GAP, hbox, _("Distribute vertically with even vertical gaps")); + /* SECTION: Shift by Offset */ + frame = gimp_frame_new (_("Shift")); + 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->offset_hor_button[n++] = + gimp_align_options_button_new (options, GIMP_SHIFT_FROM_LEFT, hbox, + _("Align to the left and distribute horizontally with offset")); + options->priv->offset_hor_button[n++] = + gimp_align_options_button_new (options, GIMP_SHIFT_FROM_RIGHT, hbox, + _("Align to the right and distribute horizontally with offset")); + + 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->offset_ver_button[n++] = + gimp_align_options_button_new (options, GIMP_SHIFT_FROM_TOP, hbox, + _("Align to the top and distribute vertically with offset")); + options->priv->offset_ver_button[n++] = + gimp_align_options_button_new (options, GIMP_SHIFT_FROM_BOTTOM, hbox, + _("Align to the bottom and distribute vertically with offset")); + g_signal_connect_object (gimp_get_user_context (GIMP_CONTEXT (options)->gimp), "image-changed", G_CALLBACK (gimp_align_options_image_changed), @@ -552,6 +660,18 @@ gimp_align_options_gui (GimpToolOptions *tool_options) gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT (options)->gimp)), 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_label_new (_("Offset:")); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gimp_prop_spin_button_new (config, "shift-offset", 1, 20, 0); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + return vbox; } @@ -582,7 +702,7 @@ gimp_align_options_get_objects (GimpAlignOptions *options) objects = g_list_concat (objects, paths); } - if (options->priv->selected_guides) + if (options->priv->align_guides && options->priv->selected_guides) { GList *guides; @@ -671,11 +791,26 @@ gimp_align_options_align_contents (GimpAlignOptions *options) return options->priv->align_contents; } +gboolean +gimp_align_options_align_guides (GimpAlignOptions *options) +{ + return options->priv->align_guides; +} + +gint +gimp_align_options_get_shift_offset (GimpAlignOptions *options) +{ + return options->priv->shift_offset; +} + void gimp_align_options_pick_guide (GimpAlignOptions *options, GimpGuide *guide, gboolean extend) { + if (! options->priv->align_guides) + return; + if (! extend) g_clear_pointer (&options->priv->selected_guides, g_list_free); @@ -761,8 +896,8 @@ gimp_align_options_update_area (GimpAlignOptions *options) n_items += g_list_length (layers); if (options->priv->align_paths) n_items += g_list_length (paths); - - n_items += g_list_length (options->priv->selected_guides); + if (options->priv->align_guides) + n_items += g_list_length (options->priv->selected_guides); } if (n_items > 0) @@ -787,9 +922,13 @@ gimp_align_options_update_area (GimpAlignOptions *options) 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); + for (gint i = 0; i < ALIGN_DISTR_HOR_N_BUTTONS; i++) + gtk_widget_set_sensitive (options->priv->offset_hor_button[i], enable_hor_distr); + for (gint i = 0; i < ALIGN_DISTR_VER_N_BUTTONS; i++) + gtk_widget_set_sensitive (options->priv->offset_ver_button[i], enable_ver_distr); /* Update the guide picking widgets. */ - if (options->priv->selected_guides) + if (options->priv->align_guides && options->priv->selected_guides) { gchar *tmp_txt; @@ -881,4 +1020,46 @@ gimp_align_options_pivot_changed (GimpPivotSelector *selector, "pivot-x", x, "pivot-y", y, NULL); + + if (options->priv->anchor_label) + { + gchar *text; + + text = g_strdup_printf (_("Anchor point: %s"), + gimp_align_options_get_anchor_text (options)); + gtk_label_set_text (GTK_LABEL (options->priv->anchor_label), text); + g_free (text); + } +} + +static const gchar * +gimp_align_options_get_anchor_text (GimpAlignOptions *options) +{ + if (options->priv->pivot_x == 0.0) + { + if (options->priv->pivot_y == 0.0) + return _("top-left"); + else if (options->priv->pivot_y == 0.5) + return _("left"); + else + return _("bottom-left"); + } + else if (options->priv->pivot_x == 0.5) + { + if (options->priv->pivot_y == 0.0) + return _("top"); + else if (options->priv->pivot_y == 0.5) + return _("center"); + else + return _("bottom"); + } + else + { + if (options->priv->pivot_y == 0.0) + return _("top-right"); + else if (options->priv->pivot_y == 0.5) + return _("right"); + else + return _("bottom-right"); + } } diff --git a/app/tools/gimpalignoptions.h b/app/tools/gimpalignoptions.h index 4c20cb7ed155aac93ea1a67bd24f85e9e8553246..104e86934985f2628f9781b7ede78a601dff4f44 100644 --- a/app/tools/gimpalignoptions.h +++ b/app/tools/gimpalignoptions.h @@ -64,6 +64,8 @@ void gimp_align_options_pick_reference (GimpAlignOptions *options, GObject * gimp_align_options_get_reference (GimpAlignOptions *options, gboolean blink_if_none); gboolean gimp_align_options_align_contents (GimpAlignOptions *options); +gboolean gimp_align_options_align_guides (GimpAlignOptions *options); +gint gimp_align_options_get_shift_offset (GimpAlignOptions *options); void gimp_align_options_pick_guide (GimpAlignOptions *options, GimpGuide *guide, diff --git a/app/tools/gimpaligntool.c b/app/tools/gimpaligntool.c index fced3c55b08ee289bc1dd4d25f45d8bef2c7c84d..07e823a1bd5cc75041cab9e1030b896d948b25ad 100644 --- a/app/tools/gimpaligntool.c +++ b/app/tools/gimpaligntool.c @@ -191,6 +191,9 @@ gimp_align_tool_constructed (GObject *object) g_signal_connect_object (options, "notify::align-contents", G_CALLBACK (gimp_align_tool_redraw), align_tool, G_CONNECT_SWAPPED); + g_signal_connect_object (options, "notify::align-guides", + G_CALLBACK (gimp_align_tool_redraw), + align_tool, G_CONNECT_SWAPPED); g_signal_connect_object (gimp_get_user_context (GIMP_CONTEXT (options)->gimp), "display-changed", G_CALLBACK (gimp_align_tool_display_changed), @@ -545,6 +548,7 @@ gimp_align_tool_status_update (GimpTool *tool, gboolean proximity) { GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (tool); + GimpAlignOptions *options = GIMP_ALIGN_TOOL_GET_OPTIONS (align_tool); gchar *status = NULL; GdkModifierType extend_mask; @@ -576,16 +580,19 @@ gimp_align_tool_status_update (GimpTool *tool, break; case ALIGN_TOOL_ALIGN_IDLE: - status = g_strdup (_("Click on a guide to add it to objects to align, " - "click anywhere else to unselect all guides")); + if (gimp_align_options_align_guides (options)) + status = g_strdup (_("Click on a guide to add it to objects to align, " + "click anywhere else to unselect all guides")); break; case ALIGN_TOOL_ALIGN_PICK_GUIDE: - status = gimp_suggest_modifiers (_("Click to select this guide for alignment"), - extend_mask & ~state, - NULL, NULL, NULL); + if (gimp_align_options_align_guides (options)) + status = gimp_suggest_modifiers (_("Click to select this guide for alignment"), + extend_mask & ~state, + NULL, NULL, NULL); break; case ALIGN_TOOL_ALIGN_ADD_GUIDE: - status = g_strdup (_("Click to add this guide to the list of objects to align")); + if (gimp_align_options_align_guides (options)) + status = g_strdup (_("Click to add this guide to the list of objects to align")); break; case ALIGN_TOOL_NO_ACTION: @@ -811,7 +818,8 @@ gimp_align_tool_align (GimpAlignTool *align_tool, align_x, align_y, reference_object, align_type, - gimp_align_options_align_contents (options)); + gimp_align_options_align_contents (options), + gimp_align_options_get_shift_offset (options)); gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool));