diff --git a/ChangeLog b/ChangeLog index 7c64315b23..e437211acd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,55 @@ +2003-06-23 Henrik Brix Andersen + + Added a per image configurable grid. + This fixes bug #65198 + + * app/core/Makefile.am + * app/core/core-types.h: + * app/core/gimpgrid.[ch]: added new class GimpGrid. + + * app/core/core-enums.[ch]: added new enum GimpGridType. + + * app/core/gimpimage-guides.[ch]: removed the gimp_image_snap_*() + functions... + + * app/core/gimpimage-snap.[ch]: ...and added them here since they + are no longer guide specific. + + * app/core/gimpimage-undo-push.[ch]: added + gimp_image_undo_push_image_grid() + + * app/display/gimpdisplayshell-handlers.c: + * app/core/gimpimage.[ch]: added grid member to _GimpImage. Added + new signal "grid_changed", added gimp_image_grid_changed(), + gimp_image_get_grid() and gimp_image_set_grid(). + + * app/display/gimpdisplayshell-appearance.[ch]: added + gimp_display_shell_set_show_grid(), + gimp_display_shell_get_show_grid(), + gimp_display_shell_set_snap_to_grid() and + gimp_display_shell_get_snap_to_grid(). + + * app/display/gimpdisplayshell-callbacks.c: added call to + gimp_display_shell_draw_grid() + + * app/display/gimpdisplayshell.[ch]: added grid member to + _GimpDisplayShellVisibility, added snap_to_grid and grid_dialog + members to _GimpDisplayShell, added + gimp_display_shell_draw_grid(), modified + gimp_display_shell_snap_coords() to use the new + gimp_image_snap_*() functions. + + * app/gui/image-menu.c: added grid entries to + image_menu_entries[]. + + * app/gui/view-commands.[ch]: added + view_configure_grid_cmd_callback(), + view_toggle_grid_cmd_callback() and + view_snap_to_grid_cmd_callback(). + + * app/gui/Makefile.am + * app/gui/grid-dialog.[ch]: added a grid dialog. + 2003-06-23 Michael Natterer * app/plug-in/plug-in.[ch]: added separate GMainLoops for waiting diff --git a/app/actions/view-commands.c b/app/actions/view-commands.c index 992a66f8aa..98a33d26e5 100644 --- a/app/actions/view-commands.c +++ b/app/actions/view-commands.c @@ -42,6 +42,7 @@ #include "dialogs.h" #include "info-dialog.h" #include "info-window.h" +#include "grid-dialog.h" #include "view-commands.h" @@ -350,6 +351,63 @@ view_snap_to_guides_cmd_callback (GtkWidget *widget, } } +void +view_configure_grid_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDisplay *gdisp; + GtkWidget *grid_dialog; + return_if_no_display (gdisp, data); + + grid_dialog = grid_dialog_new (GIMP_DISPLAY (gdisp)); + + g_signal_connect_object (gdisp, "disconnect", + G_CALLBACK (gtk_widget_destroy), + grid_dialog, + G_CONNECT_SWAPPED); + + gtk_widget_show (grid_dialog); +} + + +void +view_toggle_grid_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDisplay *gdisp; + GimpDisplayShell *shell; + return_if_no_display (gdisp, data); + + shell = GIMP_DISPLAY_SHELL (gdisp->shell); + + gimp_display_shell_set_show_grid (shell, + GTK_CHECK_MENU_ITEM (widget)->active); + +} + +void +view_snap_to_grid_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDisplay *gdisp; + GimpDisplayShell *shell; + return_if_no_display (gdisp, data); + + shell = GIMP_DISPLAY_SHELL (gdisp->shell); + + if (shell->snap_to_grid != GTK_CHECK_MENU_ITEM (widget)->active) + { + shell->snap_to_grid = GTK_CHECK_MENU_ITEM (widget)->active; + + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->menubar_factory), + "/View/Snap to Grid", + shell->snap_to_grid); + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->popup_factory), + "/View/Snap to Grid", + shell->snap_to_grid); + } +} + void view_new_view_cmd_callback (GtkWidget *widget, gpointer data) diff --git a/app/actions/view-commands.h b/app/actions/view-commands.h index 858e31496a..20c9495ec9 100644 --- a/app/actions/view-commands.h +++ b/app/actions/view-commands.h @@ -57,6 +57,12 @@ void view_toggle_guides_cmd_callback (GtkWidget *widget, gpointer data); void view_snap_to_guides_cmd_callback (GtkWidget *widget, gpointer data); +void view_toggle_grid_cmd_callback (GtkWidget *widget, + gpointer data); +void view_configure_grid_cmd_callback (GtkWidget *widget, + gpointer data); +void view_snap_to_grid_cmd_callback (GtkWidget *widget, + gpointer data); void view_new_view_cmd_callback (GtkWidget *widget, gpointer data); void view_shrink_wrap_cmd_callback (GtkWidget *widget, diff --git a/app/core/Makefile.am b/app/core/Makefile.am index 301f7f1a94..a2375d048d 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -83,6 +83,8 @@ libappcore_a_sources = \ gimpenvirontable.c \ gimpgradient.c \ gimpgradient.h \ + gimpgrid.c \ + gimpgrid.h \ gimpimage.c \ gimpimage.h \ gimpimage-colorhash.c \ @@ -125,6 +127,8 @@ libappcore_a_sources = \ gimpimage-rotate.h \ gimpimage-scale.c \ gimpimage-scale.h \ + gimpimage-snap.c \ + gimpimage-snap.h \ gimpimage-undo.c \ gimpimage-undo.h \ gimpimage-undo-push.c \ diff --git a/app/core/core-enums.c b/app/core/core-enums.c index 18425aedb1..8304590f4f 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -213,6 +213,27 @@ gimp_gradient_type_get_type (void) } +static const GEnumValue gimp_grid_type_enum_values[] = +{ + { GIMP_GRID_TYPE_INTERSECTION, N_("Intersections Only"), "intersection" }, + { GIMP_GRID_TYPE_ON_OFF_DASH, N_("Dashed"), "on-off-dash" }, + { GIMP_GRID_TYPE_DOUBLE_DASH, N_("Double Dashed"), "double-dash" }, + { GIMP_GRID_TYPE_SOLID, N_("Solid"), "solid" }, + { 0, NULL, NULL } +}; + +GType +gimp_grid_type_get_type (void) +{ + static GType enum_type = 0; + + if (!enum_type) + enum_type = g_enum_register_static ("GimpGridType", gimp_grid_type_enum_values); + + return enum_type; +} + + static const GEnumValue gimp_image_base_type_enum_values[] = { { GIMP_RGB, N_("RGB"), "rgb" }, @@ -456,6 +477,7 @@ static const GEnumValue gimp_undo_type_enum_values[] = { GIMP_UNDO_GROUP_IMAGE_CROP, N_("Crop Image"), "group-image-crop" }, { GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, N_("Merge Layers"), "group-image-layers-merge" }, { GIMP_UNDO_GROUP_IMAGE_QMASK, N_("QuickMask"), "group-image-qmask" }, + { GIMP_UNDO_GROUP_IMAGE_GRID, N_("Grid"), "group-image-grid" }, { GIMP_UNDO_GROUP_IMAGE_GUIDE, N_("Guide"), "group-image-guide" }, { GIMP_UNDO_GROUP_MASK, N_("Selection Mask"), "group-mask" }, { GIMP_UNDO_GROUP_ITEM_PROPERTIES, N_("Item Properties"), "group-item-properties" }, @@ -483,6 +505,7 @@ static const GEnumValue gimp_undo_type_enum_values[] = { GIMP_UNDO_IMAGE_SIZE, N_("Image Size"), "image-size" }, { GIMP_UNDO_IMAGE_RESOLUTION, N_("Resolution Change"), "image-resolution" }, { GIMP_UNDO_IMAGE_QMASK, N_("QuickMask"), "image-qmask" }, + { GIMP_UNDO_IMAGE_GRID, N_("Grid"), "image-grid" }, { GIMP_UNDO_IMAGE_GUIDE, N_("Guide"), "image-guide" }, { GIMP_UNDO_IMAGE_COLORMAP, N_("Change Indexed Palette"), "image-colormap" }, { GIMP_UNDO_MASK, N_("Selection Mask"), "mask" }, diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 2c5bd04901..f1350f555a 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -170,6 +170,19 @@ typedef enum } GimpGradientType; +#define GIMP_TYPE_GRID_TYPE (gimp_grid_type_get_type ()) + +GType gimp_grid_type_get_type (void) G_GNUC_CONST; + +typedef enum /*< pdb-skip >*/ +{ + GIMP_GRID_TYPE_INTERSECTION, /*< desc="Intersections Only" >*/ + GIMP_GRID_TYPE_ON_OFF_DASH, /*< desc="Dashed" >*/ + GIMP_GRID_TYPE_DOUBLE_DASH, /*< desc="Double Dashed" >*/ + GIMP_GRID_TYPE_SOLID /*< desc="Solid" >*/ +} GimpGridType; + + #define GIMP_TYPE_IMAGE_BASE_TYPE (gimp_image_base_type_get_type ()) GType gimp_image_base_type_get_type (void) G_GNUC_CONST; @@ -335,6 +348,7 @@ typedef enum /*< pdb-skip >*/ GIMP_UNDO_GROUP_IMAGE_CROP, /*< desc="Crop Image" >*/ GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, /*< desc="Merge Layers" >*/ GIMP_UNDO_GROUP_IMAGE_QMASK, /*< desc="QuickMask" >*/ + GIMP_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/ GIMP_UNDO_GROUP_IMAGE_GUIDE, /*< desc="Guide" >*/ GIMP_UNDO_GROUP_MASK, /*< desc="Selection Mask" >*/ GIMP_UNDO_GROUP_ITEM_PROPERTIES, /*< desc="Item Properties" >*/ @@ -367,6 +381,7 @@ typedef enum /*< pdb-skip >*/ GIMP_UNDO_IMAGE_SIZE, /*< desc="Image Size" >*/ GIMP_UNDO_IMAGE_RESOLUTION, /*< desc="Resolution Change" >*/ GIMP_UNDO_IMAGE_QMASK, /*< desc="QuickMask" >*/ + GIMP_UNDO_IMAGE_GRID, /*< desc="Grid" >*/ GIMP_UNDO_IMAGE_GUIDE, /*< desc="Guide" >*/ GIMP_UNDO_IMAGE_COLORMAP, /*< desc="Change Indexed Palette" >*/ GIMP_UNDO_MASK, /*< desc="Selection Mask" >*/ diff --git a/app/core/core-types.h b/app/core/core-types.h index 5bb28778e1..3db81452bf 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -73,6 +73,7 @@ typedef struct _GimpDocumentList GimpDocumentList; typedef struct _GimpTemplate GimpTemplate; +typedef struct _GimpGrid GimpGrid; /* drawable objects */ diff --git a/app/core/gimpgrid.c b/app/core/gimpgrid.c new file mode 100644 index 0000000000..cdeb72e736 --- /dev/null +++ b/app/core/gimpgrid.c @@ -0,0 +1,255 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "libgimpbase/gimplimits.h" +#include "libgimpcolor/gimpcolor.h" + +#include "core-types.h" + +#include "config/gimpconfig.h" +#include "config/gimpconfig-params.h" + +#include "gimpgrid.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_XSPACING, + PROP_YSPACING, + PROP_SPACING_UNIT, + PROP_XOFFSET, + PROP_YOFFSET, + PROP_OFFSET_UNIT, + PROP_FGCOLOR, + PROP_BGCOLOR, + PROP_TYPE +}; + +static void gimp_grid_class_init (GimpGridClass *klass); +static void gimp_grid_finalize (GObject *object); +static void gimp_grid_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_grid_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + + +static GObjectClass *parent_class = NULL; + + +GType +gimp_grid_get_type (void) +{ + static GType grid_type = 0; + + if (! grid_type) + { + static const GTypeInfo grid_info = + { + sizeof (GimpGridClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gimp_grid_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GimpGrid), + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + static const GInterfaceInfo grid_iface_info = + { + NULL, /* iface_init */ + NULL, /* iface_finalize */ + NULL /* iface_data */ + }; + + grid_type = g_type_register_static (G_TYPE_OBJECT, + "GimpGrid", &grid_info, 0); + + g_type_add_interface_static (grid_type, + GIMP_TYPE_CONFIG_INTERFACE, + &grid_iface_info); + } + + return grid_type; +} + +static void +gimp_grid_class_init (GimpGridClass *klass) +{ + GObjectClass *object_class; + GimpRGB black; + GimpRGB white; + + object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gimp_grid_finalize; + object_class->get_property = gimp_grid_get_property; + object_class->set_property = gimp_grid_set_property; + + gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); + gimp_rgba_set (&white, 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_XSPACING, + "xspacing", NULL, + 1.0, GIMP_MAX_IMAGE_SIZE, 10.0, + 0); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_YSPACING, + "yspacing", NULL, + 1.0, GIMP_MAX_IMAGE_SIZE, 10.0, + 0); + GIMP_CONFIG_INSTALL_PROP_UNIT (object_class, PROP_SPACING_UNIT, + "spacing-unit", NULL, + FALSE, GIMP_UNIT_INCH, + 0); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_XOFFSET, + "xoffset", NULL, + - GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE, 0.0, + 0); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_YOFFSET, + "yoffset", NULL, + - GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE, 0.0, + 0); + GIMP_CONFIG_INSTALL_PROP_UNIT (object_class, PROP_OFFSET_UNIT, + "offset-unit", NULL, + FALSE, GIMP_UNIT_INCH, + 0); + GIMP_CONFIG_INSTALL_PROP_COLOR (object_class, PROP_FGCOLOR, + "fgcolor", NULL, + &black, + 0); + GIMP_CONFIG_INSTALL_PROP_COLOR (object_class, PROP_BGCOLOR, + "bgcolor", NULL, + &white, + 0); + GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_TYPE, + "type", NULL, + GIMP_TYPE_GRID_TYPE, + GIMP_GRID_TYPE_INTERSECTION, + 0); +} + +static void +gimp_grid_finalize (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static void +gimp_grid_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpGrid *grid = GIMP_GRID (object); + + switch (property_id) + { + case PROP_XSPACING: + g_value_set_double (value, grid->xspacing); + break; + case PROP_YSPACING: + g_value_set_double (value, grid->yspacing); + break; + case PROP_SPACING_UNIT: + g_value_set_int (value, grid->spacing_unit); + break; + case PROP_XOFFSET: + g_value_set_double (value, grid->xoffset); + break; + case PROP_YOFFSET: + g_value_set_double (value, grid->yoffset); + break; + case PROP_OFFSET_UNIT: + g_value_set_int (value, grid->offset_unit); + break; + case PROP_FGCOLOR: + g_value_set_boxed (value, &grid->fgcolor); + break; + case PROP_BGCOLOR: + g_value_set_boxed (value, &grid->bgcolor); + break; + case PROP_TYPE: + g_value_set_enum (value, grid->type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_grid_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpGrid *grid = GIMP_GRID (object); + GimpRGB *color; + + switch (property_id) + { + case PROP_XSPACING: + grid->xspacing = g_value_get_double (value); + break; + case PROP_YSPACING: + grid->yspacing = g_value_get_double (value); + break; + case PROP_SPACING_UNIT: + grid->spacing_unit = g_value_get_int (value); + break; + case PROP_XOFFSET: + grid->xoffset = g_value_get_double (value); + break; + case PROP_YOFFSET: + grid->yoffset = g_value_get_double (value); + break; + case PROP_OFFSET_UNIT: + grid->offset_unit = g_value_get_int (value); + break; + case PROP_FGCOLOR: + color = g_value_get_boxed (value); + grid->fgcolor = *color; + break; + case PROP_BGCOLOR: + color = g_value_get_boxed (value); + grid->bgcolor = *color; + break; + case PROP_TYPE: + grid->type = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} diff --git a/app/core/gimpgrid.h b/app/core/gimpgrid.h new file mode 100644 index 0000000000..b7cf3bc8db --- /dev/null +++ b/app/core/gimpgrid.h @@ -0,0 +1,58 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_GRID_H__ +#define __GIMP_GRID_H__ + + +#define GIMP_TYPE_GRID (gimp_grid_get_type ()) +#define GIMP_GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_GRID, GimpGrid)) +#define GIMP_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_GRID, GimpGridClass)) +#define GIMP_IS_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_GRID)) +#define GIMP_IS_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_GRID)) +#define GIMP_GRID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_GRID, GimpGridClass)) + + +typedef struct _GimpGridClass GimpGridClass; + +struct _GimpGrid +{ + GObject parent_instance; + + gdouble xspacing; + gdouble yspacing; + GimpUnit spacing_unit; + gdouble xoffset; + gdouble yoffset; + GimpUnit offset_unit; + GimpRGB fgcolor; + GimpRGB bgcolor; + GimpGridType type; +}; + + +struct _GimpGridClass +{ + GObjectClass parent_class; +}; + + +GType gimp_grid_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_GRID_H__ */ diff --git a/app/core/gimpimage-guides.c b/app/core/gimpimage-guides.c index 66037ff00c..1e07195fac 100644 --- a/app/core/gimpimage-guides.c +++ b/app/core/gimpimage-guides.c @@ -216,209 +216,3 @@ gimp_image_find_guide (GimpImage *gimage, return NULL; } - -gboolean -gimp_image_snap_x (GimpImage *gimage, - gdouble x, - gint *tx) -{ - GList *list; - GimpGuide *guide; - gint mindist = G_MAXINT; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx != NULL, FALSE); - - *tx = ROUND (x); - - if (x < 0 || x >= gimage->width) - return FALSE; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - if (guide->orientation == GIMP_ORIENTATION_VERTICAL) - { - dist = ABS (guide->position - x); - - if (dist < MIN (GUIDE_EPSILON, mindist)) - { - mindist = dist; - *tx = guide->position; - snapped = TRUE; - } - } - } - - return snapped; -} - -gboolean -gimp_image_snap_y (GimpImage *gimage, - gdouble y, - gint *ty) -{ - GList *list; - GimpGuide *guide; - gint mindist = G_MAXINT; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (ty != NULL, FALSE); - - *ty = ROUND (y); - - if (y < 0 || y >= gimage->height) - return FALSE; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - if (guide->orientation == GIMP_ORIENTATION_HORIZONTAL) - { - dist = ABS (guide->position - y); - - if (dist < MIN (GUIDE_EPSILON, mindist)) - { - mindist = dist; - *ty = guide->position; - snapped = TRUE; - } - } - } - - return snapped; -} - -gboolean -gimp_image_snap_point (GimpImage *gimage, - gdouble x, - gdouble y, - gint *tx, - gint *ty) -{ - GList *list; - GimpGuide *guide; - gint minxdist, minydist; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx != NULL, FALSE); - g_return_val_if_fail (ty != NULL, FALSE); - - *tx = ROUND (x); - *ty = ROUND (y); - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return FALSE; - } - - minxdist = G_MAXINT; - minydist = G_MAXINT; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - switch (guide->orientation) - { - case GIMP_ORIENTATION_HORIZONTAL: - dist = ABS (guide->position - y); - - if (dist < MIN (GUIDE_EPSILON, minydist)) - { - minydist = dist; - *ty = guide->position; - snapped = TRUE; - } - break; - - case GIMP_ORIENTATION_VERTICAL: - dist = ABS (guide->position - x); - - if (dist < MIN (GUIDE_EPSILON, minxdist)) - { - minxdist = dist; - *tx = guide->position; - snapped = TRUE; - } - break; - - default: - break; - } - } - - return snapped; -} - -gboolean -gimp_image_snap_rectangle (GimpImage *gimage, - gdouble x1, - gdouble y1, - gdouble x2, - gdouble y2, - gint *tx1, - gint *ty1) -{ - gint nx1, ny1; - gint nx2, ny2; - gboolean snap1, snap2, snap3, snap4; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx1 != NULL, FALSE); - g_return_val_if_fail (ty1 != NULL, FALSE); - - *tx1 = ROUND (x1); - *ty1 = ROUND (y1); - - snap1 = gimp_image_snap_x (gimage, x1, &nx1); - snap2 = gimp_image_snap_x (gimage, x2, &nx2); - snap3 = gimp_image_snap_y (gimage, y1, &ny1); - snap4 = gimp_image_snap_y (gimage, y2, &ny2); - - if (snap1 && snap2) - { - if (ABS (x1 - nx1) > ABS (x2 - nx2)) - snap1 = FALSE; - else - snap2 = FALSE; - } - - if (snap1) - *tx1 = nx1; - else if (snap2) - *tx1 = ROUND (x1 + (nx2 - x2)); - - if (snap3 && snap4) - { - if (ABS (y1 - ny1) > ABS (y2 - ny2)) - snap3 = FALSE; - else - snap4 = FALSE; - } - - if (snap3) - *ty1 = ny1; - else if (snap4) - *ty1 = ROUND (y1 + (ny2 - y2)); - - return (snap1 || snap2 || snap3 || snap4); -} diff --git a/app/core/gimpimage-guides.h b/app/core/gimpimage-guides.h index 2493a2c1f8..dd7f42f8b6 100644 --- a/app/core/gimpimage-guides.h +++ b/app/core/gimpimage-guides.h @@ -45,24 +45,5 @@ GimpGuide * gimp_image_find_guide (GimpImage *gimage, gdouble x, gdouble y); -gboolean gimp_image_snap_x (GimpImage *gimage, - gdouble x, - gint *tx); -gboolean gimp_image_snap_y (GimpImage *gimage, - gdouble y, - gint *ty); -gboolean gimp_image_snap_point (GimpImage *gimage, - gdouble x, - gdouble y, - gint *tx, - gint *ty); -gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gdouble x1, - gdouble y1, - gdouble x2, - gdouble y2, - gint *tx1, - gint *ty1); - #endif /* __GIMP_IMAGE_GUIDES_H__ */ diff --git a/app/core/gimpimage-snap.c b/app/core/gimpimage-snap.c new file mode 100644 index 0000000000..85ae53f26b --- /dev/null +++ b/app/core/gimpimage-snap.c @@ -0,0 +1,383 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "core-types.h" + +#include "gimp.h" +#include "gimpimage.h" +#include "gimpimage-snap.h" + +#include "gimp-intl.h" + + +#define EPSILON 5 + + +/* public functions */ + + +gboolean +gimp_image_snap_x (GimpImage *gimage, + gdouble x, + gint *tx, + gboolean snap_to_guides, + gboolean snap_to_grid) +{ + GList *list; + GimpGuide *guide; + GimpGrid *grid; + gdouble xspacing; + gdouble xoffset; + gint mindist = G_MAXINT; + gint dist; + gint i; + gboolean snapped = FALSE; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (tx != NULL, FALSE); + + if (! snap_to_guides && ! snap_to_grid) + return FALSE; + + *tx = ROUND (x); + + if (x < 0 || x >= gimage->width) + return FALSE; + + if (snap_to_guides && gimage->guides != NULL) + { + for (list = gimage->guides; list; list = g_list_next (list)) + { + guide = (GimpGuide *) list->data; + + if (guide->position < 0) + continue; + + if (guide->orientation == GIMP_ORIENTATION_VERTICAL) + { + dist = ABS (guide->position - x); + + if (dist < MIN (EPSILON, mindist)) + { + mindist = dist; + *tx = guide->position; + snapped = TRUE; + } + } + } + } + + if (snap_to_grid && gimage->grid != NULL) + { + grid = gimp_image_get_grid (gimage); + + g_object_get (G_OBJECT (grid), + "xspacing", &xspacing, + "xoffset", &xoffset, + NULL); + + for (i = xoffset; i <= gimage->width; i += xspacing) + { + if (i < 0) + continue; + + dist = ABS (i - x); + + if (dist < MIN (EPSILON, mindist)) + { + mindist = dist; + *tx = i; + snapped = TRUE; + } + } + } + + return snapped; +} + +gboolean +gimp_image_snap_y (GimpImage *gimage, + gdouble y, + gint *ty, + gboolean snap_to_guides, + gboolean snap_to_grid) +{ + GList *list; + GimpGuide *guide; + GimpGrid *grid; + gdouble yspacing; + gdouble yoffset; + gint mindist = G_MAXINT; + gint dist; + gint i; + gboolean snapped = FALSE; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (ty != NULL, FALSE); + + if (! snap_to_guides && ! snap_to_grid) + return FALSE; + + *ty = ROUND (y); + + if (y < 0 || y >= gimage->height) + return FALSE; + + if (snap_to_guides && gimage->guides != NULL) + { + for (list = gimage->guides; list; list = g_list_next (list)) + { + guide = (GimpGuide *) list->data; + + if (guide->position < 0) + continue; + + if (guide->orientation == GIMP_ORIENTATION_HORIZONTAL) + { + dist = ABS (guide->position - y); + + if (dist < MIN (EPSILON, mindist)) + { + mindist = dist; + *ty = guide->position; + snapped = TRUE; + } + } + } + } + + if (snap_to_grid && gimage->grid != NULL) + { + grid = gimp_image_get_grid (gimage); + + g_object_get (G_OBJECT (grid), + "yspacing", &yspacing, + "yoffset", &yoffset, + NULL); + + for (i = yoffset; i <= gimage->height; i += yspacing) + { + if (i < 0) + continue; + + dist = ABS (i - y); + + if (dist < MIN (EPSILON, mindist)) + { + mindist = dist; + *ty = i; + snapped = TRUE; + } + } + } + + return snapped; +} + +gboolean +gimp_image_snap_point (GimpImage *gimage, + gdouble x, + gdouble y, + gint *tx, + gint *ty, + gboolean snap_to_guides, + gboolean snap_to_grid) +{ + GList *list; + GimpGuide *guide; + GimpGrid *grid; + gdouble xspacing, yspacing; + gdouble xoffset, yoffset; + gint minxdist, minydist; + gint dist; + gint i; + gboolean snapped = FALSE; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (tx != NULL, FALSE); + g_return_val_if_fail (ty != NULL, FALSE); + + if (! snap_to_guides && ! snap_to_grid) + return FALSE; + + *tx = ROUND (x); + *ty = ROUND (y); + + if (x < 0 || x >= gimage->width || + y < 0 || y >= gimage->height) + { + return FALSE; + } + + minxdist = G_MAXINT; + minydist = G_MAXINT; + + if (snap_to_guides && gimage->guides != NULL) + { + for (list = gimage->guides; list; list = g_list_next (list)) + { + guide = (GimpGuide *) list->data; + + if (guide->position < 0) + continue; + + switch (guide->orientation) + { + case GIMP_ORIENTATION_HORIZONTAL: + dist = ABS (guide->position - y); + + if (dist < MIN (EPSILON, minydist)) + { + minydist = dist; + *ty = guide->position; + snapped = TRUE; + } + break; + + case GIMP_ORIENTATION_VERTICAL: + dist = ABS (guide->position - x); + + if (dist < MIN (EPSILON, minxdist)) + { + minxdist = dist; + *tx = guide->position; + snapped = TRUE; + } + break; + + default: + break; + } + } + } + + if (snap_to_grid && gimage->grid != NULL) + { + grid = gimp_image_get_grid (gimage); + + g_object_get (G_OBJECT (grid), + "xspacing", &xspacing, + "yspacing", &yspacing, + "xoffset", &xoffset, + "yoffset", &yoffset, + NULL); + + for (i = xoffset; i <= gimage->width; i += xspacing) + { + if (i < 0) + continue; + + dist = ABS (i - x); + + if (dist < MIN (EPSILON, minxdist)) + { + minxdist = dist; + *tx = i; + snapped = TRUE; + } + } + + for (i = yoffset; i <= gimage->height; i += yspacing) + { + if (i < 0) + continue; + + dist = ABS (i - y); + + if (dist < MIN (EPSILON, minydist)) + { + minydist = dist; + *ty = i; + snapped = TRUE; + } + } + } + + return snapped; +} + +gboolean +gimp_image_snap_rectangle (GimpImage *gimage, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gint *tx1, + gint *ty1, + gboolean snap_to_guides, + gboolean snap_to_grid) +{ + gint nx1, ny1; + gint nx2, ny2; + gboolean snap1, snap2, snap3, snap4; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (tx1 != NULL, FALSE); + g_return_val_if_fail (ty1 != NULL, FALSE); + + if (! snap_to_guides && ! snap_to_grid) + return FALSE; + + *tx1 = ROUND (x1); + *ty1 = ROUND (y1); + + snap1 = gimp_image_snap_x (gimage, x1, &nx1, + snap_to_guides, + snap_to_grid); + snap2 = gimp_image_snap_x (gimage, x2, &nx2, + snap_to_guides, + snap_to_grid); + snap3 = gimp_image_snap_y (gimage, y1, &ny1, + snap_to_guides, + snap_to_grid); + snap4 = gimp_image_snap_y (gimage, y2, &ny2, + snap_to_guides, + snap_to_grid); + + if (snap1 && snap2) + { + if (ABS (x1 - nx1) > ABS (x2 - nx2)) + snap1 = FALSE; + else + snap2 = FALSE; + } + + if (snap1) + *tx1 = nx1; + else if (snap2) + *tx1 = ROUND (x1 + (nx2 - x2)); + + if (snap3 && snap4) + { + if (ABS (y1 - ny1) > ABS (y2 - ny2)) + snap3 = FALSE; + else + snap4 = FALSE; + } + + if (snap3) + *ty1 = ny1; + else if (snap4) + *ty1 = ROUND (y1 + (ny2 - y2)); + + return (snap1 || snap2 || snap3 || snap4); +} diff --git a/app/core/gimpimage-snap.h b/app/core/gimpimage-snap.h new file mode 100644 index 0000000000..c835e1f399 --- /dev/null +++ b/app/core/gimpimage-snap.h @@ -0,0 +1,51 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattisbvf + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_IMAGE_SNAP_H__ +#define __GIMP_IMAGE_SNAP_H__ + + +gboolean gimp_image_snap_x (GimpImage *gimage, + gdouble x, + gint *tx, + gboolean snap_to_guides, + gboolean snap_to_grid); +gboolean gimp_image_snap_y (GimpImage *gimage, + gdouble y, + gint *ty, + gboolean snap_to_guides, + gboolean snap_to_grid); +gboolean gimp_image_snap_point (GimpImage *gimage, + gdouble x, + gdouble y, + gint *tx, + gint *ty, + gboolean snap_to_guides, + gboolean snap_to_grid); +gboolean gimp_image_snap_rectangle (GimpImage *gimage, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gint *tx1, + gint *ty1, + gboolean snap_to_guides, + gboolean snap_to_grid); + + +#endif /* __GIMP_IMAGE_SNAP_H__ */ diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index ea98de4ed3..5d8da6e7fb 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -39,6 +39,7 @@ #include "gimp.h" #include "gimpchannel.h" #include "gimpcontext.h" +#include "gimpgrid.h" #include "gimpimage-colormap.h" #include "gimpimage-guides.h" #include "gimpimage-mask.h" @@ -624,6 +625,93 @@ undo_free_image_qmask (GimpUndo *undo, } +/****************/ +/* Grid Undo */ +/****************/ + +typedef struct _GridUndo GridUndo; + +struct _GridUndo +{ + GimpGrid *grid; +}; + +static gboolean undo_pop_image_grid (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void undo_free_image_grid (GimpUndo *undo, + GimpUndoMode undo_mode); + +gboolean +gimp_image_undo_push_image_grid (GimpImage *gimage, + const gchar *undo_desc, + GimpGrid *grid) +{ + GimpUndo *new; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (grid == NULL || GIMP_IS_GRID (grid), FALSE); + +#ifdef __GNUC__ +#warning FIXME: mark image as dirty when grid save functionality is added +#endif + if ((new = gimp_image_undo_push (gimage, + sizeof (GridUndo), + sizeof (GridUndo), + GIMP_UNDO_IMAGE_GRID, undo_desc, + FALSE, + undo_pop_image_grid, + undo_free_image_grid))) + { + GridUndo *gu; + + gu = new->data; + + if (grid) + gu->grid = g_object_ref (grid); + else + gu->grid = NULL; + + return TRUE; + } + + return FALSE; +} + +static gboolean +undo_pop_image_grid (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + GridUndo *gu; + GimpGrid *tmp; + + gu = (GridUndo *) undo->data; + + tmp = gimp_image_get_grid (undo->gimage); + gimp_image_set_grid (undo->gimage, gu->grid, FALSE); + gu->grid = tmp; + + gimp_image_grid_changed (undo->gimage); + + return TRUE; +} + +static void +undo_free_image_grid (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + GridUndo *gu; + + gu = (GridUndo *) undo->data; + + if (gu->grid) + g_object_unref (gu->grid); + + g_free (gu); +} + + /****************/ /* Guide Undo */ /****************/ diff --git a/app/core/gimpimage-undo-push.h b/app/core/gimpimage-undo-push.h index b5df3aaeaf..b25d7fc2d3 100644 --- a/app/core/gimpimage-undo-push.h +++ b/app/core/gimpimage-undo-push.h @@ -46,6 +46,9 @@ gboolean gimp_image_undo_push_image_resolution (GimpImage *gimage, const gchar *undo_desc); gboolean gimp_image_undo_push_image_qmask (GimpImage *gimage, const gchar *undo_desc); +gboolean gimp_image_undo_push_image_grid (GimpImage *gimage, + const gchar *undo_desc, + GimpGrid *grid); gboolean gimp_image_undo_push_image_guide (GimpImage *gimage, const gchar *undo_desc, GimpGuide *guide); diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index 9c6fe4cc57..e7b9ec682a 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -39,6 +39,7 @@ #include "gimp.h" #include "gimp-parasites.h" #include "gimpcontext.h" +#include "gimpgrid.h" #include "gimpimage.h" #include "gimpimage-colorhash.h" #include "gimpimage-colormap.h" @@ -80,6 +81,7 @@ enum ACTIVE_VECTORS_CHANGED, COMPONENT_VISIBILITY_CHANGED, COMPONENT_ACTIVE_CHANGED, + GRID_CHANGED, MASK_CHANGED, RESOLUTION_CHANGED, UNIT_CHANGED, @@ -259,6 +261,15 @@ gimp_image_class_init (GimpImageClass *klass) G_TYPE_NONE, 1, GIMP_TYPE_CHANNEL_TYPE); + gimp_image_signals[GRID_CHANGED] = + g_signal_new ("grid_changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpImageClass, grid_changed), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gimp_image_signals[MASK_CHANGED] = g_signal_new ("mask_changed", G_TYPE_FROM_CLASS (klass), @@ -400,6 +411,7 @@ gimp_image_class_init (GimpImageClass *klass) viewable_class->get_new_preview = gimp_image_get_new_preview; viewable_class->get_description = gimp_image_get_description; + klass->grid_changed = NULL; klass->mode_changed = NULL; klass->alpha_changed = NULL; klass->floating_selection_changed = NULL; @@ -455,6 +467,8 @@ gimp_image_init (GimpImage *gimage) gimage->guides = NULL; + gimage->grid = NULL; + gimage->layers = gimp_list_new (GIMP_TYPE_LAYER, GIMP_CONTAINER_POLICY_STRONG); gimage->channels = gimp_list_new (GIMP_TYPE_CHANNEL, @@ -573,6 +587,12 @@ gimp_image_finalize (GObject *object) gimage->guides = NULL; } + if (gimage->grid) + { + g_object_unref (gimage->grid); + gimage->grid = NULL; + } + if (gimage->undo_stack) { g_object_unref (gimage->undo_stack); @@ -626,6 +646,8 @@ gimp_image_get_memsize (GimpObject *object) memsize += (g_list_length (gimage->guides) * (sizeof (GList) + sizeof (GimpGuide))); + memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->grid)); + memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->layers)); memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->channels)); memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->vectors)); @@ -3220,3 +3242,37 @@ gimp_image_invalidate_channel_previews (GimpImage *gimage) (GFunc) gimp_viewable_invalidate_preview, NULL); } + + +/* grid */ + +void +gimp_image_grid_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (gimage, gimp_image_signals[GRID_CHANGED], 0); +} + +GimpGrid * +gimp_image_get_grid (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->grid; +} + +void +gimp_image_set_grid (GimpImage *gimage, + GimpGrid *grid, + gboolean push_undo) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (grid == NULL || GIMP_IS_GRID (grid)); + + if (push_undo) + gimp_image_undo_push_image_grid (gimage, _("Grid"), gimage->grid); + + gimage->grid = grid; + gimp_image_grid_changed (gimage); +} diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h index afec41a643..e7b7c8a094 100644 --- a/app/core/gimpimage.h +++ b/app/core/gimpimage.h @@ -124,6 +124,7 @@ struct _GimpImage /* channels */ GList *guides; /* guides */ + GimpGrid *grid; /* grid */ /* Layer/Channel attributes */ GimpContainer *layers; /* the list of layers */ @@ -174,6 +175,7 @@ struct _GimpImageClass GimpChannelType channel); void (* component_active_changed) (GimpImage *gimage, GimpChannelType channel); + void (* grid_changed) (GimpImage *gimage); void (* mask_changed) (GimpImage *gimage); void (* resolution_changed) (GimpImage *gimage); void (* unit_changed) (GimpImage *gimage); @@ -269,6 +271,7 @@ void gimp_image_set_component_visible (GimpImage *gimage, gboolean gimp_image_get_component_visible (const GimpImage *gimage, GimpChannelType type); +void gimp_image_grid_changed (GimpImage *gimage); void gimp_image_mode_changed (GimpImage *gimage); void gimp_image_alpha_changed (GimpImage *gimage); void gimp_image_update (GimpImage *gimage, @@ -483,5 +486,10 @@ GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, void gimp_image_invalidate_layer_previews (GimpImage *gimage); void gimp_image_invalidate_channel_previews (GimpImage *gimage); +GimpGrid * gimp_image_get_grid (GimpImage *gimage); +void gimp_image_set_grid (GimpImage *gimage, + GimpGrid *grid, + gboolean push_undo); + #endif /* __GIMP_IMAGE_H__ */ diff --git a/app/dialogs/grid-dialog.c b/app/dialogs/grid-dialog.c new file mode 100644 index 0000000000..ecaa3aeab3 --- /dev/null +++ b/app/dialogs/grid-dialog.c @@ -0,0 +1,411 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include "config.h" + +#include + +#include "libgimpbase/gimplimits.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "gui-types.h" + +#include "config/gimpconfig-types.h" +#include "config/gimpconfig-utils.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" +#include "core/gimpgrid.h" + +#include "display/gimpdisplay.h" +#include "display/gimpdisplayshell.h" +#include "display/gimpdisplayshell-appearance.h" + +#include "widgets/gimpviewabledialog.h" +#include "widgets/gimppropwidgets.h" + +#include "grid-dialog.h" + +#include "gimp-intl.h" + + +#define GRID_COLOR_SIZE 20 + + +/* local functions */ + + +static void reset_callback (GtkWidget *widget, + GtkWidget *dialog); +static void remove_callback (GtkWidget *widget, + GtkWidget *dialog); +static void cancel_callback (GtkWidget *widget, + GtkWidget *dialog); +static void ok_callback (GtkWidget *widget, + GtkWidget *dialog); + + +/* public function */ + + +GtkWidget * +grid_dialog_new (GimpDisplay *gdisp) +{ + GimpImage *gimage; + GimpDisplayShell *shell; + GimpGrid *grid_orig; + GimpGrid *grid; + + GtkWidget *dialog; + GtkWidget *main_vbox; + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *table; + GtkWidget *type; + GtkWidget *color_button; + GtkWidget *sizeentry; + GtkWidget *show_button; + GtkWidget *snap_button; + + gboolean show_grid; + gboolean snap_to_grid; + + g_return_val_if_fail (GIMP_IS_DISPLAY (gdisp), NULL); + + gimage = GIMP_IMAGE (gdisp->gimage); + shell = GIMP_DISPLAY_SHELL (gdisp->shell); + + grid_orig = gimp_image_get_grid (GIMP_IMAGE (gimage)); + grid = g_object_new (GIMP_TYPE_GRID, NULL); + + g_object_ref (G_OBJECT (grid)); + + /* the dialog */ + dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (gimage), + _("Configure Grid"), "configure_grid", + GIMP_STOCK_GRID, _("Configure Image Grid"), + gimp_standard_help_func, + "dialogs/configure_grid.html", + + GIMP_STOCK_RESET, reset_callback, + NULL, NULL, NULL, FALSE, FALSE, + + GTK_STOCK_REMOVE, remove_callback, + NULL, NULL, NULL, FALSE, FALSE, + + GTK_STOCK_CANCEL, cancel_callback, + NULL, NULL, NULL, FALSE, TRUE, + + GTK_STOCK_OK, ok_callback, + NULL, NULL, NULL, TRUE, FALSE, + + NULL); + + /* the main vbox */ + main_vbox = gtk_vbox_new (FALSE, 4); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), + main_vbox); + + /* misc options */ + vbox = gtk_vbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); + gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0); + + show_button = gtk_check_button_new_with_label (_("Show Grid")); + gtk_box_pack_start (GTK_BOX (vbox), show_button, FALSE, FALSE, 0); + + show_grid = gimp_display_shell_get_show_grid (GIMP_DISPLAY_SHELL (shell)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show_button), + show_grid); + gtk_widget_show (show_button); + + snap_button = gtk_check_button_new_with_label (_("Snap to Grid")); + gtk_box_pack_start (GTK_BOX (vbox), snap_button, FALSE, FALSE, 0); + + snap_to_grid = gimp_display_shell_get_snap_to_grid (GIMP_DISPLAY_SHELL (shell)); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (snap_button), + snap_to_grid); + gtk_widget_show (snap_button); + gtk_widget_show (vbox); + + /* the appearence frame */ + frame = gtk_frame_new (_("Appearence")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + table = gtk_table_new (3, 2, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table), 2); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_container_add (GTK_CONTAINER (frame), table); + + type = gimp_prop_enum_option_menu_new (G_OBJECT (grid), "type", + GIMP_GRID_TYPE_INTERSECTION, + GIMP_GRID_TYPE_SOLID); + gimp_table_attach_aligned (GTK_TABLE (table), 0, 0, + _("Line Style:"), 1.0, 0.5, + type, 1, TRUE); + + color_button = gimp_prop_color_button_new (G_OBJECT (grid), "fgcolor", + _("Grid Foreground Color"), + GRID_COLOR_SIZE, GRID_COLOR_SIZE, + GIMP_COLOR_AREA_FLAT); + gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, + _("Foreground Color:"), 1.0, 0.5, + color_button, 1, TRUE); + + color_button = gimp_prop_color_button_new (G_OBJECT (grid), "bgcolor", + _("Grid Background Color"), + GRID_COLOR_SIZE, GRID_COLOR_SIZE, + GIMP_COLOR_AREA_FLAT); + gimp_table_attach_aligned (GTK_TABLE (table), 0, 2, + _("Background Color:"), 1.0, 0.5, + color_button, 1, TRUE); + + gtk_widget_show (table); + + /* the spacing frame */ + frame = gtk_frame_new (_("Spacing")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 2); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + sizeentry = gimp_prop_coordinates_new (G_OBJECT (grid), + "xspacing", + "yspacing", + "spacing-unit", + "%a", + GIMP_SIZE_ENTRY_UPDATE_SIZE, + gimage->xresolution, + gimage->yresolution, + TRUE); + + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 0, 1.0, GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 1, 1.0, GIMP_MAX_IMAGE_SIZE); + + gtk_table_set_col_spacings (GTK_TABLE (sizeentry), 2); + gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2); + + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Width"), 0, 1, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Height"), 0, 2, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Pixels"), 1, 4, 0.0); + + gtk_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0); + gtk_widget_show (sizeentry); + + gtk_widget_show (hbox); + + /* the offset frame */ + frame = gtk_frame_new (_("Offset")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 2); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + sizeentry = gimp_prop_coordinates_new (G_OBJECT (grid), + "xoffset", + "yoffset", + "offset-unit", + "%a", + GIMP_SIZE_ENTRY_UPDATE_SIZE, + gimage->xresolution, + gimage->yresolution, + TRUE); + + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 0, - GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 1, - GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + + gtk_table_set_col_spacings (GTK_TABLE (sizeentry), 2); + gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2); + + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Width"), 0, 1, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Height"), 0, 2, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Pixels"), 1, 4, 0.0); + + gtk_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0); + gtk_widget_show (sizeentry); + + gtk_widget_show (hbox); + + if (grid_orig) + { + gimp_config_copy_properties (G_OBJECT (grid_orig), G_OBJECT (grid)); + } + else + { + gimp_config_reset_properties (G_OBJECT (grid)); + g_object_set (G_OBJECT (grid), + "spacing-unit", gimage->unit, + NULL); + g_object_set (G_OBJECT (grid), + "offset-unit", gimage->unit, + NULL); + } + + gtk_widget_show (main_vbox); + + g_object_set_data (G_OBJECT (dialog), "gimage", gimage); + g_object_set_data (G_OBJECT (dialog), "shell", shell); + + g_object_set_data (G_OBJECT (dialog), "grid", grid); + + g_object_set_data (G_OBJECT (dialog), "show-button", show_button); + g_object_set_data (G_OBJECT (dialog), "snap-button", snap_button); + + return dialog; +} + + +/* local functions */ + + +static void +reset_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpImage *gimage; + GimpDisplayShell *shell; + GimpGrid *grid_orig; + GimpGrid *grid; + GimpUnit unit_orig; + GtkWidget *show_button; + GtkWidget *snap_button; + gboolean show_grid; + gboolean snap_to_grid; + + gimage = g_object_get_data (G_OBJECT (dialog), "gimage"); + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + shell = g_object_get_data (G_OBJECT (dialog), "shell"); + show_button = g_object_get_data (G_OBJECT (dialog), "show-button"); + snap_button = g_object_get_data (G_OBJECT (dialog), "snap-button"); + + grid_orig = gimp_image_get_grid (GIMP_IMAGE (gimage)); + unit_orig = gimp_image_get_unit (GIMP_IMAGE (gimage)); + + if (grid_orig) + { + gimp_config_copy_properties (G_OBJECT (grid_orig), + G_OBJECT (grid)); + } + else + { + g_object_freeze_notify (G_OBJECT (grid)); + gimp_config_reset_properties (G_OBJECT (grid)); + + g_object_set (G_OBJECT (grid), + "spacing-unit", unit_orig, + NULL); + g_object_set (G_OBJECT (grid), + "offset-unit", unit_orig, + NULL); + + g_object_thaw_notify (G_OBJECT (grid)); + } + + show_grid = gimp_display_shell_get_show_grid (GIMP_DISPLAY_SHELL (shell)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show_button), + show_grid); + + snap_to_grid = gimp_display_shell_get_snap_to_grid (GIMP_DISPLAY_SHELL (shell)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (snap_button), + snap_to_grid); +} + +static void +remove_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpImage *gimage; + GimpGrid *grid; + + gimage = g_object_get_data (G_OBJECT (dialog), "gimage"); + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + + gimp_image_set_grid (gimage, NULL, TRUE); + g_object_unref (G_OBJECT (grid)); + gtk_widget_destroy (dialog); +} + + +static void +cancel_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpGrid *grid; + + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + + g_object_unref (G_OBJECT (grid)); + gtk_widget_destroy (dialog); +} + +static void +ok_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpImage *gimage; + GimpDisplayShell *shell; + GimpGrid *grid; + GimpGrid *grid_orig; + GtkWidget *show_button; + GtkWidget *snap_button; + gboolean show_grid; + gboolean snap_to_grid; + + gimage = g_object_get_data (G_OBJECT (dialog), "gimage"); + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + shell = g_object_get_data (G_OBJECT (dialog), "shell"); + show_button = g_object_get_data (G_OBJECT (dialog), "show-button"); + snap_button = g_object_get_data (G_OBJECT (dialog), "snap-button"); + + grid_orig = gimp_image_get_grid (GIMP_IMAGE (gimage)); + + if (grid_orig == NULL || gimp_config_diff (G_OBJECT (grid_orig), G_OBJECT (grid), 0)) + gimp_image_set_grid (GIMP_IMAGE (gimage), grid, TRUE); + else + g_object_unref (G_OBJECT (grid)); + + show_grid = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_button)); + gimp_display_shell_set_show_grid (GIMP_DISPLAY_SHELL (shell), show_grid); + + snap_to_grid = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (snap_button)); + gimp_display_shell_set_snap_to_grid (GIMP_DISPLAY_SHELL (shell), snap_to_grid); + + gtk_widget_destroy (dialog); +} diff --git a/app/dialogs/grid-dialog.h b/app/dialogs/grid-dialog.h new file mode 100644 index 0000000000..11f0803481 --- /dev/null +++ b/app/dialogs/grid-dialog.h @@ -0,0 +1,24 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GRID_DIALOG_H__ +#define __GRID_DIALOG_H__ + +GtkWidget * grid_dialog_new (GimpDisplay *gdisp); + +#endif /* __GRID_DIALOG_H__ */ diff --git a/app/display/gimpdisplayshell-appearance.c b/app/display/gimpdisplayshell-appearance.c index f3c73f0964..f9197d55ae 100644 --- a/app/display/gimpdisplayshell-appearance.c +++ b/app/display/gimpdisplayshell-appearance.c @@ -207,6 +207,63 @@ gimp_display_shell_get_show_layer (GimpDisplayShell *shell) return GET_VISIBILITY (shell)->active_layer; } +void +gimp_display_shell_set_show_grid (GimpDisplayShell *shell, + gboolean show) +{ + GimpDisplayShellVisibility *visibility; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + visibility = GET_VISIBILITY (shell); + + if (show != visibility->grid) + { + visibility->grid = show ? TRUE : FALSE; + + if (shell->gdisp->gimage->grid) + gimp_display_shell_expose_full (shell); + + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->menubar_factory), + "/View/Show Grid", show); + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->popup_factory), + "/View/Show Grid", show); + } +} + +gboolean +gimp_display_shell_get_show_grid (GimpDisplayShell *shell) +{ + g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE); + + return GET_VISIBILITY (shell)->grid; +} + +void +gimp_display_shell_set_snap_to_grid (GimpDisplayShell *shell, + gboolean snap) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + if (snap != shell->snap_to_grid) + { + shell->snap_to_grid = snap ? TRUE : FALSE; + + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->menubar_factory), + "/View/Snap to Grid", snap); + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->popup_factory), + "/View/Snap to Grid", snap); + } +} + +gboolean +gimp_display_shell_get_snap_to_grid (GimpDisplayShell *shell) +{ + g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE); + + return shell->snap_to_grid; +} + void gimp_display_shell_set_show_guides (GimpDisplayShell *shell, gboolean show) diff --git a/app/display/gimpdisplayshell-appearance.h b/app/display/gimpdisplayshell-appearance.h index cbc41b342b..74b46949b3 100644 --- a/app/display/gimpdisplayshell-appearance.h +++ b/app/display/gimpdisplayshell-appearance.h @@ -36,6 +36,14 @@ void gimp_display_shell_set_show_layer (GimpDisplayShell *shell, gboolean show); gboolean gimp_display_shell_get_show_layer (GimpDisplayShell *shell); +void gimp_display_shell_set_show_grid (GimpDisplayShell *shell, + gboolean show); +gboolean gimp_display_shell_get_show_grid (GimpDisplayShell *shell); + +void gimp_display_shell_set_snap_to_grid (GimpDisplayShell *shell, + gboolean snap); +gboolean gimp_display_shell_get_snap_to_grid (GimpDisplayShell *shell); + void gimp_display_shell_set_show_guides (GimpDisplayShell *shell, gboolean show); gboolean gimp_display_shell_get_show_guides (GimpDisplayShell *shell); diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c index ac7bab0c6e..738801d330 100644 --- a/app/display/gimpdisplayshell-callbacks.c +++ b/app/display/gimpdisplayshell-callbacks.c @@ -211,6 +211,7 @@ gimp_display_shell_events (GtkWidget *widget, gimp_display_shell_set_show_selection (shell, visibility.selection); gimp_display_shell_set_show_layer (shell, visibility.active_layer); gimp_display_shell_set_show_guides (shell, visibility.guides); + gimp_display_shell_set_show_grid (shell, visibility.grid); gimp_display_shell_set_show_menubar (shell, visibility.menubar); gimp_display_shell_set_show_rulers (shell, visibility.rulers); gimp_display_shell_set_show_scrollbars (shell, visibility.scrollbars); @@ -335,6 +336,9 @@ gimp_display_shell_canvas_expose (GtkWidget *widget, /* draw the guides */ gimp_display_shell_draw_guides (shell); + /* draw the grid */ + gimp_display_shell_draw_grid (shell); + /* and the cursor (if we have a software cursor) */ if (shell->have_cursor) gimp_display_shell_draw_cursor (shell); diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c index 786961007d..ae1f9ae179 100644 --- a/app/display/gimpdisplayshell-draw.c +++ b/app/display/gimpdisplayshell-draw.c @@ -36,9 +36,10 @@ #include "core/gimp.h" #include "core/gimpbuffer.h" #include "core/gimpcontext.h" +#include "core/gimpgrid.h" #include "core/gimpimage.h" -#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" +#include "core/gimpimage-snap.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" #include "core/gimpmarshal.h" @@ -208,6 +209,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->proximity = FALSE; shell->snap_to_guides = TRUE; + shell->snap_to_grid = TRUE; shell->select = NULL; @@ -254,6 +256,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->info_dialog = NULL; shell->scale_dialog = NULL; shell->nav_popup = NULL; + shell->grid_dialog = NULL; shell->filters = NULL; shell->filters_dialog = NULL; @@ -266,6 +269,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->visibility.selection = TRUE; shell->visibility.active_layer = TRUE; shell->visibility.guides = TRUE; + shell->visibility.grid = TRUE; shell->visibility.menubar = FALSE; shell->visibility.rulers = TRUE; shell->visibility.scrollbars = TRUE; @@ -274,6 +278,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->fullscreen_visibility.selection = TRUE; shell->fullscreen_visibility.active_layer = TRUE; shell->fullscreen_visibility.guides = TRUE; + shell->fullscreen_visibility.grid = TRUE; shell->fullscreen_visibility.menubar = FALSE; shell->fullscreen_visibility.rulers = FALSE; shell->fullscreen_visibility.scrollbars = FALSE; @@ -396,6 +401,12 @@ gimp_display_shell_destroy (GtkObject *object) shell->nav_popup = NULL; } + if (shell->grid_dialog) + { + gtk_widget_destroy (shell->grid_dialog); + shell->grid_dialog = NULL; + } + shell->gdisp = NULL; GTK_OBJECT_CLASS (parent_class)->destroy (object); @@ -967,6 +978,9 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, gint snap_width, gint snap_height) { + gboolean snap_to_guides = FALSE; + gboolean snap_to_grid = FALSE; + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (coords != NULL); g_return_if_fail (snapped_coords != NULL); @@ -976,6 +990,18 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, if (gimp_display_shell_get_show_guides (shell) && shell->snap_to_guides && shell->gdisp->gimage->guides) + { + snap_to_guides = TRUE; + } + + if (gimp_display_shell_get_show_grid (shell) && + gimp_display_shell_get_snap_to_grid (shell) && + shell->gdisp->gimage->grid) + { + snap_to_grid = TRUE; + } + + if (snap_to_guides || snap_to_grid) { gboolean snapped; gint tx, ty; @@ -990,7 +1016,9 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, coords->y + snap_offset_y + snap_height, &tx, - &ty); + &ty, + snap_to_guides, + snap_to_grid); } else { @@ -998,7 +1026,9 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, coords->x + snap_offset_x, coords->y + snap_offset_y, &tx, - &ty); + &ty, + snap_to_guides, + snap_to_grid); } if (snapped) @@ -1328,6 +1358,131 @@ gimp_display_shell_draw_guides (GimpDisplayShell *shell) } } +void +gimp_display_shell_draw_grid (GimpDisplayShell *shell) +{ + GdkGC *gc; + GdkGCValues values; + GdkColor fg, bg; + + GimpGrid *grid; + gdouble xspacing, yspacing; + gdouble xoffset, yoffset; + GimpRGB *fgcolor, *bgcolor; + GimpGridType type; + + gint x1, x2; + gint y1, y2; + gint x, y; + gint x_real, y_real; + const gint length = 2; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + grid = GIMP_GRID (shell->gdisp->gimage->grid); + + if (grid == NULL) + return; + + if (gimp_display_shell_get_show_grid (shell)) + { + g_object_get (G_OBJECT (grid), + "xspacing", &xspacing, + "yspacing", &yspacing, + "xoffset", &xoffset, + "yoffset", &yoffset, + "fgcolor", &fgcolor, + "bgcolor", &bgcolor, + "type", &type, + NULL); + + switch (type) + { + case GIMP_GRID_TYPE_INTERSECTION: + values.line_style = GDK_LINE_SOLID; + break; + + case GIMP_GRID_TYPE_ON_OFF_DASH: + values.line_style = GDK_LINE_ON_OFF_DASH; + break; + + case GIMP_GRID_TYPE_DOUBLE_DASH: + values.line_style = GDK_LINE_DOUBLE_DASH; + break; + + case GIMP_GRID_TYPE_SOLID: + values.line_style = GDK_LINE_SOLID; + break; + + default: + g_assert_not_reached (); + } + + values.join_style = GDK_JOIN_MITER; + + gc = gdk_gc_new_with_values (shell->canvas->window, &values, + GDK_GC_LINE_STYLE | GDK_GC_JOIN_STYLE); + + gimp_rgb_get_gdk_color (fgcolor, &fg); + gimp_rgb_get_gdk_color (bgcolor, &bg); + + gdk_gc_set_rgb_fg_color (gc, &fg); + gdk_gc_set_rgb_bg_color (gc, &bg); + + gimp_display_shell_transform_xy (shell, 0, 0, &x1, &y1, FALSE); + gimp_display_shell_transform_xy (shell, + shell->gdisp->gimage->width, + shell->gdisp->gimage->height, + &x2, &y2, FALSE); + + switch (type) + { + case GIMP_GRID_TYPE_INTERSECTION: + for (x = xoffset; x <= shell->gdisp->gimage->width; x += xspacing) + { + for (y = yoffset; y <= shell->gdisp->gimage->height; y += yspacing) + { + gimp_display_shell_transform_xy (shell, x, y, &x_real, &y_real, FALSE); + if (x_real >= x1 && x_real < x2) + { + gdk_draw_line (shell->canvas->window, gc, + x_real, CLAMP (y_real - length, y1, y2 - 1), + x_real, CLAMP (y_real + length, y1, y2 - 1)); + } + if (y_real >= y1 && y_real < y2) + { + gdk_draw_line (shell->canvas->window, gc, + CLAMP (x_real - length, x1, x2 - 1), y_real, + CLAMP (x_real + length, x1, x2 - 1), y_real); + } + } + } + break; + + case GIMP_GRID_TYPE_ON_OFF_DASH: + case GIMP_GRID_TYPE_DOUBLE_DASH: + case GIMP_GRID_TYPE_SOLID: + for (x = xoffset; x < shell->gdisp->gimage->width; x += xspacing) + { + gimp_display_shell_transform_xy (shell, x, 0, &x_real, &y_real, FALSE); + if (x_real > x1) + gdk_draw_line (shell->canvas->window, gc, x_real, y1, x_real, y2 - 1); + } + + for (y = yoffset; y < shell->gdisp->gimage->height; y += yspacing) + { + gimp_display_shell_transform_xy (shell, 0, y, &x_real, &y_real, FALSE); + if (y_real > y1) + gdk_draw_line (shell->canvas->window, gc, x1, y_real, x2 - 1, y_real); + } + break; + + default: + g_assert_not_reached (); + } + } +} + void gimp_display_shell_draw_area (GimpDisplayShell *shell, gint x, diff --git a/app/display/gimpdisplayshell-draw.h b/app/display/gimpdisplayshell-draw.h index 99aa213a3d..8d332af9aa 100644 --- a/app/display/gimpdisplayshell-draw.h +++ b/app/display/gimpdisplayshell-draw.h @@ -34,6 +34,7 @@ struct _GimpDisplayShellVisibility gboolean selection; gboolean active_layer; gboolean guides; + gboolean grid; gboolean menubar; gboolean rulers; @@ -107,6 +108,7 @@ struct _GimpDisplayShell gboolean proximity; /* is a device in proximity */ gboolean snap_to_guides; /* should the guides be snapped to? */ + gboolean snap_to_grid; /* should the grid be snapped to? */ Selection *select; /* Selection object */ @@ -155,6 +157,7 @@ struct _GimpDisplayShell InfoDialog *info_dialog; /* image information dialog */ GtkWidget *scale_dialog; /* scale (zoom) dialog */ GtkWidget *nav_popup; /* navigation popup */ + GtkWidget *grid_dialog; /* grid configuration dialog */ GList *filters; /* color display conversion stuff */ GtkWidget *filters_dialog; /* color display filter dialog */ @@ -233,6 +236,8 @@ void gimp_display_shell_draw_guide (GimpDisplayShell *shell, gboolean active); void gimp_display_shell_draw_guides (GimpDisplayShell *shell); +void gimp_display_shell_draw_grid (GimpDisplayShell *shell); + void gimp_display_shell_update_icon (GimpDisplayShell *shell); void gimp_display_shell_shrink_wrap (GimpDisplayShell *shell); diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c index 35ea5678ca..b536d3f397 100644 --- a/app/display/gimpdisplayshell-handlers.c +++ b/app/display/gimpdisplayshell-handlers.c @@ -53,6 +53,8 @@ static void gimp_display_shell_undo_event_handler (GimpImage *g GimpUndoEvent event, GimpUndo *undo, GimpDisplayShell *shell); +static void gimp_display_shell_grid_changed_handler (GimpImage *gimage, + GimpDisplayShell *shell); static void gimp_display_shell_name_changed_handler (GimpImage *gimage, GimpDisplayShell *shell); static void gimp_display_shell_selection_control_handler (GimpImage *gimage, @@ -122,6 +124,9 @@ gimp_display_shell_connect (GimpDisplayShell *shell) g_signal_connect (gimage, "undo_event", G_CALLBACK (gimp_display_shell_undo_event_handler), shell); + g_signal_connect (gimage, "grid_changed", + G_CALLBACK (gimp_display_shell_grid_changed_handler), + shell); g_signal_connect (gimage, "name_changed", G_CALLBACK (gimp_display_shell_name_changed_handler), shell); @@ -256,6 +261,9 @@ gimp_display_shell_disconnect (GimpDisplayShell *shell) g_signal_handlers_disconnect_by_func (gimage, gimp_display_shell_name_changed_handler, shell); + g_signal_handlers_disconnect_by_func (gimage, + gimp_display_shell_grid_changed_handler, + shell); g_signal_handlers_disconnect_by_func (gimage, gimp_display_shell_undo_event_handler, shell); @@ -283,6 +291,16 @@ gimp_display_shell_undo_event_handler (GimpImage *gimage, gimp_display_shell_update_title (shell); } +static void +gimp_display_shell_grid_changed_handler (GimpImage *gimage, + GimpDisplayShell *shell) +{ + gimp_display_shell_expose_full (shell); + + /* update item factory */ + gimp_display_flush (shell->gdisp); +} + static void gimp_display_shell_name_changed_handler (GimpImage *gimage, GimpDisplayShell *shell) diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index 786961007d..ae1f9ae179 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -36,9 +36,10 @@ #include "core/gimp.h" #include "core/gimpbuffer.h" #include "core/gimpcontext.h" +#include "core/gimpgrid.h" #include "core/gimpimage.h" -#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" +#include "core/gimpimage-snap.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" #include "core/gimpmarshal.h" @@ -208,6 +209,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->proximity = FALSE; shell->snap_to_guides = TRUE; + shell->snap_to_grid = TRUE; shell->select = NULL; @@ -254,6 +256,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->info_dialog = NULL; shell->scale_dialog = NULL; shell->nav_popup = NULL; + shell->grid_dialog = NULL; shell->filters = NULL; shell->filters_dialog = NULL; @@ -266,6 +269,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->visibility.selection = TRUE; shell->visibility.active_layer = TRUE; shell->visibility.guides = TRUE; + shell->visibility.grid = TRUE; shell->visibility.menubar = FALSE; shell->visibility.rulers = TRUE; shell->visibility.scrollbars = TRUE; @@ -274,6 +278,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->fullscreen_visibility.selection = TRUE; shell->fullscreen_visibility.active_layer = TRUE; shell->fullscreen_visibility.guides = TRUE; + shell->fullscreen_visibility.grid = TRUE; shell->fullscreen_visibility.menubar = FALSE; shell->fullscreen_visibility.rulers = FALSE; shell->fullscreen_visibility.scrollbars = FALSE; @@ -396,6 +401,12 @@ gimp_display_shell_destroy (GtkObject *object) shell->nav_popup = NULL; } + if (shell->grid_dialog) + { + gtk_widget_destroy (shell->grid_dialog); + shell->grid_dialog = NULL; + } + shell->gdisp = NULL; GTK_OBJECT_CLASS (parent_class)->destroy (object); @@ -967,6 +978,9 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, gint snap_width, gint snap_height) { + gboolean snap_to_guides = FALSE; + gboolean snap_to_grid = FALSE; + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (coords != NULL); g_return_if_fail (snapped_coords != NULL); @@ -976,6 +990,18 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, if (gimp_display_shell_get_show_guides (shell) && shell->snap_to_guides && shell->gdisp->gimage->guides) + { + snap_to_guides = TRUE; + } + + if (gimp_display_shell_get_show_grid (shell) && + gimp_display_shell_get_snap_to_grid (shell) && + shell->gdisp->gimage->grid) + { + snap_to_grid = TRUE; + } + + if (snap_to_guides || snap_to_grid) { gboolean snapped; gint tx, ty; @@ -990,7 +1016,9 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, coords->y + snap_offset_y + snap_height, &tx, - &ty); + &ty, + snap_to_guides, + snap_to_grid); } else { @@ -998,7 +1026,9 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, coords->x + snap_offset_x, coords->y + snap_offset_y, &tx, - &ty); + &ty, + snap_to_guides, + snap_to_grid); } if (snapped) @@ -1328,6 +1358,131 @@ gimp_display_shell_draw_guides (GimpDisplayShell *shell) } } +void +gimp_display_shell_draw_grid (GimpDisplayShell *shell) +{ + GdkGC *gc; + GdkGCValues values; + GdkColor fg, bg; + + GimpGrid *grid; + gdouble xspacing, yspacing; + gdouble xoffset, yoffset; + GimpRGB *fgcolor, *bgcolor; + GimpGridType type; + + gint x1, x2; + gint y1, y2; + gint x, y; + gint x_real, y_real; + const gint length = 2; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + grid = GIMP_GRID (shell->gdisp->gimage->grid); + + if (grid == NULL) + return; + + if (gimp_display_shell_get_show_grid (shell)) + { + g_object_get (G_OBJECT (grid), + "xspacing", &xspacing, + "yspacing", &yspacing, + "xoffset", &xoffset, + "yoffset", &yoffset, + "fgcolor", &fgcolor, + "bgcolor", &bgcolor, + "type", &type, + NULL); + + switch (type) + { + case GIMP_GRID_TYPE_INTERSECTION: + values.line_style = GDK_LINE_SOLID; + break; + + case GIMP_GRID_TYPE_ON_OFF_DASH: + values.line_style = GDK_LINE_ON_OFF_DASH; + break; + + case GIMP_GRID_TYPE_DOUBLE_DASH: + values.line_style = GDK_LINE_DOUBLE_DASH; + break; + + case GIMP_GRID_TYPE_SOLID: + values.line_style = GDK_LINE_SOLID; + break; + + default: + g_assert_not_reached (); + } + + values.join_style = GDK_JOIN_MITER; + + gc = gdk_gc_new_with_values (shell->canvas->window, &values, + GDK_GC_LINE_STYLE | GDK_GC_JOIN_STYLE); + + gimp_rgb_get_gdk_color (fgcolor, &fg); + gimp_rgb_get_gdk_color (bgcolor, &bg); + + gdk_gc_set_rgb_fg_color (gc, &fg); + gdk_gc_set_rgb_bg_color (gc, &bg); + + gimp_display_shell_transform_xy (shell, 0, 0, &x1, &y1, FALSE); + gimp_display_shell_transform_xy (shell, + shell->gdisp->gimage->width, + shell->gdisp->gimage->height, + &x2, &y2, FALSE); + + switch (type) + { + case GIMP_GRID_TYPE_INTERSECTION: + for (x = xoffset; x <= shell->gdisp->gimage->width; x += xspacing) + { + for (y = yoffset; y <= shell->gdisp->gimage->height; y += yspacing) + { + gimp_display_shell_transform_xy (shell, x, y, &x_real, &y_real, FALSE); + if (x_real >= x1 && x_real < x2) + { + gdk_draw_line (shell->canvas->window, gc, + x_real, CLAMP (y_real - length, y1, y2 - 1), + x_real, CLAMP (y_real + length, y1, y2 - 1)); + } + if (y_real >= y1 && y_real < y2) + { + gdk_draw_line (shell->canvas->window, gc, + CLAMP (x_real - length, x1, x2 - 1), y_real, + CLAMP (x_real + length, x1, x2 - 1), y_real); + } + } + } + break; + + case GIMP_GRID_TYPE_ON_OFF_DASH: + case GIMP_GRID_TYPE_DOUBLE_DASH: + case GIMP_GRID_TYPE_SOLID: + for (x = xoffset; x < shell->gdisp->gimage->width; x += xspacing) + { + gimp_display_shell_transform_xy (shell, x, 0, &x_real, &y_real, FALSE); + if (x_real > x1) + gdk_draw_line (shell->canvas->window, gc, x_real, y1, x_real, y2 - 1); + } + + for (y = yoffset; y < shell->gdisp->gimage->height; y += yspacing) + { + gimp_display_shell_transform_xy (shell, 0, y, &x_real, &y_real, FALSE); + if (y_real > y1) + gdk_draw_line (shell->canvas->window, gc, x1, y_real, x2 - 1, y_real); + } + break; + + default: + g_assert_not_reached (); + } + } +} + void gimp_display_shell_draw_area (GimpDisplayShell *shell, gint x, diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h index 99aa213a3d..8d332af9aa 100644 --- a/app/display/gimpdisplayshell.h +++ b/app/display/gimpdisplayshell.h @@ -34,6 +34,7 @@ struct _GimpDisplayShellVisibility gboolean selection; gboolean active_layer; gboolean guides; + gboolean grid; gboolean menubar; gboolean rulers; @@ -107,6 +108,7 @@ struct _GimpDisplayShell gboolean proximity; /* is a device in proximity */ gboolean snap_to_guides; /* should the guides be snapped to? */ + gboolean snap_to_grid; /* should the grid be snapped to? */ Selection *select; /* Selection object */ @@ -155,6 +157,7 @@ struct _GimpDisplayShell InfoDialog *info_dialog; /* image information dialog */ GtkWidget *scale_dialog; /* scale (zoom) dialog */ GtkWidget *nav_popup; /* navigation popup */ + GtkWidget *grid_dialog; /* grid configuration dialog */ GList *filters; /* color display conversion stuff */ GtkWidget *filters_dialog; /* color display filter dialog */ @@ -233,6 +236,8 @@ void gimp_display_shell_draw_guide (GimpDisplayShell *shell, gboolean active); void gimp_display_shell_draw_guides (GimpDisplayShell *shell); +void gimp_display_shell_draw_grid (GimpDisplayShell *shell); + void gimp_display_shell_update_icon (GimpDisplayShell *shell); void gimp_display_shell_shrink_wrap (GimpDisplayShell *shell); diff --git a/app/gui/Makefile.am b/app/gui/Makefile.am index b633185872..4cc1fc00f9 100644 --- a/app/gui/Makefile.am +++ b/app/gui/Makefile.am @@ -29,6 +29,8 @@ dialogs_sources = \ font-select.h \ gradient-select.c \ gradient-select.h \ + grid-dialog.h \ + grid-dialog.c \ info-dialog.c \ info-dialog.h \ info-window.c \ diff --git a/app/gui/grid-dialog.c b/app/gui/grid-dialog.c new file mode 100644 index 0000000000..ecaa3aeab3 --- /dev/null +++ b/app/gui/grid-dialog.c @@ -0,0 +1,411 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include "config.h" + +#include + +#include "libgimpbase/gimplimits.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "gui-types.h" + +#include "config/gimpconfig-types.h" +#include "config/gimpconfig-utils.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" +#include "core/gimpgrid.h" + +#include "display/gimpdisplay.h" +#include "display/gimpdisplayshell.h" +#include "display/gimpdisplayshell-appearance.h" + +#include "widgets/gimpviewabledialog.h" +#include "widgets/gimppropwidgets.h" + +#include "grid-dialog.h" + +#include "gimp-intl.h" + + +#define GRID_COLOR_SIZE 20 + + +/* local functions */ + + +static void reset_callback (GtkWidget *widget, + GtkWidget *dialog); +static void remove_callback (GtkWidget *widget, + GtkWidget *dialog); +static void cancel_callback (GtkWidget *widget, + GtkWidget *dialog); +static void ok_callback (GtkWidget *widget, + GtkWidget *dialog); + + +/* public function */ + + +GtkWidget * +grid_dialog_new (GimpDisplay *gdisp) +{ + GimpImage *gimage; + GimpDisplayShell *shell; + GimpGrid *grid_orig; + GimpGrid *grid; + + GtkWidget *dialog; + GtkWidget *main_vbox; + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *table; + GtkWidget *type; + GtkWidget *color_button; + GtkWidget *sizeentry; + GtkWidget *show_button; + GtkWidget *snap_button; + + gboolean show_grid; + gboolean snap_to_grid; + + g_return_val_if_fail (GIMP_IS_DISPLAY (gdisp), NULL); + + gimage = GIMP_IMAGE (gdisp->gimage); + shell = GIMP_DISPLAY_SHELL (gdisp->shell); + + grid_orig = gimp_image_get_grid (GIMP_IMAGE (gimage)); + grid = g_object_new (GIMP_TYPE_GRID, NULL); + + g_object_ref (G_OBJECT (grid)); + + /* the dialog */ + dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (gimage), + _("Configure Grid"), "configure_grid", + GIMP_STOCK_GRID, _("Configure Image Grid"), + gimp_standard_help_func, + "dialogs/configure_grid.html", + + GIMP_STOCK_RESET, reset_callback, + NULL, NULL, NULL, FALSE, FALSE, + + GTK_STOCK_REMOVE, remove_callback, + NULL, NULL, NULL, FALSE, FALSE, + + GTK_STOCK_CANCEL, cancel_callback, + NULL, NULL, NULL, FALSE, TRUE, + + GTK_STOCK_OK, ok_callback, + NULL, NULL, NULL, TRUE, FALSE, + + NULL); + + /* the main vbox */ + main_vbox = gtk_vbox_new (FALSE, 4); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), + main_vbox); + + /* misc options */ + vbox = gtk_vbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); + gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0); + + show_button = gtk_check_button_new_with_label (_("Show Grid")); + gtk_box_pack_start (GTK_BOX (vbox), show_button, FALSE, FALSE, 0); + + show_grid = gimp_display_shell_get_show_grid (GIMP_DISPLAY_SHELL (shell)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show_button), + show_grid); + gtk_widget_show (show_button); + + snap_button = gtk_check_button_new_with_label (_("Snap to Grid")); + gtk_box_pack_start (GTK_BOX (vbox), snap_button, FALSE, FALSE, 0); + + snap_to_grid = gimp_display_shell_get_snap_to_grid (GIMP_DISPLAY_SHELL (shell)); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (snap_button), + snap_to_grid); + gtk_widget_show (snap_button); + gtk_widget_show (vbox); + + /* the appearence frame */ + frame = gtk_frame_new (_("Appearence")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + table = gtk_table_new (3, 2, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table), 2); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_container_add (GTK_CONTAINER (frame), table); + + type = gimp_prop_enum_option_menu_new (G_OBJECT (grid), "type", + GIMP_GRID_TYPE_INTERSECTION, + GIMP_GRID_TYPE_SOLID); + gimp_table_attach_aligned (GTK_TABLE (table), 0, 0, + _("Line Style:"), 1.0, 0.5, + type, 1, TRUE); + + color_button = gimp_prop_color_button_new (G_OBJECT (grid), "fgcolor", + _("Grid Foreground Color"), + GRID_COLOR_SIZE, GRID_COLOR_SIZE, + GIMP_COLOR_AREA_FLAT); + gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, + _("Foreground Color:"), 1.0, 0.5, + color_button, 1, TRUE); + + color_button = gimp_prop_color_button_new (G_OBJECT (grid), "bgcolor", + _("Grid Background Color"), + GRID_COLOR_SIZE, GRID_COLOR_SIZE, + GIMP_COLOR_AREA_FLAT); + gimp_table_attach_aligned (GTK_TABLE (table), 0, 2, + _("Background Color:"), 1.0, 0.5, + color_button, 1, TRUE); + + gtk_widget_show (table); + + /* the spacing frame */ + frame = gtk_frame_new (_("Spacing")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 2); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + sizeentry = gimp_prop_coordinates_new (G_OBJECT (grid), + "xspacing", + "yspacing", + "spacing-unit", + "%a", + GIMP_SIZE_ENTRY_UPDATE_SIZE, + gimage->xresolution, + gimage->yresolution, + TRUE); + + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 0, 1.0, GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 1, 1.0, GIMP_MAX_IMAGE_SIZE); + + gtk_table_set_col_spacings (GTK_TABLE (sizeentry), 2); + gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2); + + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Width"), 0, 1, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Height"), 0, 2, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Pixels"), 1, 4, 0.0); + + gtk_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0); + gtk_widget_show (sizeentry); + + gtk_widget_show (hbox); + + /* the offset frame */ + frame = gtk_frame_new (_("Offset")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 2); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + sizeentry = gimp_prop_coordinates_new (G_OBJECT (grid), + "xoffset", + "yoffset", + "offset-unit", + "%a", + GIMP_SIZE_ENTRY_UPDATE_SIZE, + gimage->xresolution, + gimage->yresolution, + TRUE); + + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 0, - GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), + 1, - GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + + gtk_table_set_col_spacings (GTK_TABLE (sizeentry), 2); + gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2); + + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Width"), 0, 1, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Height"), 0, 2, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), + _("Pixels"), 1, 4, 0.0); + + gtk_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0); + gtk_widget_show (sizeentry); + + gtk_widget_show (hbox); + + if (grid_orig) + { + gimp_config_copy_properties (G_OBJECT (grid_orig), G_OBJECT (grid)); + } + else + { + gimp_config_reset_properties (G_OBJECT (grid)); + g_object_set (G_OBJECT (grid), + "spacing-unit", gimage->unit, + NULL); + g_object_set (G_OBJECT (grid), + "offset-unit", gimage->unit, + NULL); + } + + gtk_widget_show (main_vbox); + + g_object_set_data (G_OBJECT (dialog), "gimage", gimage); + g_object_set_data (G_OBJECT (dialog), "shell", shell); + + g_object_set_data (G_OBJECT (dialog), "grid", grid); + + g_object_set_data (G_OBJECT (dialog), "show-button", show_button); + g_object_set_data (G_OBJECT (dialog), "snap-button", snap_button); + + return dialog; +} + + +/* local functions */ + + +static void +reset_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpImage *gimage; + GimpDisplayShell *shell; + GimpGrid *grid_orig; + GimpGrid *grid; + GimpUnit unit_orig; + GtkWidget *show_button; + GtkWidget *snap_button; + gboolean show_grid; + gboolean snap_to_grid; + + gimage = g_object_get_data (G_OBJECT (dialog), "gimage"); + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + shell = g_object_get_data (G_OBJECT (dialog), "shell"); + show_button = g_object_get_data (G_OBJECT (dialog), "show-button"); + snap_button = g_object_get_data (G_OBJECT (dialog), "snap-button"); + + grid_orig = gimp_image_get_grid (GIMP_IMAGE (gimage)); + unit_orig = gimp_image_get_unit (GIMP_IMAGE (gimage)); + + if (grid_orig) + { + gimp_config_copy_properties (G_OBJECT (grid_orig), + G_OBJECT (grid)); + } + else + { + g_object_freeze_notify (G_OBJECT (grid)); + gimp_config_reset_properties (G_OBJECT (grid)); + + g_object_set (G_OBJECT (grid), + "spacing-unit", unit_orig, + NULL); + g_object_set (G_OBJECT (grid), + "offset-unit", unit_orig, + NULL); + + g_object_thaw_notify (G_OBJECT (grid)); + } + + show_grid = gimp_display_shell_get_show_grid (GIMP_DISPLAY_SHELL (shell)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show_button), + show_grid); + + snap_to_grid = gimp_display_shell_get_snap_to_grid (GIMP_DISPLAY_SHELL (shell)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (snap_button), + snap_to_grid); +} + +static void +remove_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpImage *gimage; + GimpGrid *grid; + + gimage = g_object_get_data (G_OBJECT (dialog), "gimage"); + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + + gimp_image_set_grid (gimage, NULL, TRUE); + g_object_unref (G_OBJECT (grid)); + gtk_widget_destroy (dialog); +} + + +static void +cancel_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpGrid *grid; + + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + + g_object_unref (G_OBJECT (grid)); + gtk_widget_destroy (dialog); +} + +static void +ok_callback (GtkWidget *widget, + GtkWidget *dialog) +{ + GimpImage *gimage; + GimpDisplayShell *shell; + GimpGrid *grid; + GimpGrid *grid_orig; + GtkWidget *show_button; + GtkWidget *snap_button; + gboolean show_grid; + gboolean snap_to_grid; + + gimage = g_object_get_data (G_OBJECT (dialog), "gimage"); + grid = g_object_get_data (G_OBJECT (dialog), "grid"); + shell = g_object_get_data (G_OBJECT (dialog), "shell"); + show_button = g_object_get_data (G_OBJECT (dialog), "show-button"); + snap_button = g_object_get_data (G_OBJECT (dialog), "snap-button"); + + grid_orig = gimp_image_get_grid (GIMP_IMAGE (gimage)); + + if (grid_orig == NULL || gimp_config_diff (G_OBJECT (grid_orig), G_OBJECT (grid), 0)) + gimp_image_set_grid (GIMP_IMAGE (gimage), grid, TRUE); + else + g_object_unref (G_OBJECT (grid)); + + show_grid = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_button)); + gimp_display_shell_set_show_grid (GIMP_DISPLAY_SHELL (shell), show_grid); + + snap_to_grid = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (snap_button)); + gimp_display_shell_set_snap_to_grid (GIMP_DISPLAY_SHELL (shell), snap_to_grid); + + gtk_widget_destroy (dialog); +} diff --git a/app/gui/grid-dialog.h b/app/gui/grid-dialog.h new file mode 100644 index 0000000000..11f0803481 --- /dev/null +++ b/app/gui/grid-dialog.h @@ -0,0 +1,24 @@ +/* The GIMP -- an 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GRID_DIALOG_H__ +#define __GRID_DIALOG_H__ + +GtkWidget * grid_dialog_new (GimpDisplay *gdisp); + +#endif /* __GRID_DIALOG_H__ */ diff --git a/app/gui/image-menu.c b/app/gui/image-menu.c index 2dcbf4d9a2..639d5646c2 100644 --- a/app/gui/image-menu.c +++ b/app/gui/image-menu.c @@ -422,6 +422,21 @@ GimpItemFactoryEntry image_menu_entries[] = MENU_SEPARATOR ("/View/---"), + { { N_("/View/Configure Grid..."), NULL, + view_configure_grid_cmd_callback, 0, NULL }, + NULL, + "view/configure_grid.html", NULL }, + { { N_("/View/Show Grid"), NULL, + view_toggle_grid_cmd_callback, 0, "" }, + NULL, + "view/toggle_grid.html", NULL }, + { { N_("/View/Snap to Grid"), NULL, + view_snap_to_grid_cmd_callback, 0, "" }, + NULL, + "view/snap_to_grid.html", NULL }, + + MENU_SEPARATOR ("/View/---"), + { { N_("/View/Show Menubar"), NULL, view_toggle_menubar_cmd_callback, 0, "" }, NULL, @@ -1414,6 +1429,11 @@ image_menu_update (GtkItemFactory *item_factory, SET_SENSITIVE ("/View/Snap to Guides", gdisp); SET_ACTIVE ("/View/Snap to Guides", gdisp && shell->snap_to_guides); + SET_SENSITIVE ("/View/Show Grid", gdisp); + SET_ACTIVE ("/View/Show Grid", gdisp && visibility->grid); + SET_SENSITIVE ("/View/Snap to Grid", gdisp); + SET_ACTIVE ("/View/Snap to Grid", gdisp && shell->snap_to_grid); + SET_SENSITIVE ("/View/Show Menubar", gdisp); SET_ACTIVE ("/View/Show Menubar", gdisp && visibility->menubar); SET_SENSITIVE ("/View/Show Rulers", gdisp); diff --git a/app/gui/view-commands.c b/app/gui/view-commands.c index 992a66f8aa..98a33d26e5 100644 --- a/app/gui/view-commands.c +++ b/app/gui/view-commands.c @@ -42,6 +42,7 @@ #include "dialogs.h" #include "info-dialog.h" #include "info-window.h" +#include "grid-dialog.h" #include "view-commands.h" @@ -350,6 +351,63 @@ view_snap_to_guides_cmd_callback (GtkWidget *widget, } } +void +view_configure_grid_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDisplay *gdisp; + GtkWidget *grid_dialog; + return_if_no_display (gdisp, data); + + grid_dialog = grid_dialog_new (GIMP_DISPLAY (gdisp)); + + g_signal_connect_object (gdisp, "disconnect", + G_CALLBACK (gtk_widget_destroy), + grid_dialog, + G_CONNECT_SWAPPED); + + gtk_widget_show (grid_dialog); +} + + +void +view_toggle_grid_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDisplay *gdisp; + GimpDisplayShell *shell; + return_if_no_display (gdisp, data); + + shell = GIMP_DISPLAY_SHELL (gdisp->shell); + + gimp_display_shell_set_show_grid (shell, + GTK_CHECK_MENU_ITEM (widget)->active); + +} + +void +view_snap_to_grid_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDisplay *gdisp; + GimpDisplayShell *shell; + return_if_no_display (gdisp, data); + + shell = GIMP_DISPLAY_SHELL (gdisp->shell); + + if (shell->snap_to_grid != GTK_CHECK_MENU_ITEM (widget)->active) + { + shell->snap_to_grid = GTK_CHECK_MENU_ITEM (widget)->active; + + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->menubar_factory), + "/View/Snap to Grid", + shell->snap_to_grid); + gimp_item_factory_set_active (GTK_ITEM_FACTORY (shell->popup_factory), + "/View/Snap to Grid", + shell->snap_to_grid); + } +} + void view_new_view_cmd_callback (GtkWidget *widget, gpointer data) diff --git a/app/gui/view-commands.h b/app/gui/view-commands.h index 858e31496a..20c9495ec9 100644 --- a/app/gui/view-commands.h +++ b/app/gui/view-commands.h @@ -57,6 +57,12 @@ void view_toggle_guides_cmd_callback (GtkWidget *widget, gpointer data); void view_snap_to_guides_cmd_callback (GtkWidget *widget, gpointer data); +void view_toggle_grid_cmd_callback (GtkWidget *widget, + gpointer data); +void view_configure_grid_cmd_callback (GtkWidget *widget, + gpointer data); +void view_snap_to_grid_cmd_callback (GtkWidget *widget, + gpointer data); void view_new_view_cmd_callback (GtkWidget *widget, gpointer data); void view_shrink_wrap_cmd_callback (GtkWidget *widget, diff --git a/app/menus/image-menu.c b/app/menus/image-menu.c index 2dcbf4d9a2..639d5646c2 100644 --- a/app/menus/image-menu.c +++ b/app/menus/image-menu.c @@ -422,6 +422,21 @@ GimpItemFactoryEntry image_menu_entries[] = MENU_SEPARATOR ("/View/---"), + { { N_("/View/Configure Grid..."), NULL, + view_configure_grid_cmd_callback, 0, NULL }, + NULL, + "view/configure_grid.html", NULL }, + { { N_("/View/Show Grid"), NULL, + view_toggle_grid_cmd_callback, 0, "" }, + NULL, + "view/toggle_grid.html", NULL }, + { { N_("/View/Snap to Grid"), NULL, + view_snap_to_grid_cmd_callback, 0, "" }, + NULL, + "view/snap_to_grid.html", NULL }, + + MENU_SEPARATOR ("/View/---"), + { { N_("/View/Show Menubar"), NULL, view_toggle_menubar_cmd_callback, 0, "" }, NULL, @@ -1414,6 +1429,11 @@ image_menu_update (GtkItemFactory *item_factory, SET_SENSITIVE ("/View/Snap to Guides", gdisp); SET_ACTIVE ("/View/Snap to Guides", gdisp && shell->snap_to_guides); + SET_SENSITIVE ("/View/Show Grid", gdisp); + SET_ACTIVE ("/View/Show Grid", gdisp && visibility->grid); + SET_SENSITIVE ("/View/Snap to Grid", gdisp); + SET_ACTIVE ("/View/Snap to Grid", gdisp && shell->snap_to_grid); + SET_SENSITIVE ("/View/Show Menubar", gdisp); SET_ACTIVE ("/View/Show Menubar", gdisp && visibility->menubar); SET_SENSITIVE ("/View/Show Rulers", gdisp);