diff --git a/ChangeLog b/ChangeLog index 39ce10b139..bd4ac6305b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2008-05-26 Sven Neumann + + * libgimpwidgets/Makefile.am + * libgimpwidgets/gimpwidgets.h + * libgimpwidgets/gimpwidgetstypes.h + + * libgimpwidgets/gimpruler.[ch] + * libgimpwidgets/gimphruler.[ch] + * libgimpwidgets/gimpvruler.[ch]: added ruler widgets. These are + mostly copied from GTK+ and work as a drop-in replacement for + GtkRuler and friends. + + * libgimpwidgets/gimpwidgets.def: updated. + + * app/display/gimpdisplayshell.c + * app/display/gimpdisplayshell-scale.c + * app/dialogs/resolution-calibrate-dialog.c + * plug-ins/imagemap/imap_preview.c + * plug-ins/gfig/gfig-preview.c: use the GimpRuler widgets. + 2008-05-26 Sven Neumann * libgimp/gimp.def: added gimp_drawable_free_shadow(). diff --git a/app/dialogs/resolution-calibrate-dialog.c b/app/dialogs/resolution-calibrate-dialog.c index 4d38a4f59c..9bc08eee91 100644 --- a/app/dialogs/resolution-calibrate-dialog.c +++ b/app/dialogs/resolution-calibrate-dialog.c @@ -105,16 +105,16 @@ resolution_calibrate_dialog (GtkWidget *resolution_entry, gtk_widget_show (image); } - ruler = gtk_hruler_new (); + ruler = gimp_hruler_new (); gtk_widget_set_size_request (ruler, ruler_width, 32); - gtk_ruler_set_range (GTK_RULER (ruler), 0, ruler_width, 0, ruler_width); + gimp_ruler_set_range (GIMP_RULER (ruler), 0, ruler_width, 0, ruler_width); gtk_table_attach (GTK_TABLE (table), ruler, 1, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_show (ruler); - ruler = gtk_vruler_new (); + ruler = gimp_vruler_new (); gtk_widget_set_size_request (ruler, 32, ruler_height); - gtk_ruler_set_range (GTK_RULER (ruler), 0, ruler_height, 0, ruler_height); + gimp_ruler_set_range (GIMP_RULER (ruler), 0, ruler_height, 0, ruler_height); gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 3, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_show (ruler); diff --git a/app/display/gimpdisplayshell-scale.c b/app/display/gimpdisplayshell-scale.c index 53032fb144..5ee4e0cdf9 100644 --- a/app/display/gimpdisplayshell-scale.c +++ b/app/display/gimpdisplayshell-scale.c @@ -89,10 +89,13 @@ void gimp_display_shell_scale_setup (GimpDisplayShell *shell) { GimpImage *image; - GtkRuler *hruler; - GtkRuler *vruler; + gdouble lower; + gdouble upper; + gdouble position; + gdouble max_size; gfloat sx, sy; - gint image_width, image_height; + gint image_width; + gint image_height; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); @@ -133,95 +136,92 @@ gimp_display_shell_scale_setup (GimpDisplayShell *shell) gtk_adjustment_changed (shell->hsbdata); gtk_adjustment_changed (shell->vsbdata); - hruler = GTK_RULER (shell->hrule); - vruler = GTK_RULER (shell->vrule); + /* horizontal ruler */ - hruler->lower = 0; + gimp_ruler_get_range (GIMP_RULER (shell->hrule), + &lower, &upper, &position, &max_size); + lower = 0; if (image) { - hruler->upper = img2real (shell, TRUE, - FUNSCALEX (shell, shell->disp_width)); - hruler->max_size = img2real (shell, TRUE, - MAX (image_width, image_height)); + upper = img2real (shell, TRUE, FUNSCALEX (shell, shell->disp_width)); + max_size = img2real (shell, TRUE, MAX (image_width, image_height)); } else { - hruler->upper = image_width; - hruler->max_size = MAX (image_width, image_height); - } - - vruler->lower = 0; - - if (image) - { - vruler->upper = img2real (shell, FALSE, - FUNSCALEY (shell, shell->disp_height)); - vruler->max_size = img2real (shell, FALSE, - MAX (image_width, image_height)); - } - else - { - vruler->upper = image_height; - vruler->max_size = MAX (image_width, image_height); + upper = image_width; + max_size = MAX (image_width, image_height); } if (image && sx < shell->disp_width) { shell->disp_xoffset = (shell->disp_width - sx) / 2; - hruler->lower -= img2real (shell, TRUE, - FUNSCALEX (shell, - (gdouble) shell->disp_xoffset)); - hruler->upper -= img2real (shell, TRUE, - FUNSCALEX (shell, - (gdouble) shell->disp_xoffset)); + lower -= img2real (shell, TRUE, + FUNSCALEX (shell, (gdouble) shell->disp_xoffset)); + upper -= img2real (shell, TRUE, + FUNSCALEX (shell, (gdouble) shell->disp_xoffset)); } else if (image) { shell->disp_xoffset = 0; - hruler->lower += img2real (shell, TRUE, - FUNSCALEX (shell, - (gdouble) shell->offset_x)); - hruler->upper += img2real (shell, TRUE, - FUNSCALEX (shell, - (gdouble) shell->offset_x)); + lower += img2real (shell, TRUE, + FUNSCALEX (shell, (gdouble) shell->offset_x)); + upper += img2real (shell, TRUE, + FUNSCALEX (shell, (gdouble) shell->offset_x)); } else { shell->disp_xoffset = 0; } + gimp_ruler_set_range (GIMP_RULER (shell->hrule), + lower, upper, position, max_size); + + /* vertical ruler */ + + gimp_ruler_get_range (GIMP_RULER (shell->vrule), + &lower, &upper, &position, &max_size); + lower = 0; + + if (image) + { + upper = img2real (shell, FALSE, FUNSCALEY (shell, shell->disp_height)); + max_size = img2real (shell, FALSE, MAX (image_width, image_height)); + } + else + { + upper = image_height; + max_size = MAX (image_width, image_height); + } + if (image && sy < shell->disp_height) { shell->disp_yoffset = (shell->disp_height - sy) / 2; - vruler->lower -= img2real (shell, FALSE, - FUNSCALEY (shell, - (gdouble) shell->disp_yoffset)); - vruler->upper -= img2real (shell, FALSE, - FUNSCALEY (shell, - (gdouble) shell->disp_yoffset)); + lower -= img2real (shell, FALSE, + FUNSCALEY (shell, (gdouble) shell->disp_yoffset)); + upper -= img2real (shell, FALSE, + FUNSCALEY (shell, (gdouble) shell->disp_yoffset)); } else if (image) { shell->disp_yoffset = 0; - vruler->lower += img2real (shell, FALSE, - FUNSCALEY (shell, - (gdouble) shell->offset_y)); - vruler->upper += img2real (shell, FALSE, - FUNSCALEY (shell, - (gdouble) shell->offset_y)); + lower += img2real (shell, FALSE, + FUNSCALEY (shell, (gdouble) shell->offset_y)); + upper += img2real (shell, FALSE, + FUNSCALEY (shell, (gdouble) shell->offset_y)); } else { shell->disp_yoffset = 0; } - gtk_widget_queue_draw (GTK_WIDGET (hruler)); - gtk_widget_queue_draw (GTK_WIDGET (vruler)); + gimp_ruler_set_range (GIMP_RULER (shell->vrule), + lower, upper, position, max_size); + #if 0 g_printerr ("offset_x: %d\n" @@ -240,8 +240,8 @@ gimp_display_shell_scale_setup (GimpDisplayShell *shell) * gimp_display_shell_scale_revert: * @shell: the #GimpDisplayShell * - * Reverts the display to the previously used scale. If no previous scale exist - * then the call does nothing. + * Reverts the display to the previously used scale. If no previous + * scale exist, then the call does nothing. * * Return value: %TRUE if the scale was reverted, otherwise %FALSE. **/ diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index 0b181baec6..144ef1abd9 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -968,7 +968,7 @@ gimp_display_shell_new (GimpDisplay *display, gimp_display_shell_selection_init (shell); /* the horizontal ruler */ - shell->hrule = gtk_hruler_new (); + shell->hrule = gimp_hruler_new (); gtk_widget_set_events (GTK_WIDGET (shell->hrule), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); @@ -982,7 +982,7 @@ gimp_display_shell_new (GimpDisplay *display, gimp_help_set_help_data (shell->hrule, NULL, GIMP_HELP_IMAGE_WINDOW_RULER); /* the vertical ruler */ - shell->vrule = gtk_vruler_new (); + shell->vrule = gimp_vruler_new (); gtk_widget_set_events (GTK_WIDGET (shell->vrule), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); diff --git a/libgimpwidgets/Makefile.am b/libgimpwidgets/Makefile.am index 112aa47b73..c0ae46c4a7 100644 --- a/libgimpwidgets/Makefile.am +++ b/libgimpwidgets/Makefile.am @@ -122,6 +122,8 @@ libgimpwidgets_2_0_la_sources = \ gimphelpui.h \ gimphintbox.c \ gimphintbox.h \ + gimphruler.c \ + gimphruler.h \ gimpintcombobox.c \ gimpintcombobox.h \ gimpintstore.c \ @@ -150,6 +152,8 @@ libgimpwidgets_2_0_la_sources = \ gimppropwidgets.h \ gimpquerybox.c \ gimpquerybox.h \ + gimpruler.c \ + gimpruler.h \ gimpscaleentry.c \ gimpscaleentry.h \ gimpscrolledpreview.c \ @@ -162,6 +166,8 @@ libgimpwidgets_2_0_la_sources = \ gimpstringcombobox.h \ gimpunitmenu.c \ gimpunitmenu.h \ + gimpvruler.c \ + gimpvruler.h \ gimpzoommodel.c \ gimpzoommodel.h \ gimpwidgets-private.c \ @@ -212,6 +218,7 @@ libgimpwidgetsinclude_HEADERS = \ gimpframe.h \ gimphelpui.h \ gimphintbox.h \ + gimphruler.h \ gimpintcombobox.h \ gimpintstore.h \ gimpmemsizeentry.h \ @@ -226,12 +233,14 @@ libgimpwidgetsinclude_HEADERS = \ gimppreviewarea.h \ gimppropwidgets.h \ gimpquerybox.h \ + gimpruler.h \ gimpscaleentry.h \ gimpscrolledpreview.h \ gimpsizeentry.h \ gimpstock.h \ gimpstringcombobox.h \ gimpunitmenu.h \ + gimpvruler.h \ gimpzoommodel.h libgimpwidgets_2_0_la_LDFLAGS = \ diff --git a/libgimpwidgets/gimphruler.c b/libgimpwidgets/gimphruler.c new file mode 100644 index 0000000000..3514cc73f2 --- /dev/null +++ b/libgimpwidgets/gimphruler.c @@ -0,0 +1,324 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include "libgimpmath/gimpmath.h" + +#include "gimpwidgetstypes.h" + +#include "gimphruler.h" + + +#define RULER_HEIGHT 14 +#define MINIMUM_INCR 5 +#define MAXIMUM_SUBDIVIDE 5 +#define MAXIMUM_SCALES 10 + + +typedef struct +{ + gint xsrc; + gint ysrc; +} GimpHRulerPrivate; + + +static gint gimp_hruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gimp_hruler_draw_ticks (GimpRuler *ruler); +static void gimp_hruler_draw_pos (GimpRuler *ruler); + +G_DEFINE_TYPE (GimpHRuler, gimp_hruler, GIMP_TYPE_RULER) + +#define GIMP_HRULER_GET_PRIVATE(ruler) \ + G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_HRULER, GimpHRulerPrivate) + + +static void +gimp_hruler_class_init (GimpHRulerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GimpRulerClass *ruler_class = GIMP_RULER_CLASS (klass); + + widget_class->motion_notify_event = gimp_hruler_motion_notify; + + ruler_class->draw_ticks = gimp_hruler_draw_ticks; + ruler_class->draw_pos = gimp_hruler_draw_pos; + + g_type_class_add_private (object_class, sizeof (GimpHRulerPrivate)); +} + +static void +gimp_hruler_init (GimpHRuler *hruler) +{ + GtkWidget *widget = GTK_WIDGET (hruler); + + widget->requisition.width = widget->style->xthickness * 2 + 1; + widget->requisition.height = widget->style->ythickness * 2 + RULER_HEIGHT; +} + + +GtkWidget* +gimp_hruler_new (void) +{ + return g_object_new (GIMP_TYPE_HRULER, NULL); +} + +static gint +gimp_hruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GimpRuler *ruler = GIMP_RULER (widget); + gdouble lower; + gdouble upper; + gdouble position; + gint x; + + gdk_event_request_motions (event); + x = event->x; + + gimp_ruler_get_range (ruler, &lower, &upper, NULL, NULL); + + position = lower + ((upper - lower) * x) / widget->allocation.width; + + g_object_set (ruler, "position", position, NULL); + + gimp_ruler_draw_pos (ruler); + + return FALSE; +} + +static void +gimp_hruler_draw_ticks (GimpRuler *ruler) +{ + GtkWidget *widget = GTK_WIDGET (ruler); + GimpRulerMetric *metric; + GdkDrawable *backing_store; + cairo_t *cr; + gint i; + gint width, height; + gint xthickness; + gint ythickness; + gint length, ideal_length; + gdouble lower, upper; /* Upper and lower limits, in ruler units */ + gdouble increment; /* Number of pixels per unit */ + gint scale; /* Number of units per major unit */ + gdouble subd_incr; + gdouble start, end, cur; + gchar unit_str[32]; + gint digit_height; + gint digit_offset; + gint text_width; + gint pos; + gdouble max_size; + PangoLayout *layout; + PangoRectangle logical_rect, ink_rect; + + if (! GTK_WIDGET_DRAWABLE (widget)) + return; + + backing_store = _gimp_ruler_get_backing_store (ruler); + + xthickness = widget->style->xthickness; + ythickness = widget->style->ythickness; + + layout = gtk_widget_create_pango_layout (widget, "012456789"); + pango_layout_get_extents (layout, &ink_rect, &logical_rect); + + digit_height = PANGO_PIXELS (ink_rect.height) + 2; + digit_offset = ink_rect.y; + + width = widget->allocation.width; + height = widget->allocation.height - ythickness * 2; + + gtk_paint_box (widget->style, backing_store, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "hruler", + 0, 0, + widget->allocation.width, widget->allocation.height); + + cr = gdk_cairo_create (backing_store); + gdk_cairo_set_source_color (cr, &widget->style->fg[widget->state]); + + cairo_rectangle (cr, + xthickness, + height + ythickness, + widget->allocation.width - 2 * xthickness, + 1); + + gimp_ruler_get_range (ruler, &lower, &upper, NULL, &max_size); + + metric = _gimp_ruler_get_metric (ruler); + + upper = upper / metric->pixels_per_unit; + lower = lower / metric->pixels_per_unit; + + if ((upper - lower) == 0) + goto out; + + increment = (gdouble) width / (upper - lower); + + /* determine the scale + * We calculate the text size as for the vruler instead of using + * text_width = gdk_string_width(font, unit_str), so that the result + * for the scale looks consistent with an accompanying vruler + */ + scale = ceil (max_size / metric->pixels_per_unit); + g_snprintf (unit_str, sizeof (unit_str), "%d", scale); + text_width = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < MAXIMUM_SCALES; scale++) + if (metric->ruler_scale[scale] * fabs(increment) > 2 * text_width) + break; + + if (scale == MAXIMUM_SCALES) + scale = MAXIMUM_SCALES - 1; + + /* drawing starts here */ + length = 0; + for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--) + { + subd_incr = (gdouble) metric->ruler_scale[scale] / + (gdouble) metric->subdivide[i]; + if (subd_incr * fabs(increment) <= MINIMUM_INCR) + continue; + + /* Calculate the length of the tickmarks. Make sure that + * this length increases for each set of ticks + */ + ideal_length = height / (i + 1) - 1; + if (ideal_length > ++length) + length = ideal_length; + + if (lower < upper) + { + start = floor (lower / subd_incr) * subd_incr; + end = ceil (upper / subd_incr) * subd_incr; + } + else + { + start = floor (upper / subd_incr) * subd_incr; + end = ceil (lower / subd_incr) * subd_incr; + } + + + for (cur = start; cur <= end; cur += subd_incr) + { + pos = ROUND ((cur - lower) * increment); + + cairo_rectangle (cr, + pos, height + ythickness - length, + 1, length); + + /* draw label */ + if (i == 0) + { + g_snprintf (unit_str, sizeof (unit_str), "%d", (int) cur); + + pango_layout_set_text (layout, unit_str, -1); + pango_layout_get_extents (layout, &logical_rect, NULL); + + gtk_paint_layout (widget->style, + backing_store, + GTK_WIDGET_STATE (widget), + FALSE, + NULL, + widget, + "hruler", + pos + 2, + ythickness + PANGO_PIXELS (logical_rect.y - digit_offset), + layout); + } + } + } + + cairo_fill (cr); +out: + cairo_destroy (cr); + + g_object_unref (layout); +} + +static void +gimp_hruler_draw_pos (GimpRuler *ruler) +{ + GtkWidget *widget = GTK_WIDGET (ruler); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + GimpHRulerPrivate *priv = GIMP_HRULER_GET_PRIVATE (ruler); + gint x, y; + gint width, height; + gint bs_width, bs_height; + gint xthickness; + gint ythickness; + + xthickness = widget->style->xthickness; + ythickness = widget->style->ythickness; + width = widget->allocation.width; + height = widget->allocation.height - ythickness * 2; + + bs_width = height / 2 + 2; + bs_width |= 1; /* make sure it's odd */ + bs_height = bs_width / 2 + 1; + + if ((bs_width > 0) && (bs_height > 0)) + { + GdkDrawable *backing_store = _gimp_ruler_get_backing_store (ruler); + cairo_t *cr = gdk_cairo_create (widget->window); + gdouble lower; + gdouble upper; + gdouble position; + gdouble increment; + + /* If a backing store exists, restore the ruler */ + if (backing_store) + gdk_draw_drawable (widget->window, + widget->style->black_gc, + backing_store, + priv->xsrc, priv->ysrc, + priv->xsrc, priv->ysrc, + bs_width, bs_height); + + gimp_ruler_get_range (ruler, &lower, &upper, &position, NULL); + + increment = (gdouble) width / (upper - lower); + + x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1; + y = (height + bs_height) / 2 + ythickness; + + gdk_cairo_set_source_color (cr, &widget->style->fg[widget->state]); + + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + bs_width / 2., y + bs_height); + cairo_line_to (cr, x + bs_width, y); + cairo_fill (cr); + + cairo_destroy (cr); + + priv->xsrc = x; + priv->ysrc = y; + } + } +} diff --git a/libgimpwidgets/gimphruler.h b/libgimpwidgets/gimphruler.h new file mode 100644 index 0000000000..684b9b0757 --- /dev/null +++ b/libgimpwidgets/gimphruler.h @@ -0,0 +1,55 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GIMP_HRULER_H__ +#define __GIMP_HRULER_H__ + +#include "gimpruler.h" + + +G_BEGIN_DECLS + + +#define GIMP_TYPE_HRULER (gimp_hruler_get_type ()) +#define GIMP_HRULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HRULER, GimpHRuler)) +#define GIMP_HRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HRULER, GimpHRulerClass)) +#define GIMP_IS_HRULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HRULER)) +#define GIMP_IS_HRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HRULER)) +#define GIMP_HRULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HRULER, GimpHRulerClass)) + + +typedef GimpRulerClass GimpHRulerClass; +typedef GimpRuler GimpHRuler; + + +GType gimp_hruler_get_type (void) G_GNUC_CONST; +GtkWidget* gimp_hruler_new (void); + + +G_END_DECLS + + +#endif /* __GIMP_HRULER_H__ */ diff --git a/libgimpwidgets/gimpruler.c b/libgimpwidgets/gimpruler.c new file mode 100644 index 0000000000..feaeeae809 --- /dev/null +++ b/libgimpwidgets/gimpruler.c @@ -0,0 +1,532 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "gimpwidgetstypes.h" + +#include "gimpruler.h" + + +/* All distances below are in 1/72nd's of an inch. (According to + * Adobe that's a point, but points are really 1/72.27 in.) + */ +typedef struct +{ + GdkPixmap *backing_store; + GdkGC *non_gr_exp_gc; + GimpRulerMetric *metric; + + /* The upper limit of the ruler (in points) */ + gdouble lower; + /* The lower limit of the ruler */ + gdouble upper; + /* The position of the mark on the ruler */ + gdouble position; + /* The maximum size of the ruler */ + gdouble max_size; +} GimpRulerPrivate; + +enum +{ + PROP_0, + PROP_LOWER, + PROP_UPPER, + PROP_POSITION, + PROP_MAX_SIZE, + PROP_METRIC +}; + +static void gimp_ruler_realize (GtkWidget *widget); +static void gimp_ruler_unrealize (GtkWidget *widget); +static void gimp_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gimp_ruler_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gimp_ruler_make_pixmap (GimpRuler *ruler); +static void gimp_ruler_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_ruler_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static const GimpRulerMetric ruler_metrics[] = +{ + { "Pixel", "Pi", 1.0, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, + { "Inches", "In", 72.0, { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }, { 1, 2, 4, 8, 16 }}, + { "Centimeters", "Cn", 28.35, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, +}; + +G_DEFINE_TYPE (GimpRuler, gimp_ruler, GTK_TYPE_WIDGET) + +#define GIMP_RULER_GET_PRIVATE(ruler) \ + G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_RULER, GimpRulerPrivate) + + +static void +gimp_ruler_class_init (GimpRulerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->set_property = gimp_ruler_set_property; + object_class->get_property = gimp_ruler_get_property; + + widget_class->realize = gimp_ruler_realize; + widget_class->unrealize = gimp_ruler_unrealize; + widget_class->size_allocate = gimp_ruler_size_allocate; + widget_class->expose_event = gimp_ruler_expose; + + klass->draw_ticks = NULL; + klass->draw_pos = NULL; + + g_type_class_add_private (object_class, sizeof (GimpRulerPrivate)); + + g_object_class_install_property (object_class, + PROP_LOWER, + g_param_spec_double ("lower", + "Lower", + "Lower limit of ruler", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0.0, + GIMP_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_UPPER, + g_param_spec_double ("upper", + "Upper", + "Upper limit of ruler", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0.0, + GIMP_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_POSITION, + g_param_spec_double ("position", + "Position", + "Position of mark on the ruler", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0.0, + GIMP_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_MAX_SIZE, + g_param_spec_double ("max-size", + "Max Size", + "Maximum size of the ruler", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0.0, + GIMP_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_METRIC, + g_param_spec_enum ("metric", + "Metric", + "The metric used for the ruler", + GTK_TYPE_METRIC_TYPE, + GTK_PIXELS, + GIMP_PARAM_READWRITE)); +} + +static void +gimp_ruler_init (GimpRuler *ruler) +{ + GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler); + + priv->backing_store = NULL; + priv->lower = 0; + priv->upper = 0; + priv->position = 0; + priv->max_size = 0; + + gimp_ruler_set_metric (ruler, GTK_PIXELS); +} + +static void +gimp_ruler_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpRuler *ruler = GIMP_RULER (object); + GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler); + + switch (prop_id) + { + case PROP_LOWER: + gimp_ruler_set_range (ruler, g_value_get_double (value), priv->upper, + priv->position, priv->max_size); + break; + case PROP_UPPER: + gimp_ruler_set_range (ruler, priv->lower, g_value_get_double (value), + priv->position, priv->max_size); + break; + case PROP_POSITION: + gimp_ruler_set_range (ruler, priv->lower, priv->upper, + g_value_get_double (value), priv->max_size); + break; + case PROP_MAX_SIZE: + gimp_ruler_set_range (ruler, priv->lower, priv->upper, + priv->position, g_value_get_double (value)); + break; + case PROP_METRIC: + gimp_ruler_set_metric (ruler, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gimp_ruler_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GimpRuler *ruler = GIMP_RULER (object); + GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler); + + switch (prop_id) + { + case PROP_LOWER: + g_value_set_double (value, priv->lower); + break; + case PROP_UPPER: + g_value_set_double (value, priv->upper); + break; + case PROP_POSITION: + g_value_set_double (value, priv->position); + break; + case PROP_MAX_SIZE: + g_value_set_double (value, priv->max_size); + break; + case PROP_METRIC: + g_value_set_enum (value, gimp_ruler_get_metric (ruler)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +void +gimp_ruler_set_metric (GimpRuler *ruler, + GtkMetricType metric) +{ + GimpRulerPrivate *priv; + + g_return_if_fail (GIMP_IS_RULER (ruler)); + + priv = GIMP_RULER_GET_PRIVATE (ruler); + + priv->metric = (GimpRulerMetric *) &ruler_metrics[metric]; + + if (GTK_WIDGET_DRAWABLE (ruler)) + gtk_widget_queue_draw (GTK_WIDGET (ruler)); + + g_object_notify (G_OBJECT (ruler), "metric"); +} + +/** + * gimp_ruler_get_metric: + * @ruler: a #GimpRuler + * + * Gets the units used for a #GimpRuler. See gimp_ruler_set_metric(). + * + * Return value: the units currently used for @ruler + * + * Since: GIMP 2.8 + **/ +GtkMetricType +gimp_ruler_get_metric (GimpRuler *ruler) +{ + GimpRulerPrivate *priv; + gint i; + + g_return_val_if_fail (GIMP_IS_RULER (ruler), 0); + + priv = GIMP_RULER_GET_PRIVATE (ruler); + + for (i = 0; i < G_N_ELEMENTS (ruler_metrics); i++) + if (priv->metric == &ruler_metrics[i]) + return i; + + g_assert_not_reached (); + + return 0; +} + +/** + * gimp_ruler_set_range: + * @ruler: the gtkruler + * @lower: the lower limit of the ruler + * @upper: the upper limit of the ruler + * @position: the mark on the ruler + * @max_size: the maximum size of the ruler used when calculating the space to + * leave for the text + * + * This sets the range of the ruler. + * + * Since: GIMP 2.8 + */ +void +gimp_ruler_set_range (GimpRuler *ruler, + gdouble lower, + gdouble upper, + gdouble position, + gdouble max_size) +{ + GimpRulerPrivate *priv; + + g_return_if_fail (GIMP_IS_RULER (ruler)); + + priv = GIMP_RULER_GET_PRIVATE (ruler); + + g_object_freeze_notify (G_OBJECT (ruler)); + if (priv->lower != lower) + { + priv->lower = lower; + g_object_notify (G_OBJECT (ruler), "lower"); + } + if (priv->upper != upper) + { + priv->upper = upper; + g_object_notify (G_OBJECT (ruler), "upper"); + } + if (priv->position != position) + { + priv->position = position; + g_object_notify (G_OBJECT (ruler), "position"); + } + if (priv->max_size != max_size) + { + priv->max_size = max_size; + g_object_notify (G_OBJECT (ruler), "max-size"); + } + g_object_thaw_notify (G_OBJECT (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + gtk_widget_queue_draw (GTK_WIDGET (ruler)); +} + +/** + * gimp_ruler_get_range: + * @ruler: a #GimpRuler + * @lower: location to store lower limit of the ruler, or %NULL + * @upper: location to store upper limit of the ruler, or %NULL + * @position: location to store the current position of the mark on the ruler, or %NULL + * @max_size: location to store the maximum size of the ruler used when calculating + * the space to leave for the text, or %NULL. + * + * Retrieves values indicating the range and current position of a #GimpRuler. + * See gimp_ruler_set_range(). + * + * Since: GIMP 2.8 + **/ +void +gimp_ruler_get_range (GimpRuler *ruler, + gdouble *lower, + gdouble *upper, + gdouble *position, + gdouble *max_size) +{ + GimpRulerPrivate *priv; + + g_return_if_fail (GIMP_IS_RULER (ruler)); + + priv = GIMP_RULER_GET_PRIVATE (ruler); + + if (lower) + *lower = priv->lower; + if (upper) + *upper = priv->upper; + if (position) + *position = priv->position; + if (max_size) + *max_size = priv->max_size; +} + +void +gimp_ruler_draw_ticks (GimpRuler *ruler) +{ + g_return_if_fail (GIMP_IS_RULER (ruler)); + + if (GIMP_RULER_GET_CLASS (ruler)->draw_ticks) + GIMP_RULER_GET_CLASS (ruler)->draw_ticks (ruler); +} + +void +gimp_ruler_draw_pos (GimpRuler *ruler) +{ + g_return_if_fail (GIMP_IS_RULER (ruler)); + + if (GIMP_RULER_GET_CLASS (ruler)->draw_pos) + GIMP_RULER_GET_CLASS (ruler)->draw_pos (ruler); +} + + +GdkDrawable * +_gimp_ruler_get_backing_store (GimpRuler *ruler) +{ + return GIMP_RULER_GET_PRIVATE (ruler)->backing_store; +} + +GimpRulerMetric * +_gimp_ruler_get_metric (GimpRuler *ruler) +{ + return GIMP_RULER_GET_PRIVATE (ruler)->metric; +} + +static void +gimp_ruler_realize (GtkWidget *widget) +{ + GimpRuler *ruler = GIMP_RULER (widget); + GdkWindowAttr attributes; + gint attributes_mask; + + GTK_WIDGET_SET_FLAGS (ruler, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, ruler); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); + + gimp_ruler_make_pixmap (ruler); +} + +static void +gimp_ruler_unrealize (GtkWidget *widget) +{ + GimpRuler *ruler = GIMP_RULER (widget); + GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler); + + if (priv->backing_store) + { + g_object_unref (priv->backing_store); + priv->backing_store = NULL; + } + + if (priv->non_gr_exp_gc) + { + g_object_unref (priv->non_gr_exp_gc); + priv->non_gr_exp_gc = NULL; + } + + if (GTK_WIDGET_CLASS (gimp_ruler_parent_class)->unrealize) + (* GTK_WIDGET_CLASS (gimp_ruler_parent_class)->unrealize) (widget); +} + +static void +gimp_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GimpRuler *ruler = GIMP_RULER (widget); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gimp_ruler_make_pixmap (ruler); + } +} + +static gint +gimp_ruler_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + if (GTK_WIDGET_DRAWABLE (widget)) + { + GimpRuler *ruler = GIMP_RULER (widget); + GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler); + + gimp_ruler_draw_ticks (ruler); + + gdk_draw_drawable (widget->window, + priv->non_gr_exp_gc, + priv->backing_store, + 0, 0, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gimp_ruler_draw_pos (ruler); + } + + return FALSE; +} + +static void +gimp_ruler_make_pixmap (GimpRuler *ruler) +{ + GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler); + GtkWidget *widget = GTK_WIDGET (ruler); + gint width; + gint height; + + + if (priv->backing_store) + { + gdk_drawable_get_size (priv->backing_store, &width, &height); + if ((width == widget->allocation.width) && + (height == widget->allocation.height)) + return; + + g_object_unref (priv->backing_store); + } + + priv->backing_store = gdk_pixmap_new (widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + + if (!priv->non_gr_exp_gc) + { + priv->non_gr_exp_gc = gdk_gc_new (widget->window); + gdk_gc_set_exposures (priv->non_gr_exp_gc, FALSE); + } +} diff --git a/libgimpwidgets/gimpruler.h b/libgimpwidgets/gimpruler.h new file mode 100644 index 0000000000..d987f4c33d --- /dev/null +++ b/libgimpwidgets/gimpruler.h @@ -0,0 +1,91 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_RULER_H__ +#define __GIMP_RULER_H__ + + +G_BEGIN_DECLS + +#define GIMP_TYPE_RULER (gimp_ruler_get_type ()) +#define GIMP_RULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_RULER, GimpRuler)) +#define GIMP_RULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_RULER, GimpRulerClass)) +#define GIMP_IS_RULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_RULER)) +#define GIMP_IS_RULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_RULER)) +#define GIMP_RULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_RULER, GimpRulerClass)) + + +typedef struct _GimpRulerClass GimpRulerClass; +typedef struct _GimpRulerMetric GimpRulerMetric; + +struct _GimpRuler +{ + GtkWidget parent_instance; +}; + +struct _GimpRulerClass +{ + GtkWidgetClass parent_class; + + void (* draw_ticks) (GimpRuler *ruler); + void (* draw_pos) (GimpRuler *ruler); + + /* Padding for future expansion */ + void (*_gimp_reserved1) (void); + void (*_gimp_reserved2) (void); + void (*_gimp_reserved3) (void); + void (*_gimp_reserved4) (void); +}; + +struct _GimpRulerMetric +{ + gchar *metric_name; + gchar *abbrev; + /* This should be points_per_unit. This is the size of the unit + * in 1/72nd's of an inch and has nothing to do with screen pixels */ + gdouble pixels_per_unit; + gdouble ruler_scale[10]; + gint subdivide[5]; /* five possible modes of subdivision */ +}; + + +GType gimp_ruler_get_type (void) G_GNUC_CONST; +void gimp_ruler_set_metric (GimpRuler *ruler, + GtkMetricType metric); +void gimp_ruler_set_range (GimpRuler *ruler, + gdouble lower, + gdouble upper, + gdouble position, + gdouble max_size); +void gimp_ruler_draw_ticks (GimpRuler *ruler); +void gimp_ruler_draw_pos (GimpRuler *ruler); + +GtkMetricType gimp_ruler_get_metric (GimpRuler *ruler); +void gimp_ruler_get_range (GimpRuler *ruler, + gdouble *lower, + gdouble *upper, + gdouble *position, + gdouble *max_size); + +GdkDrawable * _gimp_ruler_get_backing_store (GimpRuler *ruler) G_GNUC_INTERNAL; +GimpRulerMetric * _gimp_ruler_get_metric (GimpRuler *ruler) G_GNUC_INTERNAL; + +G_END_DECLS + +#endif /* __GIMP_RULER_H__ */ diff --git a/libgimpwidgets/gimpvruler.c b/libgimpwidgets/gimpvruler.c new file mode 100644 index 0000000000..525fee1e45 --- /dev/null +++ b/libgimpwidgets/gimpvruler.c @@ -0,0 +1,329 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include "libgimpmath/gimpmath.h" + +#include "gimpwidgetstypes.h" + +#include "gimpvruler.h" + + +#define RULER_WIDTH 14 +#define MINIMUM_INCR 5 +#define MAXIMUM_SUBDIVIDE 5 +#define MAXIMUM_SCALES 10 + + +typedef struct +{ + gint xsrc; + gint ysrc; +} GimpVRulerPrivate; + + +static gint gimp_vruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gimp_vruler_draw_ticks (GimpRuler *ruler); +static void gimp_vruler_draw_pos (GimpRuler *ruler); + +G_DEFINE_TYPE (GimpVRuler, gimp_vruler, GIMP_TYPE_RULER) + +#define GIMP_VRULER_GET_PRIVATE(ruler) \ + G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_VRULER, GimpVRulerPrivate) + + + +static void +gimp_vruler_class_init (GimpVRulerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GimpRulerClass *ruler_class = GIMP_RULER_CLASS (klass); + + widget_class->motion_notify_event = gimp_vruler_motion_notify; + + ruler_class->draw_ticks = gimp_vruler_draw_ticks; + ruler_class->draw_pos = gimp_vruler_draw_pos; + + g_type_class_add_private (object_class, sizeof (GimpVRulerPrivate)); +} + +static void +gimp_vruler_init (GimpVRuler *vruler) +{ + GtkWidget *widget = GTK_WIDGET (vruler); + + widget->requisition.width = widget->style->xthickness * 2 + RULER_WIDTH; + widget->requisition.height = widget->style->ythickness * 2 + 1; +} + +GtkWidget* +gimp_vruler_new (void) +{ + return g_object_new (GIMP_TYPE_VRULER, NULL); +} + + +static gint +gimp_vruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GimpRuler *ruler = GIMP_RULER (widget); + gdouble lower; + gdouble upper; + gdouble position; + gint y; + + gdk_event_request_motions (event); + y = event->y; + + gimp_ruler_get_range (ruler, &lower, &upper, NULL, NULL); + + position = lower + ((upper - lower) * y) / widget->allocation.height; + g_object_set (ruler, "position", position, NULL); + + gimp_ruler_draw_pos (ruler); + + return FALSE; +} + +static void +gimp_vruler_draw_ticks (GimpRuler *ruler) +{ + GtkWidget *widget = GTK_WIDGET (ruler); + GimpRulerMetric *metric; + GdkDrawable *backing_store; + cairo_t *cr; + gint i, j; + gint width, height; + gint xthickness; + gint ythickness; + gint length, ideal_length; + gdouble lower, upper; /* Upper and lower limits, in ruler units */ + gdouble increment; /* Number of pixels per unit */ + gint scale; /* Number of units per major unit */ + gdouble subd_incr; + gdouble start, end, cur; + gchar unit_str[32]; + gint digit_height; + gint digit_offset; + gint text_height; + gint pos; + gdouble max_size; + PangoLayout *layout; + PangoRectangle logical_rect, ink_rect; + + if (! GTK_WIDGET_DRAWABLE (widget)) + return; + + backing_store = _gimp_ruler_get_backing_store (ruler); + + xthickness = widget->style->xthickness; + ythickness = widget->style->ythickness; + + layout = gtk_widget_create_pango_layout (widget, "012456789"); + pango_layout_get_extents (layout, &ink_rect, &logical_rect); + + digit_height = PANGO_PIXELS (ink_rect.height) + 2; + digit_offset = ink_rect.y; + + width = widget->allocation.height; + height = widget->allocation.width - ythickness * 2; + + gtk_paint_box (widget->style, backing_store, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "vruler", + 0, 0, + widget->allocation.width, widget->allocation.height); + + cr = gdk_cairo_create (backing_store); + gdk_cairo_set_source_color (cr, &widget->style->fg[widget->state]); + + cairo_rectangle (cr, + height + xthickness, + ythickness, + 1, + widget->allocation.height - 2 * ythickness); + + gimp_ruler_get_range (ruler, &lower, &upper, NULL, &max_size); + + metric = _gimp_ruler_get_metric (ruler); + + upper = upper / metric->pixels_per_unit; + lower = lower / metric->pixels_per_unit; + + if ((upper - lower) == 0) + goto out; + + increment = (gdouble) width / (upper - lower); + + /* determine the scale + * use the maximum extents of the ruler to determine the largest + * possible number to be displayed. Calculate the height in pixels + * of this displayed text. Use this height to find a scale which + * leaves sufficient room for drawing the ruler. + */ + scale = ceil (max_size / metric->pixels_per_unit); + g_snprintf (unit_str, sizeof (unit_str), "%d", scale); + text_height = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < MAXIMUM_SCALES; scale++) + if (metric->ruler_scale[scale] * fabs(increment) > 2 * text_height) + break; + + if (scale == MAXIMUM_SCALES) + scale = MAXIMUM_SCALES - 1; + + /* drawing starts here */ + length = 0; + for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--) + { + subd_incr = (gdouble) metric->ruler_scale[scale] / + (gdouble) metric->subdivide[i]; + if (subd_incr * fabs(increment) <= MINIMUM_INCR) + continue; + + /* Calculate the length of the tickmarks. Make sure that + * this length increases for each set of ticks + */ + ideal_length = height / (i + 1) - 1; + if (ideal_length > ++length) + length = ideal_length; + + if (lower < upper) + { + start = floor (lower / subd_incr) * subd_incr; + end = ceil (upper / subd_incr) * subd_incr; + } + else + { + start = floor (upper / subd_incr) * subd_incr; + end = ceil (lower / subd_incr) * subd_incr; + } + + for (cur = start; cur <= end; cur += subd_incr) + { + pos = ROUND ((cur - lower) * increment); + + cairo_rectangle (cr, + height + xthickness - length, pos, + length, 1); + + /* draw label */ + if (i == 0) + { + g_snprintf (unit_str, sizeof (unit_str), "%d", (int) cur); + + for (j = 0; j < (int) strlen (unit_str); j++) + { + pango_layout_set_text (layout, unit_str + j, 1); + pango_layout_get_extents (layout, NULL, &logical_rect); + + + gtk_paint_layout (widget->style, + backing_store, + GTK_WIDGET_STATE (widget), + FALSE, + NULL, + widget, + "vruler", + xthickness + 1, + pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset), + layout); + } + } + } + } + + cairo_fill (cr); +out: + cairo_destroy (cr); + + g_object_unref (layout); +} + + +static void +gimp_vruler_draw_pos (GimpRuler *ruler) +{ + GtkWidget *widget = GTK_WIDGET (ruler); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + GimpVRulerPrivate *priv = GIMP_VRULER_GET_PRIVATE (ruler); + gint x, y; + gint width, height; + gint bs_width, bs_height; + gint xthickness; + gint ythickness; + + xthickness = widget->style->xthickness; + ythickness = widget->style->ythickness; + width = widget->allocation.width - xthickness * 2; + height = widget->allocation.height; + + bs_height = width / 2 + 2; + bs_height |= 1; /* make sure it's odd */ + bs_width = bs_height / 2 + 1; + + if ((bs_width > 0) && (bs_height > 0)) + { + GdkDrawable *backing_store = _gimp_ruler_get_backing_store (ruler); + cairo_t *cr = gdk_cairo_create (widget->window); + gdouble lower; + gdouble upper; + gdouble position; + gdouble increment; + + /* If a backing store exists, restore the ruler */ + if (backing_store) + gdk_draw_drawable (widget->window, + widget->style->black_gc, + backing_store, + priv->xsrc, priv->ysrc, + priv->xsrc, priv->ysrc, + bs_width, bs_height); + + gimp_ruler_get_range (ruler, &lower, &upper, &position, NULL); + + increment = (gdouble) height / (upper - lower); + + x = (width + bs_width) / 2 + xthickness; + y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1; + + gdk_cairo_set_source_color (cr, &widget->style->fg[widget->state]); + + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + bs_width, y + bs_height / 2.); + cairo_line_to (cr, x, y + bs_height); + cairo_fill (cr); + + cairo_destroy (cr); + + priv->xsrc = x; + priv->ysrc = y; + } + } +} diff --git a/libgimpwidgets/gimpvruler.h b/libgimpwidgets/gimpvruler.h new file mode 100644 index 0000000000..fcde3855a4 --- /dev/null +++ b/libgimpwidgets/gimpvruler.h @@ -0,0 +1,49 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_VRULER_H__ +#define __GIMP_VRULER_H__ + +#include "gimpruler.h" + + +G_BEGIN_DECLS + + +#define GIMP_TYPE_VRULER (gimp_vruler_get_type ()) +#define GIMP_VRULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VRULER, GimpVRuler)) +#define GIMP_VRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VRULER, GimpVRulerClass)) +#define GIMP_IS_VRULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VRULER)) +#define GIMP_IS_VRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_VRULER)) +#define GIMP_VRULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_VRULER, GimpVRulerClass)) + + +typedef GimpRulerClass GimpVRulerClass; +typedef GimpRuler GimpVRuler; + + +GType gimp_vruler_get_type (void) G_GNUC_CONST; +GtkWidget* gimp_vruler_new (void); + + +G_END_DECLS + + +#endif /* __GIMP_VRULER_H__ */ + diff --git a/libgimpwidgets/gimpwidgets.def b/libgimpwidgets/gimpwidgets.def index e548c83082..de92098f66 100644 --- a/libgimpwidgets/gimpwidgets.def +++ b/libgimpwidgets/gimpwidgets.def @@ -157,6 +157,8 @@ EXPORTS gimp_help_set_help_data_with_markup gimp_hint_box_get_type gimp_hint_box_new + gimp_hruler_get_type + gimp_hruler_new gimp_int_adjustment_update gimp_int_combo_box_append gimp_int_combo_box_connect @@ -301,6 +303,13 @@ EXPORTS gimp_radio_group_new2 gimp_radio_group_set_active gimp_random_seed_new + gimp_ruler_draw_pos + gimp_ruler_draw_ticks + gimp_ruler_get_metric + gimp_ruler_get_range + gimp_ruler_get_type + gimp_ruler_set_metric + gimp_ruler_set_range gimp_scale_entry_get_logarithmic gimp_scale_entry_new gimp_scale_entry_set_logarithmic @@ -349,6 +358,8 @@ EXPORTS gimp_unit_menu_set_pixel_digits gimp_unit_menu_set_unit gimp_unit_menu_update + gimp_vruler_get_type + gimp_vruler_new gimp_widgets_init gimp_zoom_button_new gimp_zoom_model_get_factor diff --git a/libgimpwidgets/gimpwidgets.h b/libgimpwidgets/gimpwidgets.h index 422eb7ea50..ac19bbf7fc 100644 --- a/libgimpwidgets/gimpwidgets.h +++ b/libgimpwidgets/gimpwidgets.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -67,12 +68,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include diff --git a/libgimpwidgets/gimpwidgetstypes.h b/libgimpwidgets/gimpwidgetstypes.h index d03eb2b434..254049af55 100644 --- a/libgimpwidgets/gimpwidgetstypes.h +++ b/libgimpwidgets/gimpwidgetstypes.h @@ -67,6 +67,7 @@ typedef struct _GimpPickButton GimpPickButton; typedef struct _GimpPreview GimpPreview; typedef struct _GimpPreviewArea GimpPreviewArea; typedef struct _GimpPixmap GimpPixmap; +typedef struct _GimpRuler GimpRuler; typedef struct _GimpScrolledPreview GimpScrolledPreview; typedef struct _GimpSizeEntry GimpSizeEntry; typedef struct _GimpStringComboBox GimpStringComboBox; diff --git a/plug-ins/gfig/gfig-preview.c b/plug-ins/gfig/gfig-preview.c index b4c5394d8e..cb2cd657bc 100644 --- a/plug-ins/gfig/gfig-preview.c +++ b/plug-ins/gfig/gfig-preview.c @@ -99,8 +99,8 @@ make_preview (void) GTK_FILL , GTK_FILL , 0, 0); gtk_container_add (GTK_CONTAINER (frame), table); - ruler = gtk_hruler_new (); - gtk_ruler_set_range (GTK_RULER (ruler), 0, preview_width, 0, PREVIEW_SIZE); + ruler = gimp_hruler_new (); + gimp_ruler_set_range (GIMP_RULER (ruler), 0, preview_width, 0, PREVIEW_SIZE); g_signal_connect_swapped (gfig_context->preview, "motion-notify-event", G_CALLBACK (GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (ruler))->motion_notify_event), ruler); @@ -108,8 +108,8 @@ make_preview (void) GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (ruler); - ruler = gtk_vruler_new (); - gtk_ruler_set_range (GTK_RULER (ruler), 0, preview_height, 0, PREVIEW_SIZE); + ruler = gimp_vruler_new (); + gimp_ruler_set_range (GIMP_RULER (ruler), 0, preview_height, 0, PREVIEW_SIZE); g_signal_connect_swapped (gfig_context->preview, "motion-notify-event", G_CALLBACK (GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (ruler))->motion_notify_event), ruler); diff --git a/plug-ins/imagemap/imap_preview.c b/plug-ins/imagemap/imap_preview.c index 79f2dea9b7..397e71547c 100644 --- a/plug-ins/imagemap/imap_preview.c +++ b/plug-ins/imagemap/imap_preview.c @@ -411,9 +411,9 @@ static void scroll_adj_changed (GtkAdjustment *adj, GtkRuler *ruler) { - gtk_ruler_set_range (ruler, - adj->value, adj->value + adj->page_size, - G_MAXDOUBLE, adj->page_size); + gimp_ruler_set_range (ruler, + adj->value, adj->value + adj->page_size, + G_MAXDOUBLE, adj->page_size); } Preview_t* @@ -474,7 +474,7 @@ make_preview(GimpDrawable *drawable) gtk_widget_show(arrow); /* Create horizontal ruler */ - data->hruler = ruler = gtk_hruler_new(); + data->hruler = ruler = gimp_hruler_new(); g_signal_connect_swapped(preview, "motion-notify-event", G_CALLBACK(GTK_WIDGET_GET_CLASS(ruler)->motion_notify_event), ruler); @@ -484,7 +484,7 @@ make_preview(GimpDrawable *drawable) gtk_widget_show(ruler); /* Create vertical ruler */ - data->vruler = ruler = gtk_vruler_new(); + data->vruler = ruler = gimp_vruler_new(); g_signal_connect_swapped(preview, "motion-notify-event", G_CALLBACK(GTK_WIDGET_GET_CLASS(ruler)->motion_notify_event), ruler);