app: new option "Use extents of layer contents" to Align tool.

Instead of using the layer borders, we use the bounding box for the contents.
This is similar to first run "Crop to Content" on every selected layer except
we don't actually need to crop. Therefore we can work on bigger layer than the
actual content while still arranging them based on content bounds.

So often the result of alignment/distribution feels wrong because it doesn't
correspond to the content we are seeing. With this option, we'll have the option
to choose the desired behavior.
This commit is contained in:
Jehan 2022-10-18 00:30:39 +02:00
parent 9be6a6b711
commit c8547d0a50
5 changed files with 81 additions and 19 deletions

View File

@ -30,15 +30,19 @@
#include "gimpimage-undo.h"
#include "gimpitem.h"
#include "gimpguide.h"
#include "gimppickable.h"
#include "gimppickable-auto-shrink.h"
#include "gimp-intl.h"
static GList * sort_by_offset (GList *list);
static void compute_offsets (GList *list,
GimpAlignmentType alignment);
GimpAlignmentType alignment,
gboolean align_contents);
static void compute_offset (GObject *object,
GimpAlignmentType alignment);
GimpAlignmentType alignment,
gboolean align_contents);
static gint offset_compare (gconstpointer a,
gconstpointer b);
@ -50,6 +54,7 @@ static gint offset_compare (gconstpointer a,
* @alignment: The 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.
* @offset: How much to shift the target from perfect alignment..
*
* This function shifts the positions of a set of target objects,
@ -75,6 +80,7 @@ gimp_image_arrange_objects (GimpImage *image,
GimpAlignmentType alignment,
GObject *reference,
GimpAlignmentType reference_alignment,
gboolean align_contents,
gint offset)
{
gboolean do_x = FALSE;
@ -93,7 +99,7 @@ gimp_image_arrange_objects (GimpImage *image,
case GIMP_ALIGN_HCENTER:
case GIMP_ALIGN_RIGHT:
do_x = TRUE;
compute_offsets (list, GIMP_ALIGN_TOP);
compute_offsets (list, GIMP_ALIGN_TOP, align_contents);
break;
/* order horizontally for horizontal arrangement */
@ -102,7 +108,7 @@ gimp_image_arrange_objects (GimpImage *image,
case GIMP_ARRANGE_RIGHT:
case GIMP_ARRANGE_HFILL:
do_x = TRUE;
compute_offsets (list, alignment);
compute_offsets (list, alignment, align_contents);
break;
/* order horizontally for vertical alignment */
@ -110,7 +116,7 @@ gimp_image_arrange_objects (GimpImage *image,
case GIMP_ALIGN_VCENTER:
case GIMP_ALIGN_BOTTOM:
do_y = TRUE;
compute_offsets (list, GIMP_ALIGN_LEFT);
compute_offsets (list, GIMP_ALIGN_LEFT, align_contents);
break;
/* order vertically for vertical arrangement */
@ -119,7 +125,7 @@ gimp_image_arrange_objects (GimpImage *image,
case GIMP_ARRANGE_BOTTOM:
case GIMP_ARRANGE_VFILL:
do_y = TRUE;
compute_offsets (list, alignment);
compute_offsets (list, alignment, align_contents);
break;
default:
@ -129,7 +135,7 @@ gimp_image_arrange_objects (GimpImage *image,
object_list = sort_by_offset (list);
/* now get offsets used for aligning */
compute_offsets (list, alignment);
compute_offsets (list, alignment, align_contents);
if (reference == NULL)
{
@ -139,7 +145,7 @@ gimp_image_arrange_objects (GimpImage *image,
}
else
{
compute_offset (reference, reference_alignment);
compute_offset (reference, reference_alignment, FALSE);
}
z0 = GPOINTER_TO_INT (g_object_get_data (reference, "align-offset"));
@ -266,17 +272,19 @@ offset_compare (gconstpointer a,
*/
static void
compute_offsets (GList *list,
GimpAlignmentType alignment)
GimpAlignmentType alignment,
gboolean align_contents)
{
GList *l;
for (l = list; l; l = g_list_next (l))
compute_offset (l->data, alignment);
compute_offset (l->data, alignment, align_contents);
}
static void
compute_offset (GObject *object,
GimpAlignmentType alignment)
GimpAlignmentType alignment,
gboolean align_contents)
{
gint object_offset_x = 0;
gint object_offset_y = 0;
@ -304,7 +312,28 @@ compute_offset (GObject *object,
&object_width,
&object_height);
if (align_contents && GIMP_IS_PICKABLE (object))
{
gint x;
gint y;
gint width;
gint height;
if (gimp_pickable_auto_shrink (GIMP_PICKABLE (object),
0, 0,
gimp_item_get_width (GIMP_ITEM (object)),
gimp_item_get_height (GIMP_ITEM (object)),
&x, &y, &width, &height) == GIMP_AUTO_SHRINK_SHRINK)
{
object_offset_x += x;
object_offset_y += y;
object_width = width;
object_height = height;
}
}
gimp_item_get_offset (item, &off_x, &off_y);
object_offset_x += off_x;
object_offset_y += off_y;
}

View File

@ -24,6 +24,7 @@ void gimp_image_arrange_objects (GimpImage *image,
GimpAlignmentType alignment,
GObject *reference,
GimpAlignmentType reference_alignment,
gboolean align_contents,
gint offset);
#endif /* __GIMP_IMAGE_ARRANGE_H__ */

View File

@ -34,6 +34,7 @@
#include "vectors/gimpvectors.h"
#include "widgets/gimppropwidgets.h"
#include "widgets/gimpwidgets-utils.h"
#include "gimpalignoptions.h"
@ -56,12 +57,14 @@ enum
PROP_OFFSET_Y,
PROP_ALIGN_LAYERS,
PROP_ALIGN_VECTORS,
PROP_ALIGN_CONTENTS,
};
struct _GimpAlignOptionsPrivate
{
gboolean align_layers;
gboolean align_vectors;
gboolean align_contents;
GList *selected_guides;
GObject *reference;
@ -158,6 +161,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_CONTENTS,
"align-contents",
_("Use extents of layer contents"),
_("Instead of aligning or distributing on layer borders, use its content bounding box"),
TRUE,
GIMP_PARAM_STATIC_STRINGS);
}
static void
@ -209,6 +218,10 @@ gimp_align_options_set_property (GObject *object,
gimp_align_options_update_area (options);
break;
case PROP_ALIGN_CONTENTS:
options->priv->align_contents = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -243,6 +256,10 @@ gimp_align_options_get_property (GObject *object,
g_value_set_boolean (value, options->priv->align_vectors);
break;
case PROP_ALIGN_CONTENTS:
g_value_set_boolean (value, options->priv->align_contents);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -360,14 +377,24 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
gint n = 0;
/* Selected objects */
widget = gimp_prop_check_button_new (config, "align-layers", NULL);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
frame = gimp_frame_new (_("Objects to align or distribute"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
align_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), align_vbox);
gtk_widget_show (align_vbox);
widget = gimp_prop_check_button_new (config, "align-contents", NULL);
widget = gimp_prop_expanding_frame_new (config, "align-layers",
NULL, widget, NULL);
gtk_box_pack_start (GTK_BOX (align_vbox), widget, FALSE, FALSE, 0);
widget = gimp_prop_check_button_new (config, "align-vectors", NULL);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (align_vbox), widget, FALSE, FALSE, 0);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (align_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
widget = gtk_image_new_from_icon_name (GIMP_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
@ -387,7 +414,7 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
gtk_widget_show (widget);
widget = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (align_vbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
options->priv->selected_guides_label = widget;
@ -643,6 +670,12 @@ gimp_align_options_get_reference (GimpAlignOptions *options,
return reference;
}
gboolean
gimp_align_options_align_contents (GimpAlignOptions *options)
{
return options->priv->align_contents;
}
void
gimp_align_options_pick_guide (GimpAlignOptions *options,
GimpGuide *guide,

View File

@ -67,6 +67,7 @@ void gimp_align_options_pick_reference (GimpAlignOptions *options,
GObject *object);
GObject * gimp_align_options_get_reference (GimpAlignOptions *options,
gboolean blink_if_none);
gboolean gimp_align_options_align_contents (GimpAlignOptions *options);
void gimp_align_options_pick_guide (GimpAlignOptions *options,
GimpGuide *guide,

View File

@ -179,9 +179,6 @@ gimp_align_tool_constructed (GObject *object)
g_signal_connect_object (options, "align-button-clicked",
G_CALLBACK (gimp_align_tool_align),
align_tool, G_CONNECT_SWAPPED);
g_signal_connect_object (align_tool, "undo",
G_CALLBACK (gimp_align_tool_undo),
align_tool, G_CONNECT_AFTER);
}
static void
@ -765,6 +762,7 @@ gimp_align_tool_align (GimpAlignTool *align_tool,
align_type,
reference_object,
align_type,
gimp_align_options_align_contents (options),
offset);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool));