diff --git a/ChangeLog b/ChangeLog index a3f7b06df3..9444a3e944 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-06-08 Bill Skaggs + + * app/core/core-enums.[ch]: add GIMP_ARRANGE_FOO values + to GimpAlignmentType, and change CENTER to HCENTER, + MIDDLE to VCENTER. + + * app/core/gimpimage-arrange.c: extensively rewritten + to handle arrangement of objects, and to do the + required sorting of lists by offset. + + * app/tools/gimpaligntool.[ch]: added ability to arrange + groups of layers etc with constant spacing. Also try + to change things so that the tool aligns with the + object that users expect intuitively. + 2006-06-08 Simon Budig * plug-ins/common/sel_gauss.c: fix the EXPAND macro to make diff --git a/app/core/core-enums.c b/app/core/core-enums.c index 5a230052c0..d3a9772c69 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -149,23 +149,35 @@ gimp_alignment_type_get_type (void) { static const GEnumValue values[] = { - { GIMP_ALIGN_LEFT, "GIMP_ALIGN_LEFT", "left" }, - { GIMP_ALIGN_CENTER, "GIMP_ALIGN_CENTER", "center" }, - { GIMP_ALIGN_RIGHT, "GIMP_ALIGN_RIGHT", "right" }, - { GIMP_ALIGN_TOP, "GIMP_ALIGN_TOP", "top" }, - { GIMP_ALIGN_MIDDLE, "GIMP_ALIGN_MIDDLE", "middle" }, - { GIMP_ALIGN_BOTTOM, "GIMP_ALIGN_BOTTOM", "bottom" }, + { GIMP_ALIGN_LEFT, "GIMP_ALIGN_LEFT", "align-left" }, + { GIMP_ALIGN_HCENTER, "GIMP_ALIGN_HCENTER", "align-hcenter" }, + { GIMP_ALIGN_RIGHT, "GIMP_ALIGN_RIGHT", "align-right" }, + { GIMP_ALIGN_TOP, "GIMP_ALIGN_TOP", "align-top" }, + { GIMP_ALIGN_VCENTER, "GIMP_ALIGN_VCENTER", "align-vcenter" }, + { GIMP_ALIGN_BOTTOM, "GIMP_ALIGN_BOTTOM", "align-bottom" }, + { GIMP_ARRANGE_LEFT, "GIMP_ARRANGE_LEFT", "arrange-left" }, + { GIMP_ARRANGE_HCENTER, "GIMP_ARRANGE_HCENTER", "arrange-hcenter" }, + { GIMP_ARRANGE_RIGHT, "GIMP_ARRANGE_RIGHT", "arrange-right" }, + { GIMP_ARRANGE_TOP, "GIMP_ARRANGE_TOP", "arrange-top" }, + { GIMP_ARRANGE_VCENTER, "GIMP_ARRANGE_VCENTER", "arrange-vcenter" }, + { GIMP_ARRANGE_BOTTOM, "GIMP_ARRANGE_BOTTOM", "arrange-bottom" }, { 0, NULL, NULL } }; static const GimpEnumDesc descs[] = { { GIMP_ALIGN_LEFT, "GIMP_ALIGN_LEFT", NULL }, - { GIMP_ALIGN_CENTER, "GIMP_ALIGN_CENTER", NULL }, + { GIMP_ALIGN_HCENTER, "GIMP_ALIGN_HCENTER", NULL }, { GIMP_ALIGN_RIGHT, "GIMP_ALIGN_RIGHT", NULL }, { GIMP_ALIGN_TOP, "GIMP_ALIGN_TOP", NULL }, - { GIMP_ALIGN_MIDDLE, "GIMP_ALIGN_MIDDLE", NULL }, + { GIMP_ALIGN_VCENTER, "GIMP_ALIGN_VCENTER", NULL }, { GIMP_ALIGN_BOTTOM, "GIMP_ALIGN_BOTTOM", NULL }, + { GIMP_ARRANGE_LEFT, "GIMP_ARRANGE_LEFT", NULL }, + { GIMP_ARRANGE_HCENTER, "GIMP_ARRANGE_HCENTER", NULL }, + { GIMP_ARRANGE_RIGHT, "GIMP_ARRANGE_RIGHT", NULL }, + { GIMP_ARRANGE_TOP, "GIMP_ARRANGE_TOP", NULL }, + { GIMP_ARRANGE_VCENTER, "GIMP_ARRANGE_VCENTER", NULL }, + { GIMP_ARRANGE_BOTTOM, "GIMP_ARRANGE_BOTTOM", NULL }, { 0, NULL, NULL } }; diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 657ffe4063..373527f95f 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -102,11 +102,17 @@ GType gimp_alignment_type_get_type (void) G_GNUC_CONST; typedef enum /*< pdb-skip >*/ { GIMP_ALIGN_LEFT, - GIMP_ALIGN_CENTER, + GIMP_ALIGN_HCENTER, GIMP_ALIGN_RIGHT, GIMP_ALIGN_TOP, - GIMP_ALIGN_MIDDLE, - GIMP_ALIGN_BOTTOM + GIMP_ALIGN_VCENTER, + GIMP_ALIGN_BOTTOM, + GIMP_ARRANGE_LEFT, + GIMP_ARRANGE_HCENTER, + GIMP_ARRANGE_RIGHT, + GIMP_ARRANGE_TOP, + GIMP_ARRANGE_VCENTER, + GIMP_ARRANGE_BOTTOM } GimpAlignmentType; diff --git a/app/core/gimpimage-arrange.c b/app/core/gimpimage-arrange.c index 4c6e80b1ea..f3739b2097 100644 --- a/app/core/gimpimage-arrange.c +++ b/app/core/gimpimage-arrange.c @@ -31,12 +31,21 @@ #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. + * @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.. * @@ -46,6 +55,11 @@ * 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. */ @@ -59,107 +73,61 @@ gimp_image_arrange_objects (GimpImage *image, { gboolean do_x = FALSE; gboolean do_y = FALSE; - gint reference_offset_x = 0; - gint reference_offset_y = 0; - gint reference_height = 0; - gint reference_width = 0; - gint x0 = 0; - gint y0 = 0; + gint z0 = 0; + GList *object_list; g_return_if_fail (GIMP_IS_IMAGE (image)); - g_return_if_fail (G_IS_OBJECT (reference)); + g_return_if_fail (G_IS_OBJECT (reference) || reference == NULL); - /* figure out whether we are aligning horizontally or vertically */ - switch (reference_alignment) + /* get offsets used for sorting */ + switch (alignment) { + /* order vertically for horizontal alignment */ case GIMP_ALIGN_LEFT: - case GIMP_ALIGN_CENTER: + 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: + do_x = TRUE; + compute_offsets (list, alignment); + break; + /* order horizontally for vertical alignment */ case GIMP_ALIGN_TOP: - case GIMP_ALIGN_MIDDLE: + 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: + do_y = TRUE; + compute_offsets (list, alignment); break; - default: - g_assert_not_reached (); } - /* get dimensions of the reference object */ - if (GIMP_IS_IMAGE (reference)) + object_list = sort_by_offset (list); + + /* now get offsets used for aligning */ + compute_offsets (list, alignment); + + if (reference == NULL) { - reference_offset_x = 0; - reference_offset_y = 0; - reference_width = gimp_image_get_width (image); - reference_height = gimp_image_get_height (image); - } - else if (GIMP_IS_ITEM (reference)) - { - GimpItem *item = GIMP_ITEM (reference); - - reference_offset_x = item->offset_x; - reference_offset_y = item->offset_y; - reference_height = item->height; - reference_width = item->width; - } - else if (GIMP_IS_GUIDE (reference)) - { - GimpGuide *guide = GIMP_GUIDE (reference); - - switch (gimp_guide_get_orientation (guide)) - { - case GIMP_ORIENTATION_VERTICAL: - if (do_y) - return; - reference_offset_x = gimp_guide_get_position (guide); - reference_width = 0; - break; - - case GIMP_ORIENTATION_HORIZONTAL: - if (do_x) - return; - reference_offset_y = gimp_guide_get_position (guide); - reference_height = 0; - break; - - default: - break; - } + reference = G_OBJECT (object_list->data); + object_list = g_list_next (object_list); } else - { - g_printerr ("Reference object is not an image, item, or guide.\n"); - return; - } + compute_offset (reference, reference_alignment); - /* compute alignment pos for reference object */ - switch (reference_alignment) - { - case GIMP_ALIGN_LEFT: - x0 = reference_offset_x; - break; - case GIMP_ALIGN_CENTER: - x0 = reference_offset_x + reference_width/2; - break; - case GIMP_ALIGN_RIGHT: - x0 = reference_offset_x + reference_width; - break; - case GIMP_ALIGN_TOP: - y0 = reference_offset_y; - break; - case GIMP_ALIGN_MIDDLE: - y0 = reference_offset_y + reference_height/2; - break; - case GIMP_ALIGN_BOTTOM: - y0 = reference_offset_y + reference_height; - break; - default: - g_assert_not_reached (); - } + z0 = GPOINTER_TO_INT (g_object_get_data (reference, "align-offset")); - - if (list) + if (object_list) { GList *l; gint n; @@ -168,96 +136,21 @@ gimp_image_arrange_objects (GimpImage *image, gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE, _("Arrange Objects")); - for (l = list, n = 1; l; l = g_list_next (l), n++) + for (l = object_list, n = 1; l; l = g_list_next (l), n++) { GObject *target = G_OBJECT (l->data); gint xtranslate = 0; gint ytranslate = 0; - gint target_offset_x = 0; - gint target_offset_y = 0; - gint target_height = 0; - gint target_width = 0; - gint x1 = 0; - gint y1 = 0; + gint z1; - /* compute dimensions of target object */ - if (GIMP_IS_ITEM (target)) - { - GimpItem *item = GIMP_ITEM (target); - - target_offset_x = item->offset_x; - target_offset_y = item->offset_y; - target_height = item->height; - target_width = item->width; - } - else if (GIMP_IS_GUIDE (target)) - { - GimpGuide *guide = GIMP_GUIDE (target); - - switch (gimp_guide_get_orientation (guide)) - { - case GIMP_ORIENTATION_VERTICAL: - if (do_y) - return; - target_offset_x = gimp_guide_get_position (guide); - target_width = 0; - break; - - case GIMP_ORIENTATION_HORIZONTAL: - if (do_x) - return; - target_offset_y = gimp_guide_get_position (guide); - target_height = 0; - break; - - default: - break; - } - } - else - { - g_printerr ("Alignment target is not an item or guide.\n"); - } + z1 = GPOINTER_TO_INT (g_object_get_data (target, + "align-offset")); if (do_x) - { - switch (alignment) - { - case GIMP_ALIGN_LEFT: - x1 = target_offset_x; - break; - case GIMP_ALIGN_CENTER: - x1 = target_offset_x + target_width/2; - break; - case GIMP_ALIGN_RIGHT: - x1 = target_offset_x + target_width; - break; - default: - g_assert_not_reached (); - } - - xtranslate = x0 - x1 + n * offset; - } + xtranslate = z0 - z1 + n * offset; if (do_y) - { - switch (alignment) - { - case GIMP_ALIGN_TOP: - y1 = target_offset_y; - break; - case GIMP_ALIGN_MIDDLE: - y1 = target_offset_y + target_height/2; - break; - case GIMP_ALIGN_BOTTOM: - y1 = target_offset_y + target_height; - break; - default: - g_assert_not_reached (); - } - - ytranslate = y0 - y1 + n * offset; - } + ytranslate = z0 - z1 + n * offset; /* now actually align the target object */ if (GIMP_IS_ITEM (target)) @@ -272,12 +165,12 @@ gimp_image_arrange_objects (GimpImage *image, switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_VERTICAL: - gimp_image_move_guide (image, guide, x1 + xtranslate, TRUE); + gimp_image_move_guide (image, guide, z1 + xtranslate, TRUE); gimp_image_update_guide (image, guide); break; case GIMP_ORIENTATION_HORIZONTAL: - gimp_image_move_guide (image, guide, y1 + ytranslate, TRUE); + gimp_image_move_guide (image, guide, z1 + ytranslate, TRUE); gimp_image_update_guide (image, guide); break; @@ -288,7 +181,130 @@ gimp_image_arrange_objects (GimpImage *image, } gimp_image_undo_group_end (image); - - gimp_image_flush (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 (G_OBJECT (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); + + object_offset_x = item->offset_x; + object_offset_y = item->offset_y; + object_height = item->height; + object_width = item->width; + } + 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: + 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: + 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_assert_not_reached (); + } + + g_object_set_data (object, "align-offset", + GINT_TO_POINTER (offset)); } diff --git a/app/tools/gimpaligntool.c b/app/tools/gimpaligntool.c index 7cb43b0d1c..2736d18742 100644 --- a/app/tools/gimpaligntool.c +++ b/app/tools/gimpaligntool.c @@ -86,11 +86,7 @@ static void gimp_align_tool_draw (GimpDrawTool *draw_tool); static GtkWidget *button_with_stock (GimpAlignmentType action, GimpAlignTool *align_tool); static GtkWidget *gimp_align_tool_controls (GimpAlignTool *align_tool); -static void set_action (GtkWidget *widget, - gpointer data); -static void do_horizontal_alignment (GtkWidget *widget, - gpointer data); -static void do_vertical_alignment (GtkWidget *widget, +static void do_alignment (GtkWidget *widget, gpointer data); static void clear_selected_object (GObject *object, GimpAlignTool *align_tool); @@ -119,7 +115,7 @@ gimp_align_tool_register (GimpToolRegisterCallback callback, gimp_align_options_gui, 0, "gimp-align-tool", - _("Align"), + _("Alignment Tool"), _("Align or arrange layers and other items"), N_("_Align"), "Q", NULL, GIMP_HELP_TOOL_MOVE, @@ -156,8 +152,7 @@ gimp_align_tool_init (GimpAlignTool *align_tool) align_tool->selected_objects = NULL; - align_tool->horz_align_type = GIMP_ALIGN_LEFT; - align_tool->vert_align_type = GIMP_ALIGN_TOP; + align_tool->align_type = GIMP_ALIGN_LEFT; align_tool->horz_offset = 0; align_tool->vert_offset = 0; @@ -285,6 +280,13 @@ gimp_align_tool_button_press (GimpTool *tool, gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); } +/* + * some rather complex logic here. If the user clicks without modifiers, + * then we start a new list, and use the first object in it as reference. + * If the user clicks using Shift, or draws a rubber-band box, then + * we add objects to the list, but do not specify which one should + * be used as reference. + */ static void gimp_align_tool_button_release (GimpTool *tool, GimpCoords *coords, @@ -300,8 +302,20 @@ gimp_align_tool_button_release (GimpTool *tool, gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool)); - if (! (state & GDK_SHIFT_MASK)) - clear_all_selected_objects (align_tool); + if (state & GDK_BUTTON3_MASK) /* cancel this action */ + { + align_tool->x1 = align_tool->x0; + align_tool->y1 = align_tool->y0; + + gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); + return; + } + + if (! (state & GDK_SHIFT_MASK)) /* start a new list */ + { + clear_all_selected_objects (align_tool); + align_tool->set_reference = FALSE; + } #define EPSILON 3 @@ -350,6 +364,12 @@ gimp_align_tool_button_release (GimpTool *tool, g_signal_connect (object, "removed", G_CALLBACK (clear_selected_object), (gpointer) align_tool); + + /* if an object has been selected using unmodified click, + * it should be used as the reference + */ + if (! (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) + align_tool->set_reference = TRUE; } } } @@ -552,6 +572,7 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) GtkWidget *table; GtkWidget *label; GtkWidget *button; + GtkWidget *spinbutton; gint row, col, n; hbox = gtk_hbox_new (FALSE, 0); @@ -574,13 +595,13 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) hbox2 = gtk_hbox_new (FALSE, 0); gtk_table_attach_defaults (GTK_TABLE (table), hbox2, 0, 8, row, row + 1); gtk_widget_show (hbox2); - label = gtk_label_new (_("Horizontal")); + label = gtk_label_new (_("Align")); gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); gtk_widget_show (label); row++; - /* second row */ + /* horizontal align row */ col = 1; n = 0; @@ -592,7 +613,7 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) ++col; ++col; - button = button_with_stock (GIMP_ALIGN_CENTER, align_tool); + button = button_with_stock (GIMP_ALIGN_HCENTER, align_tool); gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); gimp_help_set_help_data (button, _("Align center of target"), NULL); align_tool->button[n++] = button; @@ -608,34 +629,7 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) row++; - /* next row */ -/* label = gtk_label_new (_("Offset:")); */ -/* gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 3, row, row + 1); */ -/* gtk_widget_show (label); */ - -/* spinbutton = gimp_spin_button_new (&align_tool->horz_offset_adjustment, */ -/* 0, */ -/* -100000., */ -/* 100000., */ -/* 1., 20., 20., 1., 0); */ -/* gtk_table_attach_defaults (GTK_TABLE (table), spinbutton, 3, 7, row, row + 1); */ -/* g_signal_connect (align_tool->horz_offset_adjustment, "value-changed", */ -/* G_CALLBACK (gimp_double_adjustment_update), */ -/* &align_tool->horz_offset); */ -/* gtk_widget_show (spinbutton); */ - -/* row++; */ - - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_table_attach_defaults (GTK_TABLE (table), hbox2, 0, 8, row, row + 1); - gtk_widget_show (hbox2); - label = gtk_label_new (_("Vertical")); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - gtk_widget_show (label); - - row++; - - /* second row */ + /* vertical align row */ col = 1; @@ -646,7 +640,7 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) ++col; ++col; - button = button_with_stock (GIMP_ALIGN_MIDDLE, align_tool); + button = button_with_stock (GIMP_ALIGN_VCENTER, align_tool); gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); gimp_help_set_help_data (button, _("Align middle of target"), NULL); align_tool->button[n++] = button; @@ -662,21 +656,85 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) row++; - /* next row */ -/* label = gtk_label_new (_("Offset:")); */ -/* gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 3, row, row + 1); */ -/* gtk_widget_show (label); */ + /* label row */ + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_table_attach_defaults (GTK_TABLE (table), hbox2, 0, 8, row, row + 1); + gtk_widget_show (hbox2); + label = gtk_label_new (_("Arrange")); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_widget_show (label); -/* spinbutton = gimp_spin_button_new (&align_tool->vert_offset_adjustment, */ -/* 0, */ -/* -100000., */ -/* 100000., */ -/* 1., 20., 20., 1., 0); */ -/* gtk_table_attach_defaults (GTK_TABLE (table), spinbutton, 3, 7, row, row + 1); */ -/* g_signal_connect (align_tool->vert_offset_adjustment, "value-changed", */ -/* G_CALLBACK (gimp_double_adjustment_update), */ -/* &align_tool->vert_offset); */ -/* gtk_widget_show (spinbutton); */ + row++; + + /* horizontal arrange row */ + + col = 1; + + button = button_with_stock (GIMP_ARRANGE_LEFT, align_tool); + gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); + gimp_help_set_help_data (button, _("Arrange left edges of targets"), NULL); + align_tool->button[n++] = button; + ++col; + ++col; + + button = button_with_stock (GIMP_ARRANGE_HCENTER, align_tool); + gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); + gimp_help_set_help_data (button, _("Arrange horiz centers of targets"), NULL); + align_tool->button[n++] = button; + ++col; + ++col; + + button = button_with_stock (GIMP_ARRANGE_RIGHT, align_tool); + gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); + gimp_help_set_help_data (button, _("Arrange right edges of targets"), NULL); + align_tool->button[n++] = button; + ++col; + ++col; + + row++; + + /* vertical arrange row */ + + col = 1; + + button = button_with_stock (GIMP_ARRANGE_TOP, align_tool); + gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); + gimp_help_set_help_data (button, _("Arrange top edges of targets"), NULL); + align_tool->button[n++] = button; + ++col; + ++col; + + button = button_with_stock (GIMP_ARRANGE_VCENTER, align_tool); + gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); + gimp_help_set_help_data (button, _("Arrange vertical centers of targets"), NULL); + align_tool->button[n++] = button; + ++col; + ++col; + + button = button_with_stock (GIMP_ARRANGE_BOTTOM, align_tool); + gtk_table_attach_defaults (GTK_TABLE (table), button, col, col + 2, row, row + 1); + gimp_help_set_help_data (button, _("Arrange bottoms of targets"), NULL); + align_tool->button[n++] = button; + ++col; + ++col; + + row++; + + /* offset row */ + label = gtk_label_new (_("Offset:")); + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 3, row, row + 1); + gtk_widget_show (label); + + spinbutton = gimp_spin_button_new (&align_tool->horz_offset_adjustment, + 0, + -100000., + 100000., + 1., 20., 20., 1., 0); + gtk_table_attach_defaults (GTK_TABLE (table), spinbutton, 3, 7, row, row + 1); + g_signal_connect (align_tool->horz_offset_adjustment, "value-changed", + G_CALLBACK (gimp_double_adjustment_update), + &align_tool->horz_offset); + gtk_widget_show (spinbutton); gtk_widget_show (hbox); return hbox; @@ -684,33 +742,73 @@ gimp_align_tool_controls (GimpAlignTool *align_tool) static void -do_horizontal_alignment (GtkWidget *widget, - gpointer data) +do_alignment (GtkWidget *widget, + gpointer data) { - GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (data); - GimpImage *image; - GObject *reference_object; + GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (data); + GimpAlignmentType action; + GimpImage *image; + GObject *reference_object; + GList *list; + gint offset; image = GIMP_TOOL (align_tool)->display->image; + action = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "action")); + offset = align_tool->horz_offset; + + switch (action) + { + case GIMP_ALIGN_LEFT: + case GIMP_ALIGN_HCENTER: + case GIMP_ALIGN_RIGHT: + case GIMP_ALIGN_TOP: + case GIMP_ALIGN_VCENTER: + case GIMP_ALIGN_BOTTOM: + offset = 0; + break; + case GIMP_ARRANGE_LEFT: + case GIMP_ARRANGE_HCENTER: + case GIMP_ARRANGE_RIGHT: + case GIMP_ARRANGE_TOP: + case GIMP_ARRANGE_VCENTER: + case GIMP_ARRANGE_BOTTOM: + offset = align_tool->horz_offset; + break; + } /* if nothing is selected, just return * if only one object is selected, use the image as reference - * if multiple objects are selected, use the first one as reference + * if multiple objects are selected, use the first one as reference if + * "set_reference" is TRUE, otherwise use NULL. */ if (g_list_length (align_tool->selected_objects) == 0) return; else if (g_list_length (align_tool->selected_objects) == 1) - reference_object = G_OBJECT (image); + { + reference_object = G_OBJECT (image); + list = align_tool->selected_objects; + } else - reference_object = G_OBJECT (align_tool->selected_objects->data); + { + if (align_tool->set_reference) + { + reference_object = G_OBJECT (align_tool->selected_objects->data); + list = g_list_next (align_tool->selected_objects); + } + else + { + reference_object = NULL; + list = align_tool->selected_objects; + } + } gimp_draw_tool_pause (GIMP_DRAW_TOOL (align_tool)); - gimp_image_arrange_objects (image, align_tool->selected_objects, - align_tool->horz_align_type, + gimp_image_arrange_objects (image, list, + action, reference_object, - align_tool->horz_align_type, - align_tool->horz_offset); + action, + offset); gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool)); @@ -718,40 +816,6 @@ do_horizontal_alignment (GtkWidget *widget, } -static void -do_vertical_alignment (GtkWidget *widget, - gpointer data) -{ - GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (data); - GimpImage *image; - GObject *reference_object; - - image = GIMP_TOOL (align_tool)->display->image; - - /* if nothing is selected, just return - * if only one object is selected, use the image as reference - * if multiple objects are selected, use the first one as reference - */ - if (g_list_length (align_tool->selected_objects) == 0) - return; - else if (g_list_length (align_tool->selected_objects) == 1) - reference_object = G_OBJECT (image); - else - reference_object = G_OBJECT (align_tool->selected_objects->data); - - gimp_draw_tool_pause (GIMP_DRAW_TOOL (align_tool)); - - gimp_image_arrange_objects (image, align_tool->selected_objects, - align_tool->vert_align_type, - reference_object, - align_tool->vert_align_type, - align_tool->vert_offset); - - gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool)); - - gimp_image_flush (image); -} - static GtkWidget * @@ -766,7 +830,7 @@ button_with_stock (GimpAlignmentType action, case GIMP_ALIGN_LEFT: stock_id = GIMP_STOCK_GRAVITY_WEST; break; - case GIMP_ALIGN_CENTER: + case GIMP_ALIGN_HCENTER: stock_id = GIMP_STOCK_HCENTER; break; case GIMP_ALIGN_RIGHT: @@ -775,12 +839,30 @@ button_with_stock (GimpAlignmentType action, case GIMP_ALIGN_TOP: stock_id = GIMP_STOCK_GRAVITY_NORTH; break; - case GIMP_ALIGN_MIDDLE: + case GIMP_ALIGN_VCENTER: stock_id = GIMP_STOCK_VCENTER; break; case GIMP_ALIGN_BOTTOM: stock_id = GIMP_STOCK_GRAVITY_SOUTH; break; + case GIMP_ARRANGE_LEFT: + stock_id = GIMP_STOCK_GRAVITY_WEST; + break; + case GIMP_ARRANGE_HCENTER: + stock_id = GIMP_STOCK_HCENTER; + break; + case GIMP_ARRANGE_RIGHT: + stock_id = GIMP_STOCK_GRAVITY_EAST; + break; + case GIMP_ARRANGE_TOP: + stock_id = GIMP_STOCK_GRAVITY_NORTH; + break; + case GIMP_ARRANGE_VCENTER: + stock_id = GIMP_STOCK_VCENTER; + break; + case GIMP_ARRANGE_BOTTOM: + stock_id = GIMP_STOCK_GRAVITY_SOUTH; + break; default: stock_id = "?"; break; @@ -791,7 +873,7 @@ button_with_stock (GimpAlignmentType action, g_object_set_data (G_OBJECT (button), "action", GINT_TO_POINTER (action)); g_signal_connect (button, "clicked", - G_CALLBACK (set_action), + G_CALLBACK (do_alignment), align_tool); gtk_widget_set_sensitive (button, FALSE); @@ -800,34 +882,6 @@ button_with_stock (GimpAlignmentType action, return button; } -static void -set_action (GtkWidget *widget, - gpointer data) -{ - GimpAlignTool *align_tool = data; - GimpAlignmentType action; - - action = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "action")); - - switch (action) - { - case GIMP_ALIGN_LEFT: - case GIMP_ALIGN_CENTER: - case GIMP_ALIGN_RIGHT: - align_tool->horz_align_type = action; - do_horizontal_alignment (widget, data); - break; - case GIMP_ALIGN_TOP: - case GIMP_ALIGN_MIDDLE: - case GIMP_ALIGN_BOTTOM: - align_tool->vert_align_type = action; - do_vertical_alignment (widget, data); - break; - default: - break; - } -} - static void clear_selected_object (GObject *object, GimpAlignTool *align_tool) diff --git a/app/tools/gimpaligntool.h b/app/tools/gimpaligntool.h index 5442d6bd7d..faf73a3207 100644 --- a/app/tools/gimpaligntool.h +++ b/app/tools/gimpaligntool.h @@ -30,7 +30,7 @@ #define GIMP_IS_ALIGN_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ALIGN_TOOL)) #define GIMP_ALIGN_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ALIGN_TOOL, GimpAlignToolClass)) -#define ALIGN_TOOL_NUM_BUTTONS 6 +#define ALIGN_TOOL_NUM_BUTTONS 12 typedef struct _GimpAlignTool GimpAlignTool; typedef struct _GimpAlignToolClass GimpAlignToolClass; @@ -44,8 +44,7 @@ struct _GimpAlignTool GList *selected_objects; - GimpAlignmentType horz_align_type; - GimpAlignmentType vert_align_type; + GimpAlignmentType align_type; gdouble horz_offset; gdouble vert_offset; @@ -54,6 +53,8 @@ struct _GimpAlignTool GtkObject *vert_offset_adjustment; gint x0, y0, x1, y1; /* rubber-band rectangle */ + + gboolean set_reference; }; struct _GimpAlignToolClass diff --git a/plug-ins/common/png.c b/plug-ins/common/png.c index cb5217e958..298cbae0ad 100644 --- a/plug-ins/common/png.c +++ b/plug-ins/common/png.c @@ -149,6 +149,11 @@ static gint find_unused_ia_color (const guchar *pixels, static gboolean load_defaults (void); static void save_defaults (void); static void load_gui_defaults (PngSaveGui *pg); +static guchar *fill_bit2byte (void); +static void byte2bit (const guchar *byteline, + gint width, + guchar *bitline, + gboolean invert); /* * Globals... @@ -672,8 +677,16 @@ load_image (const gchar *filename, GimpPixelRgn pixel_rgn; /* Pixel region for layer */ png_structp pp; /* PNG read pointer */ png_infop info; /* PNG info pointers */ - guchar **pixels, /* Pixel rows */ - *pixel; /* Pixel data */ + gboolean is_bw = FALSE; + guchar **pixels = NULL; /* Pixel rows */ + guchar *pixel = NULL; /* Pixel data */ + + /* b&w needs this for bits*/ + guchar *bits = NULL; /* rows of bits */ + guchar **bit_line = NULL; /* pointers to BOR */ + gint bit_line_len = 0; /* number of bytes to keep the bits */ + guchar *bit2byte = NULL; + guchar alpha[256], /* Index -> Alpha */ *alpha_ptr; /* Temporary pointer */ @@ -685,6 +698,20 @@ load_image (const gchar *filename, if (setjmp (pp->jmpbuf)) { + /* this is a (maybe useless) attempt to recover cleanly from errors. */ +#if PNG_LIBPNG_VER > 88 + png_destroy_read_struct(&pp, &info, (png_infopp) NULL); +#endif + g_free (pixel); + g_free (pixels); + + if (is_bw) + { + g_free (bit2byte); + g_free (bits); + g_free (bit_line); + }; + g_message (_("Error while reading '%s'. File corrupted?"), gimp_filename_to_utf8 (filename)); return image; @@ -744,8 +771,19 @@ load_image (const gchar *filename, if (info->color_type != PNG_COLOR_TYPE_PALETTE && (info->valid & PNG_INFO_tRNS)) { - png_set_expand (pp); - } + if (info->bit_depth == 1) + { + /* b&w, load this as an indexed image */ + is_bw = TRUE; + bits = NULL; + bit_line = NULL; + bit2byte = NULL; + } + else + { + png_set_expand (pp); + } + } /* * Turn on interlace handling... libpng returns just 1 (ie single pass) @@ -781,6 +819,7 @@ load_image (const gchar *filename, png_read_update_info (pp, info); + /* mmc: this means, that png_set_expand & png_set_packing may change info->color_type? */ switch (info->color_type) { case PNG_COLOR_TYPE_RGB: /* RGB */ @@ -796,9 +835,22 @@ load_image (const gchar *filename, break; case PNG_COLOR_TYPE_GRAY: /* Grayscale */ - bpp = 1; - image_type = GIMP_GRAY; - layer_type = GIMP_GRAY_IMAGE; + /* g_print("opening a grayscale png. bit depth: %d\n", info->bit_depth); */ + if (is_bw) + { + /* Have to construct the white&black palette, see below. */ + image_type = GIMP_INDEXED; + layer_type = GIMP_INDEXED_IMAGE; + bpp = 1; /* This is fake, we disable the expansion (by libpng)! + * But, after our conversion the rows will indeed be 1 byte-per-pixel. */ + bit2byte = fill_bit2byte (); + } + else + { + bpp = 1; + image_type = GIMP_GRAY; + layer_type = GIMP_GRAY_IMAGE; + } break; case PNG_COLOR_TYPE_GRAY_ALPHA: /* Grayscale + alpha */ @@ -938,6 +990,12 @@ load_image (const gchar *filename, info->num_palette); } } + else if (is_bw) + { + /* we are converting grayscale image to a b&w palette: this is the palette then: */ + guchar bw_map[] = { 0, 0, 0, 255, 255, 255 }; + gimp_image_set_colormap (image, bw_map,2); + } /* * Get the drawable and set the pixel region for our load... @@ -956,6 +1014,21 @@ load_image (const gchar *filename, pixel = g_new (guchar, tile_height * info->width * bpp); pixels = g_new (guchar *, tile_height); + if (is_bw) + { + bit_line_len = ((info->width +7 ) / 8); + + /* >> 3 */ + /* bits_per_byte! */ + bits = g_new (guchar, tile_height * bit_line_len); + bit_line = g_new (guchar *, tile_height); + + for (i = 0; i < tile_height; i++) + bit_line[i] = bits + bit_line_len * i; + + /* g_print("bit_line_len =%d\n", bit_line_len); */ + } + for (i = 0; i < tile_height; i++) pixels[i] = pixel + info->width * info->channels * i; @@ -977,7 +1050,49 @@ load_image (const gchar *filename, gimp_pixel_rgn_get_rect (&pixel_rgn, pixel, 0, begin, drawable->width, num); - png_read_rows (pp, pixels, NULL, num); + /* mmc: interlacing not handled now? */ + /* if we used the libpng builtin expansion, we would have to + * convert values 255 (black) into 1 (palette index) + * I think this approach is faster: + */ + + if (is_bw) + { + int i, j; + guchar *source, *dest; + + png_read_rows (pp, bit_line, NULL, num); + /* FIXME: we must not memcpy after the boundary! + * So, if the line is not a multiple of 8 (bits per byte), + * we should do it out of the cycle!*/ + +#define BITS_PER_BYTE 8 + for (j=0; j< tile_height; j++) + { + dest = pixels[j]; + source = bit_line[j]; + + for (i=0; i < (info->width / BITS_PER_BYTE) ; i++) + { + memcpy (dest, + bit2byte + *source * BITS_PER_BYTE, + BITS_PER_BYTE); + dest += BITS_PER_BYTE; + source++; + } + + if (info->width / BITS_PER_BYTE < bit_line_len) + { + memcpy (dest, + bit2byte + *source * BITS_PER_BYTE, + info->width % BITS_PER_BYTE); + } + } + } + else + { + png_read_rows (pp, pixels, NULL, num); + } gimp_pixel_rgn_set_rect (&pixel_rgn, pixel, 0, begin, drawable->width, num); @@ -1119,7 +1234,23 @@ load_image (const gchar *filename, } -/* +static guchar * +fill_bit2byte (void) +{ + guchar *bit2byte = g_new (guchar, 256 * 8); + guchar *dest; + gint i, j; + + dest = bit2byte; + + for (j = 0; j < 256; j++) + for (i = 7; i >= 0; i--) + *(dest++) = ((j & (1 << i)) != 0); + + return bit2byte; +} + + /* * 'save_image ()' - Save the specified image to a PNG file. */ @@ -1138,16 +1269,16 @@ save_image (const gchar *filename, begin, /* Beginning tile row */ end, /* Ending tile row */ num; /* Number of rows to load */ - FILE *fp; /* File pointer */ + FILE *fp = NULL; /* File pointer */ GimpDrawable *drawable; /* Drawable for layer */ GimpPixelRgn pixel_rgn; /* Pixel region for layer */ png_structp pp; /* PNG read pointer */ png_infop info; /* PNG info pointer */ gint num_colors; /* Number of colors in colormap */ gint offx, offy; /* Drawable offsets from origin */ - guchar **pixels, /* Pixel rows */ - *fixed, /* Fixed-up pixel data */ - *pixel; /* Pixel data */ + guchar **pixels = NULL; /* Pixel rows */ + guchar *fixed = NULL; /* Fixed-up pixel data */ + guchar *pixel = NULL; /* Pixel data */ gdouble xres, yres; /* GIMP resolution (dpi) */ png_color_16 background; /* Background color */ png_time mod_time; /* Modification time (ie NOW) */ @@ -1157,7 +1288,10 @@ save_image (const gchar *filename, guchar remap[256]; /* Re-mapping for the palette */ - png_textp text = NULL; + /* indexed b/w -> save as 1bit grayscale to save space! */ + gboolean is_bw = FALSE, invert = FALSE; + + png_textp text = NULL; if (pngvals.comment) { @@ -1203,7 +1337,18 @@ save_image (const gchar *filename, if (setjmp (pp->jmpbuf)) { - g_message (_("Error while saving '%s'. Could not save image."), + /* mmc: fixme: neo says, on failure a saving process exits, so this might be done implicitely + * I do it explicitely for case someone reuses the code. */ +#if PNG_LIBPNG_VER > 88 + png_destroy_write_struct(&pp, &info); +#endif + if (fp) + fclose (fp); + + g_free (pixels); + g_free (pixel); + + g_message (_("Error while saving '%s'. Could not save image."), gimp_filename_to_utf8 (filename)); return FALSE; } @@ -1279,12 +1424,42 @@ save_image (const gchar *filename, break; case GIMP_INDEXED_IMAGE: - bpp = 1; - info->color_type = PNG_COLOR_TYPE_PALETTE; - info->valid |= PNG_INFO_PLTE; - info->palette = - (png_colorp) gimp_image_get_colormap (image_ID, &num_colors); - info->num_palette = num_colors; + { + /* copied from tiff.c ! */ + guchar *cmap = gimp_image_get_colormap (image_ID, &num_colors); + + if (num_colors == 2) + { + const guchar bw_map[] = { 0, 0, 0, 255, 255, 255 }; + const guchar wb_map[] = { 255, 255, 255, 0, 0, 0 }; + + is_bw = (memcmp (cmap, bw_map, 6) == 0); + + if (!is_bw) + { + is_bw = (memcmp (cmap, wb_map, 6) == 0); + + if (is_bw) + invert = TRUE; + } + } + + if (is_bw) + { + bpp = 1; + info->color_type = PNG_COLOR_TYPE_GRAY; + info->bit_depth = 1; + g_free (cmap); + } + else + { + bpp = 1; + info->color_type = PNG_COLOR_TYPE_PALETTE; + info->valid |= PNG_INFO_PLTE; + info->palette = (png_colorp) cmap; + info->num_palette = num_colors; + } + } break; case GIMP_INDEXEDA_IMAGE: @@ -1506,6 +1681,17 @@ save_image (const gchar *filename, } } } + else if (is_bw) + { + /* indexed b/w -> 1-grayscale: at this stage, */ + /* we have to convert the 0/1 indexes(bytes) into 0/1 bits */ + /* pixel is the array of several lines of the image: indexes + * pixels is an array of pointers at the beginnings of the lines */ + for (i = 0; i < num; ++i) + { + byte2bit (pixels[i], info->width, pixels[i], invert); + } + } png_write_rows (pp, pixels, num); @@ -1539,6 +1725,53 @@ save_image (const gchar *filename, return TRUE; } +/* Convert n bytes of 0/1 to a line of bits */ +static void +byte2bit (const guchar *byteline, + gint width, + guchar *bitline, + gboolean invert) +{ + guchar bitval; + guchar rest[8]; + + while (width >= 8) + { + bitval = 0; + + if (*(byteline++)) bitval |= 0x80; + if (*(byteline++)) bitval |= 0x40; + if (*(byteline++)) bitval |= 0x20; + if (*(byteline++)) bitval |= 0x10; + if (*(byteline++)) bitval |= 0x08; + if (*(byteline++)) bitval |= 0x04; + if (*(byteline++)) bitval |= 0x02; + if (*(byteline++)) bitval |= 0x01; + + *(bitline++) = invert ? ~bitval : bitval; + + width -= 8; + } + + if (width > 0) + { + memset (rest, 0, 8); + memcpy (rest, byteline, width); + bitval = 0; + byteline = rest; + + if (*(byteline++)) bitval |= 0x80; + if (*(byteline++)) bitval |= 0x40; + if (*(byteline++)) bitval |= 0x20; + if (*(byteline++)) bitval |= 0x10; + if (*(byteline++)) bitval |= 0x08; + if (*(byteline++)) bitval |= 0x04; + if (*(byteline++)) bitval |= 0x02; + + *bitline = invert ? ~bitval & (0xff << (8 - width)) : bitval; + } +} + static gboolean ia_has_transparent_pixels (const guchar *pixels, gint numpixels) diff --git a/po/Makefile.in.in b/po/Makefile.in.in index deeb686368..22cadc6545 100644 --- a/po/Makefile.in.in +++ b/po/Makefile.in.in @@ -11,11 +11,6 @@ # # - Modified by jacob berkman to install # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize -# -# - Modified by Rodney Dawes for use with intltool -# -# We have the following line for use by intltoolize: -# INTLTOOL_MAKEFILE GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ @@ -32,21 +27,20 @@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datadir = @datadir@ -datarootdir = @datarootdir@ libdir = @libdir@ localedir = $(libdir)/locale gnulocaledir = $(datadir)/locale gettextsrcdir = $(datadir)/glib-2.0/gettext/po subdir = po install_sh = @install_sh@ -# Automake >= 1.8 provides @mkdir_p@. -# Until it can be supposed, use the safe fallback: -mkdir_p = $(install_sh) -d +mkdir_p = @mkdir_p@ +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ CC = @CC@ +GENCAT = @GENCAT@ GMSGFMT = @GMSGFMT@ MSGFMT = @MSGFMT@ XGETTEXT = @XGETTEXT@ @@ -67,13 +61,13 @@ SOURCES = POFILES = @POFILES@ GMOFILES = @GMOFILES@ DISTFILES = ChangeLog Makefile.in.in POTFILES.in \ -$(POFILES) $(SOURCES) -EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS +$(POFILES) $(GMOFILES) $(SOURCES) POTFILES = \ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ +INSTOBJEXT = @INSTOBJEXT@ .SUFFIXES: .SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat @@ -83,7 +77,7 @@ CATOBJEXT = @CATOBJEXT@ .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot - $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox + $(MSGMERGE) $< $(top_builddir)/po/$(GETTEXT_PACKAGE).pot -o $*pox .po.mo: $(MSGFMT) -o $@ $< @@ -94,7 +88,7 @@ CATOBJEXT = @CATOBJEXT@ .po.cat: sed -f ../intl/po2msg.sed < $< > $*.msg \ - && rm -f $@ && gencat $@ $*.msg + && rm -f $@ && $(GENCAT) $@ $*.msg all: all-@USE_NLS@ @@ -110,7 +104,11 @@ install-exec: install-data: install-data-@USE_NLS@ install-data-no: all install-data-yes: all - $(mkdir_p) $(DESTDIR)$(datadir) + if test -n "$(MKINSTALLDIRS)"; then \ + $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \ + else \ + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \ + fi @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ @@ -120,31 +118,39 @@ install-data-yes: all esac; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \ - $(mkdir_p) $$dir; \ - if test -r $$cat; then \ - $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE).mo; \ - echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE).mo"; \ + if test -n "$(MKINSTALLDIRS)"; then \ + $(MKINSTALLDIRS) $$dir; \ else \ - $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE).mo; \ + $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \ + fi; \ + if test -r $$cat; then \ + $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ + echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \ + else \ + $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ echo "installing $(srcdir)/$$cat as" \ - "$$dir/$(GETTEXT_PACKAGE).mo"; \ + "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \ fi; \ if test -r $$cat.m; then \ - $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ - echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ + $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ + echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \ else \ if test -r $(srcdir)/$$cat.m ; then \ $(INSTALL_DATA) $(srcdir)/$$cat.m \ - $$dir/$(GETTEXT_PACKAGE).mo.m; \ + $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ echo "installing $(srcdir)/$$cat as" \ - "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ + "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \ else \ true; \ fi; \ fi; \ done if test "$(PACKAGE)" = "glib"; then \ - $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + if test -n "$(MKINSTALLDIRS)"; then \ + $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \ + else \ + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \ + fi; \ $(INSTALL_DATA) $(srcdir)/Makefile.in.in \ $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \ else \ @@ -159,16 +165,16 @@ uninstall: for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ - rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ - rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ - rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ - rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ + rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ + rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ + rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ + rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ done if test "$(PACKAGE)" = "glib"; then \ rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \ fi -check: all $(GETTEXT_PACKAGE).pot +check: all dvi info tags TAGS ID: @@ -180,25 +186,19 @@ mostlyclean: clean: mostlyclean distclean: clean - rm -f Makefile Makefile.in POTFILES stamp-it - rm -f *.mo *.msg *.cat *.cat.m *.gmo + rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." - rm -f Makefile.in.in + rm -f $(GMOFILES) distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir) -dist distdir: $(DISTFILES) +dist distdir: $(DISTFILES) $(GETTEXT_PACKAGE).pot dists="$(DISTFILES)"; \ - extra_dists="$(EXTRA_DISTFILES)"; \ - for file in $$extra_dists; do \ - test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ - done; \ for file in $$dists; do \ - test -f $$file || file="$(srcdir)/$$file"; \ - ln $$file $(distdir) 2> /dev/null \ - || cp -p $$file $(distdir); \ + ln $(srcdir)/$$file $(distdir) 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir); \ done update-po: Makefile @@ -228,15 +228,27 @@ update-po: Makefile fi; \ done -Makefile POTFILES: stamp-it - @if test ! -f $@; then \ - rm -f stamp-it; \ - $(MAKE) stamp-it; \ - fi +# POTFILES is created from POTFILES.in by stripping comments, empty lines +# and Intltool tags (enclosed in square brackets), and appending a full +# relative path to them +POTFILES: POTFILES.in + ( if test 'x$(srcdir)' != 'x.'; then \ + posrcprefix='$(top_srcdir)/'; \ + else \ + posrcprefix="../"; \ + fi; \ + rm -f $@-t $@ \ + && (sed -e '/^#/d' \ + -e "s/^\[.*\] +//" \ + -e '/^[ ]*$$/d' \ + -e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \ + | sed -e '$$s/\\$$//') > $@-t \ + && chmod a-w $@-t \ + && mv $@-t $@ ) -stamp-it: Makefile.in.in ../config.status POTFILES.in +Makefile: Makefile.in.in ../config.status POTFILES cd .. \ - && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ $(SHELL) ./config.status # Tell versions [3.59,3.63) of GNU make not to export all variables.