diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
commit | 5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch) | |
tree | cbffb45144febf451e54061db2b21395faf94bfe /app/core/gimpimage-arrange.c | |
parent | Initial commit. (diff) | |
download | gimp-5c1676dfe6d2f3c837a5e074117b45613fd29a72.tar.xz gimp-5c1676dfe6d2f3c837a5e074117b45613fd29a72.zip |
Adding upstream version 2.10.34.upstream/2.10.34upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | app/core/gimpimage-arrange.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/app/core/gimpimage-arrange.c b/app/core/gimpimage-arrange.c new file mode 100644 index 0000000..6b6b05e --- /dev/null +++ b/app/core/gimpimage-arrange.c @@ -0,0 +1,388 @@ +/* GIMP - The GNU Image Manipulation Program + * 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 <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpmath/gimpmath.h" + +#include "core-types.h" + +#include "gimpimage.h" +#include "gimpimage-arrange.h" +#include "gimpimage-guides.h" +#include "gimpimage-undo.h" +#include "gimpitem.h" +#include "gimpguide.h" + +#include "gimp-intl.h" + + +static GList * sort_by_offset (GList *list); +static void compute_offsets (GList *list, + GimpAlignmentType alignment); +static void compute_offset (GObject *object, + GimpAlignmentType alignment); +static gint offset_compare (gconstpointer a, + gconstpointer b); + + +/** + * gimp_image_arrange_objects: + * @image: The #GimpImage to which the objects belong. + * @list: A #GList of objects to be aligned. + * @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.. + * @offset: How much to shift the target from perfect alignment.. + * + * 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., + * 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 + * first object in the sorted list is used as reference. + * + * When there are multiple target objects, they are arranged so that + * the spacing between consecutive ones is given by the argument + * @offset but for HFILL and VFILL - in this case, @offset works as an + * internal margin for the distribution (and it can be negative). + */ +void +gimp_image_arrange_objects (GimpImage *image, + GList *list, + GimpAlignmentType alignment, + GObject *reference, + GimpAlignmentType reference_alignment, + gint offset) +{ + gboolean do_x = FALSE; + gboolean do_y = FALSE; + gint z0 = 0; + GList *object_list; + + g_return_if_fail (GIMP_IS_IMAGE (image)); + g_return_if_fail (G_IS_OBJECT (reference) || reference == NULL); + + /* get offsets used for sorting */ + switch (alignment) + { + /* order vertically for horizontal alignment */ + case GIMP_ALIGN_LEFT: + case GIMP_ALIGN_HCENTER: + case GIMP_ALIGN_RIGHT: + do_x = TRUE; + compute_offsets (list, GIMP_ALIGN_TOP); + break; + + /* order horizontally for horizontal arrangement */ + case GIMP_ARRANGE_LEFT: + case GIMP_ARRANGE_HCENTER: + case GIMP_ARRANGE_RIGHT: + case GIMP_ARRANGE_HFILL: + do_x = TRUE; + compute_offsets (list, alignment); + break; + + /* order horizontally for vertical alignment */ + case GIMP_ALIGN_TOP: + case GIMP_ALIGN_VCENTER: + case GIMP_ALIGN_BOTTOM: + do_y = TRUE; + compute_offsets (list, GIMP_ALIGN_LEFT); + break; + + /* order vertically for vertical arrangement */ + case GIMP_ARRANGE_TOP: + case GIMP_ARRANGE_VCENTER: + case GIMP_ARRANGE_BOTTOM: + case GIMP_ARRANGE_VFILL: + do_y = TRUE; + compute_offsets (list, alignment); + break; + + default: + g_return_if_reached (); + } + + object_list = sort_by_offset (list); + + /* now get offsets used for aligning */ + compute_offsets (list, alignment); + + if (reference == NULL) + { + reference = G_OBJECT (object_list->data); + object_list = g_list_next (object_list); + reference_alignment = alignment; + } + else + { + compute_offset (reference, reference_alignment); + } + + z0 = GPOINTER_TO_INT (g_object_get_data (reference, "align-offset")); + + if (object_list) + { + GList *list; + gint n; + gint distr_width = 0; + gint distr_height = 0; + gdouble fill_offset = 0; + + if (reference_alignment == GIMP_ARRANGE_HFILL) + { + distr_width = GPOINTER_TO_INT (g_object_get_data + (reference, "align-width")); + /* The offset parameter works as an internal margin */ + fill_offset = (distr_width - 2 * offset) / + (gint) g_list_length (object_list); + } + if (reference_alignment == GIMP_ARRANGE_VFILL) + { + distr_height = GPOINTER_TO_INT (g_object_get_data + (reference, "align-height")); + fill_offset = (distr_height - 2 * offset) / + (gint) g_list_length (object_list); + } + + /* FIXME: undo group type is wrong */ + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE, + C_("undo-type", "Arrange Objects")); + + for (list = object_list, n = 1; + list; + list = g_list_next (list), n++) + { + GObject *target = list->data; + gint xtranslate = 0; + gint ytranslate = 0; + gint z1; + + z1 = GPOINTER_TO_INT (g_object_get_data (target, "align-offset")); + + if (reference_alignment == GIMP_ARRANGE_HFILL) + { + gint width = GPOINTER_TO_INT (g_object_get_data (target, + "align-width")); + xtranslate = ROUND (z0 - z1 + (n - 0.5) * fill_offset - + width / 2.0 + offset); + } + else if (reference_alignment == GIMP_ARRANGE_VFILL) + { + gint height = GPOINTER_TO_INT (g_object_get_data (target, + "align-height")); + ytranslate = ROUND (z0 - z1 + (n - 0.5) * fill_offset - + height / 2.0 + offset); + } + else /* the normal computing, when we don't depend on the + * width or height of the reference object + */ + { + if (do_x) + xtranslate = z0 - z1 + n * offset; + + if (do_y) + ytranslate = z0 - z1 + n * offset; + } + + /* now actually align the target object */ + if (GIMP_IS_ITEM (target)) + { + gimp_item_translate (GIMP_ITEM (target), + xtranslate, ytranslate, TRUE); + } + else if (GIMP_IS_GUIDE (target)) + { + GimpGuide *guide = GIMP_GUIDE (target); + + switch (gimp_guide_get_orientation (guide)) + { + case GIMP_ORIENTATION_VERTICAL: + gimp_image_move_guide (image, guide, z1 + xtranslate, TRUE); + break; + + case GIMP_ORIENTATION_HORIZONTAL: + gimp_image_move_guide (image, guide, z1 + ytranslate, TRUE); + break; + + default: + break; + } + } + } + + gimp_image_undo_group_end (image); + } + + g_list_free (object_list); +} + +static GList * +sort_by_offset (GList *list) +{ + return g_list_sort (g_list_copy (list), + offset_compare); + +} + +static gint +offset_compare (gconstpointer a, + gconstpointer b) +{ + gint offset1 = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (a), + "align-offset")); + gint offset2 = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (b), + "align-offset")); + + return offset1 - offset2; +} + +/* this function computes the position of the alignment point + * for each object in the list, and attaches it to the + * object as object data. + */ +static void +compute_offsets (GList *list, + GimpAlignmentType alignment) +{ + GList *l; + + for (l = list; l; l = g_list_next (l)) + compute_offset (l->data, alignment); +} + +static void +compute_offset (GObject *object, + GimpAlignmentType alignment) +{ + gint object_offset_x = 0; + gint object_offset_y = 0; + gint object_height = 0; + gint object_width = 0; + gint offset = 0; + + if (GIMP_IS_IMAGE (object)) + { + GimpImage *image = GIMP_IMAGE (object); + + object_offset_x = 0; + object_offset_y = 0; + object_height = gimp_image_get_height (image); + object_width = gimp_image_get_width (image); + } + else if (GIMP_IS_ITEM (object)) + { + GimpItem *item = GIMP_ITEM (object); + gint off_x, off_y; + + gimp_item_bounds (item, + &object_offset_x, + &object_offset_y, + &object_width, + &object_height); + + gimp_item_get_offset (item, &off_x, &off_y); + object_offset_x += off_x; + object_offset_y += off_y; + } + else if (GIMP_IS_GUIDE (object)) + { + GimpGuide *guide = GIMP_GUIDE (object); + + switch (gimp_guide_get_orientation (guide)) + { + case GIMP_ORIENTATION_VERTICAL: + object_offset_x = gimp_guide_get_position (guide); + object_width = 0; + break; + + case GIMP_ORIENTATION_HORIZONTAL: + object_offset_y = gimp_guide_get_position (guide); + object_height = 0; + break; + + default: + break; + } + } + else + { + g_printerr ("Alignment object is not an image, item or guide.\n"); + } + + switch (alignment) + { + case GIMP_ALIGN_LEFT: + case GIMP_ARRANGE_LEFT: + case GIMP_ARRANGE_HFILL: + offset = object_offset_x; + break; + + case GIMP_ALIGN_HCENTER: + case GIMP_ARRANGE_HCENTER: + offset = object_offset_x + object_width / 2; + break; + + case GIMP_ALIGN_RIGHT: + case GIMP_ARRANGE_RIGHT: + offset = object_offset_x + object_width; + break; + + case GIMP_ALIGN_TOP: + case GIMP_ARRANGE_TOP: + case GIMP_ARRANGE_VFILL: + offset = object_offset_y; + break; + + case GIMP_ALIGN_VCENTER: + case GIMP_ARRANGE_VCENTER: + offset = object_offset_y + object_height / 2; + break; + + case GIMP_ALIGN_BOTTOM: + case GIMP_ARRANGE_BOTTOM: + offset = object_offset_y + object_height; + break; + + default: + g_return_if_reached (); + } + + g_object_set_data (object, "align-offset", + GINT_TO_POINTER (offset)); + + /* These are only used for HFILL and VFILL, but since the call to + * gimp_image_arrange_objects allows for two different alignments + * (object and reference_alignment) we better be on the safe side in + * case they differ. (the current implementation of the align tool + * always pass the same value to both parameters) + */ + g_object_set_data (object, "align-width", + GINT_TO_POINTER (object_width)); + + g_object_set_data (object, "align-height", + GINT_TO_POINTER (object_height)); +} |