/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 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 . */ /* Original plug-in coded by Tim Newsome. * * Changed to make use of real-life units by Sven Neumann . * * The interface code is heavily commented in the hope that it will * help other plug-in developers to adapt their plug-ins to make use * of the pika_size_entry functionality. * * Note: There is a convenience constructor called pika_coordinetes_new () * which simplifies the task of setting up a standard X,Y sizeentry. * * For more info and bugs see libpika/pikasizeentry.h and libpika/pikawidgets.h * * May 2000 tim copperfield [timecop@japan.co.jp] * http://www.ne.jp/asahi/linux/timecop * Added dynamic preview. Due to weird implementation of signals from all * controls, preview will not auto-update. But this plugin isn't really * crying for real-time updating either. * */ #include "config.h" #include #include #include #include "libpika/stdplugins-intl.h" #define PLUG_IN_PROC "plug-in-grid" #define PLUG_IN_BINARY "grid" #define PLUG_IN_ROLE "pika-grid" #define SPIN_BUTTON_WIDTH 8 #define COLOR_BUTTON_WIDTH 55 typedef struct _Grid Grid; typedef struct _GridClass GridClass; struct _Grid { PikaPlugIn parent_instance; PikaDrawable *drawable; PikaProcedureConfig *config; GtkWidget *hcolor_button; GtkWidget *vcolor_button; GtkWidget *icolor_button; GtkWidget *color_chain; }; struct _GridClass { PikaPlugInClass parent_class; }; #define GRID_TYPE (grid_get_type ()) #define GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GRID_TYPE, Grid)) GType grid_get_type (void) G_GNUC_CONST; static GList * grid_query_procedures (PikaPlugIn *plug_in); static PikaProcedure * grid_create_procedure (PikaPlugIn *plug_in, const gchar *name); static PikaValueArray * grid_run (PikaProcedure *procedure, PikaRunMode run_mode, PikaImage *image, gint n_drawables, PikaDrawable **drawables, PikaProcedureConfig *config, gpointer run_data); static guchar best_cmap_match (const guchar *cmap, gint ncolors, const PikaRGB *color); static void render_grid (PikaImage *image, PikaDrawable *drawable, PikaProcedureConfig *config, PikaPreview *preview); static gint dialog (PikaImage *image, PikaDrawable *drawable, PikaProcedure *procedure, PikaProcedureConfig *config); G_DEFINE_TYPE (Grid, grid, PIKA_TYPE_PLUG_IN) PIKA_MAIN (GRID_TYPE) DEFINE_STD_SET_I18N static gint sx1, sy1, sx2, sy2; static GtkWidget *main_dialog = NULL; static void grid_class_init (GridClass *klass) { PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass); plug_in_class->query_procedures = grid_query_procedures; plug_in_class->create_procedure = grid_create_procedure; plug_in_class->set_i18n = STD_SET_I18N; } static void grid_init (Grid *grid) { } static GList * grid_query_procedures (PikaPlugIn *plug_in) { return g_list_append (NULL, g_strdup (PLUG_IN_PROC)); } static PikaProcedure * grid_create_procedure (PikaPlugIn *plug_in, const gchar *name) { PikaProcedure *procedure = NULL; if (! strcmp (name, PLUG_IN_PROC)) { const PikaRGB black = { 0.0, 0.0, 0.0, 1.0 }; procedure = pika_image_procedure_new (plug_in, name, PIKA_PDB_PROC_TYPE_PLUGIN, grid_run, NULL, NULL); pika_procedure_set_image_types (procedure, "*"); pika_procedure_set_sensitivity_mask (procedure, PIKA_PROCEDURE_SENSITIVE_DRAWABLE); pika_procedure_set_menu_label (procedure, _("_Grid (legacy)...")); pika_procedure_add_menu_path (procedure, "/Filters/Render/Pattern"); pika_procedure_set_documentation (procedure, _("Draw a grid on the image"), "Draws a grid using the specified " "colors. The grid origin is the " "upper left corner.", name); pika_procedure_set_attribution (procedure, "Tim Newsome", "Tim Newsome, Sven Neumann, " "Tom Rathborne, TC", "1997 - 2000"); PIKA_PROC_ARG_INT (procedure, "hwidth", "H width", "Horizontal width", 0, PIKA_MAX_IMAGE_SIZE, 1, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "hspace", "H space", "Horizontal spacing", 1, PIKA_MAX_IMAGE_SIZE, 16, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "hoffset", "H offset", "Horizontal offset", 0, PIKA_MAX_IMAGE_SIZE, 8, G_PARAM_READWRITE); /* TODO: for "hcolor", "icolor" and "vcolor", the original code would use * the foreground color as default. It would be interesting if * PIKA_PROC_ARG_RGB() had a way to specify the foreground or background * colors as default (instead of a hardcoded color). */ PIKA_PROC_ARG_RGB (procedure, "hcolor", "H color", "Horizontal color", TRUE, &black, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "vwidth", "V width", "Vertical width", 0, PIKA_MAX_IMAGE_SIZE, 1, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "vspace", "V space", "Vertical spacing", 1, PIKA_MAX_IMAGE_SIZE, 16, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "voffset", "V offset", "Vertical offset", 0, PIKA_MAX_IMAGE_SIZE, 8, G_PARAM_READWRITE); PIKA_PROC_ARG_RGB (procedure, "vcolor", "V color", "Vertical color", TRUE, &black, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "iwidth", "I width", "Intersection width", 0, PIKA_MAX_IMAGE_SIZE, 0, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "ispace", "I space", "Intersection spacing", 1, PIKA_MAX_IMAGE_SIZE, 2, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "ioffset", "I offset", "Intersection offset", 0, PIKA_MAX_IMAGE_SIZE, 6, G_PARAM_READWRITE); PIKA_PROC_ARG_RGB (procedure, "icolor", "I color", "Intersection color", TRUE, &black, G_PARAM_READWRITE); } return procedure; } static PikaValueArray * grid_run (PikaProcedure *procedure, PikaRunMode run_mode, PikaImage *image, gint n_drawables, PikaDrawable **drawables, PikaProcedureConfig *config, gpointer run_data) { PikaDrawable *drawable; gegl_init (NULL, NULL); if (n_drawables != 1) { GError *error = NULL; g_set_error (&error, PIKA_PLUG_IN_ERROR, 0, _("Procedure '%s' only works with one drawable."), PLUG_IN_PROC); return pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR, error); } else { drawable = drawables[0]; } if (run_mode == PIKA_RUN_INTERACTIVE && ! dialog (image, drawable, procedure, config)) return pika_procedure_new_return_values (procedure, PIKA_PDB_CANCEL, NULL); pika_progress_init (_("Drawing grid")); render_grid (image, drawable, config, NULL); if (run_mode != PIKA_RUN_NONINTERACTIVE) pika_displays_flush (); return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL); } #define MAXDIFF 195076 static guchar best_cmap_match (const guchar *cmap, gint ncolors, const PikaRGB *color) { guchar cmap_index = 0; gint max = MAXDIFF; gint i, diff, sum; guchar r, g, b; pika_rgb_get_uchar (color, &r, &g, &b); for (i = 0; i < ncolors; i++) { diff = r - *cmap++; sum = SQR (diff); diff = g - *cmap++; sum += SQR (diff); diff = b - *cmap++; sum += SQR (diff); if (sum < max) { cmap_index = i; max = sum; } } return cmap_index; } static inline void pix_composite (guchar *p1, guchar p2[4], gint bytes, gboolean blend, gboolean alpha) { gint b; if (blend) { if (alpha) bytes--; for (b = 0; b < bytes; b++) { *p1 = *p1 * (1.0 - p2[3]/255.0) + p2[b] * p2[3]/255.0; p1++; } } else { /* blend should only be TRUE for indexed (bytes == 1) */ *p1++ = *p2; } if (alpha && *p1 < 255) { b = *p1 + 255.0 * ((gdouble) p2[3] / (255.0 - *p1)); *p1 = b > 255 ? 255 : b; } } static void render_grid (PikaImage *image, PikaDrawable *drawable, PikaProcedureConfig *config, PikaPreview *preview) { GeglBuffer *src_buffer = NULL; GeglBuffer *dest_buffer = NULL; const Babl *format; gint bytes; gint x_offset; gint y_offset; guchar *dest = NULL; guchar *buffer = NULL; gint x, y; gboolean alpha; gboolean blend; guchar hcolor[4]; guchar vcolor[4]; guchar icolor[4]; guchar *cmap; gint ncolors; gint hwidth; gint hspace; gint hoffset; PikaRGB *hcolor_rgb; gint vwidth; gint vspace; gint voffset; PikaRGB *vcolor_rgb; gint iwidth; gint ispace; gint ioffset; PikaRGB *icolor_rgb; g_object_get (config, "hwidth", &hwidth, "hspace", &hspace, "hoffset", &hoffset, "hcolor", &hcolor_rgb, "vwidth", &vwidth, "vspace", &vspace, "voffset", &voffset, "vcolor", &vcolor_rgb, "iwidth", &iwidth, "ispace", &ispace, "ioffset", &ioffset, "icolor", &icolor_rgb, NULL); pika_rgba_get_uchar (hcolor_rgb, hcolor, hcolor + 1, hcolor + 2, hcolor + 3); pika_rgba_get_uchar (vcolor_rgb, vcolor, vcolor + 1, vcolor + 2, vcolor + 3); pika_rgba_get_uchar (icolor_rgb, icolor, icolor + 1, icolor + 2, icolor + 3); alpha = pika_drawable_has_alpha (drawable); switch (pika_image_get_base_type (image)) { case PIKA_RGB: blend = TRUE; if (alpha) format = babl_format ("R'G'B'A u8"); else format = babl_format ("R'G'B' u8"); break; case PIKA_GRAY: hcolor[0] = pika_rgb_luminance_uchar (hcolor_rgb); vcolor[0] = pika_rgb_luminance_uchar (vcolor_rgb); icolor[0] = pika_rgb_luminance_uchar (icolor_rgb); blend = TRUE; if (alpha) format = babl_format ("Y'A u8"); else format = babl_format ("Y' u8"); break; case PIKA_INDEXED: cmap = pika_image_get_colormap (image, NULL, &ncolors); hcolor[0] = best_cmap_match (cmap, ncolors, hcolor_rgb); vcolor[0] = best_cmap_match (cmap, ncolors, vcolor_rgb); icolor[0] = best_cmap_match (cmap, ncolors, icolor_rgb); g_free (cmap); blend = FALSE; format = pika_drawable_get_format (drawable); break; default: g_assert_not_reached (); blend = FALSE; } bytes = babl_format_get_bytes_per_pixel (format); if (preview) { pika_preview_get_position (preview, &sx1, &sy1); pika_preview_get_size (preview, &sx2, &sy2); buffer = g_new (guchar, bytes * sx2 * sy2); sx2 += sx1; sy2 += sy1; } else { gint w, h; if (! pika_drawable_mask_intersect (drawable, &sx1, &sy1, &w, &h)) return; sx2 = sx1 + w; sy2 = sy1 + h; dest_buffer = pika_drawable_get_shadow_buffer (drawable); } src_buffer = pika_drawable_get_buffer (drawable); dest = g_new (guchar, (sx2 - sx1) * bytes); for (y = sy1; y < sy2; y++) { gegl_buffer_get (src_buffer, GEGL_RECTANGLE (sx1, y, sx2 - sx1, 1), 1.0, format, dest, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); y_offset = y - hoffset; while (y_offset < 0) y_offset += hspace; if ((y_offset + (hwidth / 2)) % hspace < hwidth) { for (x = sx1; x < sx2; x++) { pix_composite (&dest[(x-sx1) * bytes], hcolor, bytes, blend, alpha); } } for (x = sx1; x < sx2; x++) { x_offset = vspace + x - voffset; while (x_offset < 0) x_offset += vspace; if ((x_offset + (vwidth / 2)) % vspace < vwidth) { pix_composite (&dest[(x-sx1) * bytes], vcolor, bytes, blend, alpha); } if ((x_offset + (iwidth / 2)) % vspace < iwidth && ((y_offset % hspace >= ispace && y_offset % hspace < ioffset) || (hspace - (y_offset % hspace) >= ispace && hspace - (y_offset % hspace) < ioffset))) { pix_composite (&dest[(x-sx1) * bytes], icolor, bytes, blend, alpha); } } if ((y_offset + (iwidth / 2)) % hspace < iwidth) { for (x = sx1; x < sx2; x++) { x_offset = vspace + x - voffset; while (x_offset < 0) x_offset += vspace; if ((x_offset % vspace >= ispace && x_offset % vspace < ioffset) || (vspace - (x_offset % vspace) >= ispace && vspace - (x_offset % vspace) < ioffset)) { pix_composite (&dest[(x-sx1) * bytes], icolor, bytes, blend, alpha); } } } if (preview) { memcpy (buffer + (y - sy1) * (sx2 - sx1) * bytes, dest, (sx2 - sx1) * bytes); } else { gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (sx1, y, sx2 - sx1, 1), 0, format, dest, GEGL_AUTO_ROWSTRIDE); if (y % 16 == 0) pika_progress_update ((gdouble) y / (gdouble) (sy2 - sy1)); } } g_free (dest); g_object_unref (src_buffer); if (preview) { pika_preview_draw_buffer (preview, buffer, bytes * (sx2 - sx1)); g_free (buffer); } else { pika_progress_update (1.0); g_object_unref (dest_buffer); pika_drawable_merge_shadow (drawable, TRUE); pika_drawable_update (drawable, sx1, sy1, sx2 - sx1, sy2 - sy1); } } /*************************************************** * GUI stuff */ static void update_values (Grid *grid) { GtkWidget *entry; PikaRGB color; entry = g_object_get_data (G_OBJECT (main_dialog), "width"); g_object_set (grid->config, "hwidth", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 0)), "vwidth", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 1)), "iwidth", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 2)), NULL); entry = g_object_get_data (G_OBJECT (main_dialog), "space"); g_object_set (grid->config, "hspace", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 0)), "vspace", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 1)), "ispace", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 2)), NULL); entry = g_object_get_data (G_OBJECT (main_dialog), "offset"); g_object_set (grid->config, "hoffset", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 0)), "voffset", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 1)), "ioffset", (gint) RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (entry), 2)), NULL); pika_color_button_get_color (PIKA_COLOR_BUTTON (grid->hcolor_button), &color); g_object_set (grid->config, "hcolor", &color, NULL); pika_color_button_get_color (PIKA_COLOR_BUTTON (grid->vcolor_button), &color); g_object_set (grid->config, "vcolor", &color, NULL); pika_color_button_get_color (PIKA_COLOR_BUTTON (grid->icolor_button), &color); g_object_set (grid->config, "icolor", &color, NULL); } static void update_preview (PikaPreview *preview, Grid *grid) { update_values (grid); render_grid (pika_item_get_image (PIKA_ITEM (grid->drawable)), grid->drawable, grid->config, preview); } static void entry_callback (GtkWidget *widget, gpointer data) { static gdouble x = -1.0; static gdouble y = -1.0; gdouble new_x; gdouble new_y; new_x = pika_size_entry_get_refval (PIKA_SIZE_ENTRY (widget), 0); new_y = pika_size_entry_get_refval (PIKA_SIZE_ENTRY (widget), 1); if (pika_chain_button_get_active (PIKA_CHAIN_BUTTON (data))) { if (new_x != x) { y = new_y = x = new_x; pika_size_entry_set_refval (PIKA_SIZE_ENTRY (widget), 1, y); } if (new_y != y) { x = new_x = y = new_y; pika_size_entry_set_refval (PIKA_SIZE_ENTRY (widget), 0, x); } } else { x = new_x; y = new_y; } } static void color_callback (GtkWidget *widget, gpointer data) { Grid *grid = GRID (data); GtkWidget *chain_button = grid->color_chain; if (pika_chain_button_get_active (PIKA_CHAIN_BUTTON (chain_button))) { PikaRGB color; pika_color_button_get_color (PIKA_COLOR_BUTTON (widget), &color); if (widget == grid->vcolor_button) pika_color_button_set_color (PIKA_COLOR_BUTTON (grid->hcolor_button), &color); else if (widget == grid->hcolor_button) pika_color_button_set_color (PIKA_COLOR_BUTTON (grid->vcolor_button), &color); } } static gint dialog (PikaImage *image, PikaDrawable *drawable, PikaProcedure *procedure, PikaProcedureConfig *config) { Grid *grid; PikaColorConfig *color_config; GtkWidget *dlg; GtkWidget *main_vbox; GtkWidget *vbox; GtkSizeGroup *group; GtkWidget *label; GtkWidget *preview; GtkWidget *width; GtkWidget *space; GtkWidget *offset; GtkWidget *chain_button; PikaUnit unit; gint d_width; gint d_height; gdouble xres; gdouble yres; gboolean run; gint hwidth; gint hspace; gint hoffset; PikaRGB *hcolor; gint vwidth; gint vspace; gint voffset; PikaRGB *vcolor; gint iwidth; gint ispace; gint ioffset; PikaRGB *icolor; g_return_val_if_fail (main_dialog == NULL, FALSE); g_object_get (config, "hwidth", &hwidth, "hspace", &hspace, "hoffset", &hoffset, "hcolor", &hcolor, "vwidth", &vwidth, "vspace", &vspace, "voffset", &voffset, "vcolor", &vcolor, "iwidth", &iwidth, "ispace", &ispace, "ioffset", &ioffset, "icolor", &icolor, NULL); pika_ui_init (PLUG_IN_BINARY); d_width = pika_drawable_get_width (drawable); d_height = pika_drawable_get_height (drawable); main_dialog = dlg = pika_dialog_new (_("Grid"), PLUG_IN_ROLE, NULL, 0, pika_standard_help_func, PLUG_IN_PROC, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_OK"), GTK_RESPONSE_OK, NULL); pika_dialog_set_alternative_button_order (GTK_DIALOG (dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); pika_window_set_transient (GTK_WINDOW (dlg)); /* Get the image resolution and unit */ pika_image_get_resolution (image, &xres, &yres); unit = pika_image_get_unit (image); main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), main_vbox, TRUE, TRUE, 0); gtk_widget_show (main_vbox); preview = pika_drawable_preview_new_from_drawable (drawable); gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0); gtk_widget_show (preview); grid = GRID (pika_procedure_get_plug_in (procedure)); grid->drawable = drawable; grid->config = config; g_signal_connect (preview, "invalidated", G_CALLBACK (update_preview), grid); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0); gtk_widget_show (vbox); /* The width entries */ width = pika_size_entry_new (3, /* number_of_fields */ unit, /* unit */ "%a", /* unit_format */ TRUE, /* menu_show_pixels */ TRUE, /* menu_show_percent */ FALSE, /* show_refval */ SPIN_BUTTON_WIDTH, /* spinbutton_usize */ PIKA_SIZE_ENTRY_UPDATE_SIZE); /* update_policy */ gtk_box_pack_start (GTK_BOX (vbox), width, FALSE, FALSE, 0); gtk_widget_show (width); /* set the unit back to pixels, since most times we will want pixels */ pika_size_entry_set_unit (PIKA_SIZE_ENTRY (width), PIKA_UNIT_PIXEL); /* set the resolution to the image resolution */ pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (width), 0, xres, TRUE); pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (width), 1, yres, TRUE); pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (width), 2, xres, TRUE); /* set the size (in pixels) that will be treated as 0% and 100% */ pika_size_entry_set_size (PIKA_SIZE_ENTRY (width), 0, 0.0, d_height); pika_size_entry_set_size (PIKA_SIZE_ENTRY (width), 1, 0.0, d_width); pika_size_entry_set_size (PIKA_SIZE_ENTRY (width), 2, 0.0, d_width); /* set upper and lower limits (in pixels) */ pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (width), 0, 0.0, d_height); pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (width), 1, 0.0, d_width); pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (width), 2, 0.0, MAX (d_width, d_height)); gtk_grid_set_column_spacing (GTK_GRID (width), 6); /* initialize the values */ pika_size_entry_set_refval (PIKA_SIZE_ENTRY (width), 0, hwidth); pika_size_entry_set_refval (PIKA_SIZE_ENTRY (width), 1, vwidth); pika_size_entry_set_refval (PIKA_SIZE_ENTRY (width), 2, iwidth); /* attach labels */ pika_size_entry_attach_label (PIKA_SIZE_ENTRY (width), _("Horizontal\nLines"), 0, 1, 0.0); pika_size_entry_attach_label (PIKA_SIZE_ENTRY (width), _("Vertical\nLines"), 0, 2, 0.0); pika_size_entry_attach_label (PIKA_SIZE_ENTRY (width), _("Intersection"), 0, 3, 0.0); label = pika_size_entry_attach_label (PIKA_SIZE_ENTRY (width), _("Width:"), 1, 0, 0.0); group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); gtk_size_group_add_widget (group, label); g_object_unref (group); /* put a chain_button under the size_entries */ chain_button = pika_chain_button_new (PIKA_CHAIN_BOTTOM); if (hwidth == vwidth) pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain_button), TRUE); gtk_grid_attach (GTK_GRID (width), chain_button, 1, 2, 2, 1); gtk_widget_show (chain_button); /* connect to the 'value-changed' signal because we have to take care * of keeping the entries in sync when the chainbutton is active */ g_signal_connect (width, "value-changed", G_CALLBACK (entry_callback), chain_button); g_signal_connect_swapped (width, "value-changed", G_CALLBACK (pika_preview_invalidate), preview); /* The spacing entries */ space = pika_size_entry_new (3, /* number_of_fields */ unit, /* unit */ "%a", /* unit_format */ TRUE, /* menu_show_pixels */ TRUE, /* menu_show_percent */ FALSE, /* show_refval */ SPIN_BUTTON_WIDTH, /* spinbutton_usize */ PIKA_SIZE_ENTRY_UPDATE_SIZE); /* update_policy */ gtk_box_pack_start (GTK_BOX (vbox), space, FALSE, FALSE, 0); gtk_widget_show (space); pika_size_entry_set_unit (PIKA_SIZE_ENTRY (space), PIKA_UNIT_PIXEL); /* set the resolution to the image resolution */ pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (space), 0, xres, TRUE); pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (space), 1, yres, TRUE); pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (space), 2, xres, TRUE); /* set the size (in pixels) that will be treated as 0% and 100% */ pika_size_entry_set_size (PIKA_SIZE_ENTRY (space), 0, 0.0, d_height); pika_size_entry_set_size (PIKA_SIZE_ENTRY (space), 1, 0.0, d_width); pika_size_entry_set_size (PIKA_SIZE_ENTRY (space), 2, 0.0, d_width); /* set upper and lower limits (in pixels) */ pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (space), 0, 1.0, d_height); pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (space), 1, 1.0, d_width); pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (space), 2, 0.0, MAX (d_width, d_height)); gtk_grid_set_column_spacing (GTK_GRID (space), 6); /* initialize the values */ pika_size_entry_set_refval (PIKA_SIZE_ENTRY (space), 0, hspace); pika_size_entry_set_refval (PIKA_SIZE_ENTRY (space), 1, vspace); pika_size_entry_set_refval (PIKA_SIZE_ENTRY (space), 2, ispace); /* attach labels */ label = pika_size_entry_attach_label (PIKA_SIZE_ENTRY (space), _("Spacing:"), 1, 0, 0.0); gtk_size_group_add_widget (group, label); /* put a chain_button under the spacing_entries */ chain_button = pika_chain_button_new (PIKA_CHAIN_BOTTOM); if (hspace == vspace) pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain_button), TRUE); gtk_grid_attach (GTK_GRID (space), chain_button, 1, 2, 2, 1); gtk_widget_show (chain_button); /* connect to the 'value-changed' and "unit-changed" signals because * we have to take care of keeping the entries in sync when the * chainbutton is active */ g_signal_connect (space, "value-changed", G_CALLBACK (entry_callback), chain_button); g_signal_connect (space, "unit-changed", G_CALLBACK (entry_callback), chain_button); g_signal_connect_swapped (space, "value-changed", G_CALLBACK (pika_preview_invalidate), preview); /* The offset entries */ offset = pika_size_entry_new (3, /* number_of_fields */ unit, /* unit */ "%a", /* unit_format */ TRUE, /* menu_show_pixels */ TRUE, /* menu_show_percent */ FALSE, /* show_refval */ SPIN_BUTTON_WIDTH, /* spinbutton_usize */ PIKA_SIZE_ENTRY_UPDATE_SIZE); /* update_policy */ gtk_box_pack_start (GTK_BOX (vbox), offset, FALSE, FALSE, 0); gtk_widget_show (offset); pika_size_entry_set_unit (PIKA_SIZE_ENTRY (offset), PIKA_UNIT_PIXEL); /* set the resolution to the image resolution */ pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (offset), 0, xres, TRUE); pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (offset), 1, yres, TRUE); pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (offset), 2, xres, TRUE); /* set the size (in pixels) that will be treated as 0% and 100% */ pika_size_entry_set_size (PIKA_SIZE_ENTRY (offset), 0, 0.0, d_height); pika_size_entry_set_size (PIKA_SIZE_ENTRY (offset), 1, 0.0, d_width); pika_size_entry_set_size (PIKA_SIZE_ENTRY (offset), 2, 0.0, d_width); /* set upper and lower limits (in pixels) */ pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (offset), 0, 0.0, d_height); pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (offset), 1, 0.0, d_width); pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (offset), 2, 0.0, MAX (d_width, d_height)); gtk_grid_set_column_spacing (GTK_GRID (offset), 6); /* initialize the values */ pika_size_entry_set_refval (PIKA_SIZE_ENTRY (offset), 0, hoffset); pika_size_entry_set_refval (PIKA_SIZE_ENTRY (offset), 1, voffset); pika_size_entry_set_refval (PIKA_SIZE_ENTRY (offset), 2, ioffset); /* attach labels */ label = pika_size_entry_attach_label (PIKA_SIZE_ENTRY (offset), _("Offset:"), 1, 0, 0.0); gtk_size_group_add_widget (group, label); /* put a chain_button under the offset_entries */ chain_button = pika_chain_button_new (PIKA_CHAIN_BOTTOM); if (hoffset == voffset) pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain_button), TRUE); gtk_grid_attach (GTK_GRID (offset), chain_button, 1, 2, 2, 1); gtk_widget_show (chain_button); /* connect to the 'value-changed' and "unit-changed" signals because * we have to take care of keeping the entries in sync when the * chainbutton is active */ g_signal_connect (offset, "value-changed", G_CALLBACK (entry_callback), chain_button); g_signal_connect (offset, "unit-changed", G_CALLBACK (entry_callback), chain_button); g_signal_connect_swapped (offset, "value-changed", G_CALLBACK (pika_preview_invalidate), preview); /* put a chain_button under the color_buttons */ grid->color_chain = pika_chain_button_new (PIKA_CHAIN_BOTTOM); if (pika_rgba_distance (hcolor, vcolor) < 0.0001) pika_chain_button_set_active (PIKA_CHAIN_BUTTON (grid->color_chain), TRUE); gtk_grid_attach (GTK_GRID (offset), grid->color_chain, 1, 4, 2, 1); gtk_widget_show (grid->color_chain); /* attach color selectors */ grid->hcolor_button = pika_color_button_new (_("Horizontal Color"), COLOR_BUTTON_WIDTH, 16, hcolor, PIKA_COLOR_AREA_SMALL_CHECKS); pika_color_button_set_update (PIKA_COLOR_BUTTON (grid->hcolor_button), TRUE); gtk_grid_attach (GTK_GRID (offset), grid->hcolor_button, 1, 3, 1, 1); gtk_widget_show (grid->hcolor_button); color_config = pika_get_color_configuration (); pika_color_button_set_color_config (PIKA_COLOR_BUTTON (grid->hcolor_button), color_config); g_signal_connect (grid->hcolor_button, "color-changed", G_CALLBACK (pika_color_button_get_color), hcolor); g_signal_connect (grid->hcolor_button, "color-changed", G_CALLBACK (color_callback), grid); g_signal_connect_swapped (grid->hcolor_button, "color-changed", G_CALLBACK (pika_preview_invalidate), preview); grid->vcolor_button = pika_color_button_new (_("Vertical Color"), COLOR_BUTTON_WIDTH, 16, vcolor, PIKA_COLOR_AREA_SMALL_CHECKS); pika_color_button_set_update (PIKA_COLOR_BUTTON (grid->vcolor_button), TRUE); gtk_grid_attach (GTK_GRID (offset), grid->vcolor_button, 2, 3, 1, 1); gtk_widget_show (grid->vcolor_button); pika_color_button_set_color_config (PIKA_COLOR_BUTTON (grid->vcolor_button), color_config); g_signal_connect (grid->vcolor_button, "color-changed", G_CALLBACK (pika_color_button_get_color), vcolor); g_signal_connect (grid->vcolor_button, "color-changed", G_CALLBACK (color_callback), grid); g_signal_connect_swapped (grid->vcolor_button, "color-changed", G_CALLBACK (pika_preview_invalidate), preview); grid->icolor_button = pika_color_button_new (_("Intersection Color"), COLOR_BUTTON_WIDTH, 16, icolor, PIKA_COLOR_AREA_SMALL_CHECKS); pika_color_button_set_update (PIKA_COLOR_BUTTON (grid->icolor_button), TRUE); gtk_grid_attach (GTK_GRID (offset), grid->icolor_button, 3, 3, 1, 1); gtk_widget_show (grid->icolor_button); pika_color_button_set_color_config (PIKA_COLOR_BUTTON (grid->icolor_button), color_config); g_object_unref (color_config); g_signal_connect (grid->icolor_button, "color-changed", G_CALLBACK (pika_color_button_get_color), icolor); g_signal_connect_swapped (grid->icolor_button, "color-changed", G_CALLBACK (pika_preview_invalidate), preview); gtk_widget_show (dlg); g_object_set_data (G_OBJECT (dlg), "width", width); g_object_set_data (G_OBJECT (dlg), "space", space); g_object_set_data (G_OBJECT (dlg), "offset", offset); run = (pika_dialog_run (PIKA_DIALOG (dlg)) == GTK_RESPONSE_OK); if (run) update_values (grid); gtk_widget_destroy (dlg); return run; }