talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit 442281491ccc785eb47243caa525dfd71588c28a
parent 5370d75fe2c88c0147ef8309e6fb646ffa855c38
Author: Colin Leroy <colin@colino.net>
Date:   Mon, 17 Oct 2011 09:01:28 +0000

2011-10-17 [colin]	3.7.10cvs32

	* src/compose.c
	* src/compose.h
	* src/gtk/Makefile.am
	* src/gtk/gtkshruler.c
	* src/gtk/gtkshruler.h
	* src/gtk/gtkunit.c
	* src/gtk/gtkunit.h
		Reimplement ruler using the GTK widgets. Thanks
		to Hanno for the initial patch.

Diffstat:
MChangeLog | 12++++++++++++
MPATCHSETS | 1+
Mconfigure.ac | 2+-
Msrc/compose.c | 37+++++--------------------------------
Msrc/compose.h | 2--
Msrc/gtk/Makefile.am | 6++++--
Msrc/gtk/gtkshruler.c | 1269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/gtk/gtkshruler.h | 75+++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Asrc/gtk/gtkunit.c | 699+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtkunit.h | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 2068 insertions(+), 193 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,15 @@ +2011-10-17 [colin] 3.7.10cvs32 + + * src/compose.c + * src/compose.h + * src/gtk/Makefile.am + * src/gtk/gtkshruler.c + * src/gtk/gtkshruler.h + * src/gtk/gtkunit.c + * src/gtk/gtkunit.h + Reimplement ruler using the GTK widgets. Thanks + to Hanno for the initial patch. + 2011-10-17 [colin] 3.7.10cvs31 * src/action.c diff --git a/PATCHSETS b/PATCHSETS @@ -4235,3 +4235,4 @@ ( cvs diff -u -r 1.1.2.57 -r 1.1.2.58 manual/advanced.xml; ) > 3.7.10cvs29.patchset ( cvs diff -u -r 1.115.2.239 -r 1.115.2.240 src/main.c; ) > 3.7.10cvs30.patchset ( cvs diff -u -r 1.12.2.69 -r 1.12.2.70 src/action.c; cvs diff -u -r 1.115.2.240 -r 1.115.2.241 src/main.c; cvs diff -u -r 1.5.2.98 -r 1.5.2.99 src/gtk/gtkutils.c; cvs diff -u -r 1.4.2.60 -r 1.4.2.61 src/gtk/gtkutils.h; ) > 3.7.10cvs31.patchset +( cvs diff -u -r 1.382.2.585 -r 1.382.2.586 src/compose.c; cvs diff -u -r 1.50.2.63 -r 1.50.2.64 src/compose.h; cvs diff -u -r 1.20.2.27 -r 1.20.2.28 src/gtk/Makefile.am; cvs diff -u -r 1.1.4.17 -r 1.1.4.18 src/gtk/gtkshruler.c; cvs diff -u -r 1.1.4.10 -r 1.1.4.11 src/gtk/gtkshruler.h; diff -u /dev/null src/gtk/gtkunit.c; diff -u /dev/null src/gtk/gtkunit.h; ) > 3.7.10cvs32.patchset diff --git a/configure.ac b/configure.ac @@ -12,7 +12,7 @@ MINOR_VERSION=7 MICRO_VERSION=10 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=31 +EXTRA_VERSION=32 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/compose.c b/src/compose.c @@ -83,12 +83,10 @@ #include "codeconv.h" #include "utils.h" #include "gtkutils.h" +#include "gtkshruler.h" #include "socket.h" #include "alertpanel.h" #include "manage_window.h" -#if !GTK_CHECK_VERSION(2, 24, 0) -#include "gtkshruler.h" -#endif #include "folder.h" #include "addr_compl.h" #include "quote_fmt.h" @@ -353,11 +351,9 @@ static void compose_add_field_list ( Compose *compose, /* callback functions */ -#if !GTK_CHECK_VERSION(2, 24, 0) static gboolean compose_edit_size_alloc (GtkEditable *widget, GtkAllocation *allocation, GtkSHRuler *shruler); -#endif static void account_activated (GtkComboBox *optmenu, gpointer data); static void attach_selected (GtkTreeView *tree_view, @@ -441,10 +437,8 @@ static void compose_toggle_autowrap_cb (GtkToggleAction *action, static void compose_toggle_autoindent_cb(GtkToggleAction *action, gpointer data); -#if !GTK_CHECK_VERSION(2, 24, 0) static void compose_toggle_ruler_cb (GtkToggleAction *action, gpointer data); -#endif static void compose_toggle_sign_cb (GtkToggleAction *action, gpointer data); static void compose_toggle_encrypt_cb (GtkToggleAction *action, @@ -674,9 +668,7 @@ static GtkToggleActionEntry compose_toggle_entries[] = {"Options/Encrypt", NULL, N_("_Encrypt"), NULL, NULL, G_CALLBACK(compose_toggle_encrypt_cb) }, /* Toggle */ {"Options/RequestRetRcpt", NULL, N_("_Request Return Receipt"), NULL, NULL, G_CALLBACK(compose_toggle_return_receipt_cb) }, /* TOGGLE */ {"Options/RemoveReferences", NULL, N_("Remo_ve references"), NULL, NULL, G_CALLBACK(compose_toggle_remove_refs_cb) }, /* TOGGLE */ -#if !GTK_CHECK_VERSION(2, 24, 0) {"Tools/ShowRuler", NULL, N_("Show _ruler"), NULL, NULL, G_CALLBACK(compose_toggle_ruler_cb) }, /* Toggle */ -#endif }; static GtkRadioActionEntry compose_radio_rm_entries[] = @@ -2436,9 +2428,7 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo, cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE); cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE); cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE); -#if !GTK_CHECK_VERSION(2, 24, 0) cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE); -#endif cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/Actions", FALSE); if (compose->toolbar->draft_btn) @@ -7084,10 +7074,8 @@ static Compose *compose_create(PrefsAccount *account, GtkWidget *paned; GtkWidget *edit_vbox; -#if !GTK_CHECK_VERSION(2, 24, 0) GtkWidget *ruler_hbox; GtkWidget *ruler; -#endif GtkWidget *scrolledwin; GtkWidget *text; GtkTextBuffer *buffer; @@ -7343,9 +7331,7 @@ static Compose *compose_create(PrefsAccount *account, /* phew. */ /* Tools menu */ -#if !GTK_CHECK_VERSION(2, 24, 0) MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools", "ShowRuler", "Tools/ShowRuler", GTK_UI_MANAGER_MENUITEM) -#endif MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools", "AddressBook", "Tools/AddressBook", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools", "Template", "Tools/Template", GTK_UI_MANAGER_MENU) MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools/Template", "PlaceHolder", "Tools/Template/PlaceHolder", GTK_UI_MANAGER_MENUITEM) @@ -7447,16 +7433,14 @@ static Compose *compose_create(PrefsAccount *account, gtk_box_pack_start(GTK_BOX(edit_vbox), subject_hbox, FALSE, FALSE, 0); -#if !GTK_CHECK_VERSION(2, 24, 0) /* ruler */ ruler_hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(edit_vbox), ruler_hbox, FALSE, FALSE, 0); - ruler = gtk_shruler_new(); - gtk_ruler_set_range(GTK_RULER(ruler), 0.0, 100.0, 1.0, 100.0); + ruler = gtk_shruler_new(GTK_ORIENTATION_HORIZONTAL); + gtk_shruler_set_range(GTK_SHRULER(ruler), 0.0, 100.0, 1.0); gtk_box_pack_start(GTK_BOX(ruler_hbox), ruler, TRUE, TRUE, BORDER_WIDTH); -#endif /* text widget */ scrolledwin = gtk_scrolled_window_new(NULL, NULL); @@ -7480,11 +7464,9 @@ static Compose *compose_create(PrefsAccount *account, gtk_text_buffer_add_selection_clipboard(buffer, clipboard); gtk_container_add(GTK_CONTAINER(scrolledwin), text); -#if !GTK_CHECK_VERSION(2, 24, 0) g_signal_connect_after(G_OBJECT(text), "size_allocate", G_CALLBACK(compose_edit_size_alloc), ruler); -#endif g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(compose_changed_cb), compose); g_signal_connect(G_OBJECT(text), "grab_focus", @@ -7578,10 +7560,8 @@ static Compose *compose_create(PrefsAccount *account, compose->notebook = notebook; compose->edit_vbox = edit_vbox; -#if !GTK_CHECK_VERSION(2, 24, 0) compose->ruler_hbox = ruler_hbox; compose->ruler = ruler; -#endif compose->scrolledwin = scrolledwin; compose->text = text; @@ -7700,12 +7680,10 @@ static Compose *compose_create(PrefsAccount *account, compose_list = g_list_append(compose_list, compose); -#if !GTK_CHECK_VERSION(2, 24, 0) if (!prefs_common.show_ruler) gtk_widget_hide(ruler_hbox); cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Tools/ShowRuler", prefs_common.show_ruler); -#endif /* Priority */ compose->priority = PRIORITY_NORMAL; @@ -9149,7 +9127,6 @@ static void compose_undo_state_changed(UndoMain *undostruct, gint undo_state, * includes "non-client" (windows-izm) in calculation, so this calculation * may not be accurate. */ -#if !GTK_CHECK_VERSION(2, 24, 0) static gboolean compose_edit_size_alloc(GtkEditable *widget, GtkAllocation *allocation, GtkSHRuler *shruler) @@ -9164,14 +9141,12 @@ static gboolean compose_edit_size_alloc(GtkEditable *widget, (allocation->width - allocation->x) / char_width; /* got the maximum */ - gtk_ruler_set_range(GTK_RULER(shruler), - 0.0, line_width_in_chars, 0, - /*line_width_in_chars*/ char_width); + gtk_shruler_set_range(GTK_SHRULER(shruler), + 0.0, line_width_in_chars, 0); } return TRUE; } -#endif typedef struct { gchar *header; @@ -10593,7 +10568,6 @@ static void activate_privacy_system(Compose *compose, PrefsAccount *account, gbo compose_update_privacy_system_menu_item(compose, warn); } -#if !GTK_CHECK_VERSION(2, 24, 0) static void compose_toggle_ruler_cb(GtkToggleAction *action, gpointer data) { Compose *compose = (Compose *)data; @@ -10607,7 +10581,6 @@ static void compose_toggle_ruler_cb(GtkToggleAction *action, gpointer data) prefs_common.show_ruler = FALSE; } } -#endif static void compose_attach_drag_received_cb (GtkWidget *widget, GdkDragContext *context, diff --git a/src/compose.h b/src/compose.h @@ -133,10 +133,8 @@ struct _Compose /* Textedit */ GtkWidget *edit_vbox; -#if !GTK_CHECK_VERSION(3, 0, 0) GtkWidget *ruler_hbox; GtkWidget *ruler; -#endif GtkWidget *scrolledwin; GtkWidget *text; GtkWidget *from_name; diff --git a/src/gtk/Makefile.am b/src/gtk/Makefile.am @@ -11,8 +11,7 @@ gtk2_sources = \ gtkcmctree.c \ gtkcmclist.c \ gtkcmoptionmenu.c \ - gtksctree.c \ - gtkshruler.c + gtksctree.c endif libclawsgtk_la_SOURCES = \ @@ -24,7 +23,9 @@ libclawsgtk_la_SOURCES = \ filesel.c \ foldersort.c \ gtkaspell.c \ + gtkunit.c \ $(gtk2_sources) \ + gtkshruler.c \ gtkutils.c \ gtkvscrollbutton.c \ icon_legend.c \ @@ -52,6 +53,7 @@ clawsgtkinclude_HEADERS = \ foldersort.h \ gtkaspell.h \ gtkutils.h \ + gtkunit.h \ gtkvscrollbutton.h \ headers.h \ icon_legend.h \ diff --git a/src/gtk/gtkshruler.c b/src/gtk/gtkshruler.c @@ -1,184 +1,1197 @@ -/* GtkSHRuler +/* LIBGTK - The GTK Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * - * Copyright (C) 2000-2011 Alfons Hoogervorst & The Claws Mail Team - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * 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 3 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 - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - */ - -/* I derived this class from hruler. S in HRuler could be read as - * Sylpheed (sylpheed.good-day.net), but also [S]ettable HRuler. - * I basically ripped apart the draw_ticks member of HRuler; it - * now draws the ticks at ruler->max_size. so gtk_ruler_set_range's - * last parameter has the distance between two ticks (which is - * the width of the fixed font character! - * - * -- Alfons + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. */ +#include "config.h" + #include <math.h> -#include <stdio.h> #include <string.h> + #include <gtk/gtk.h> + #include "gtkshruler.h" -#include "utils.h" -#include "gtkutils.h" +#include "gtkunit.h" -#if !GTK_CHECK_VERSION(2,24,0) +#define ROUND(x) ((int) ((x) + 0.5)) + +/** + * SECTION: gimpparam + * @title: gimpparam + * @short_description: Definitions of useful #GParamFlags. + * + * Definitions of useful #GParamFlags. + **/ -#define RULER_HEIGHT 14 -#define MINIMUM_INCR 5 -#define MAXIMUM_SUBDIVIDE 5 -#define MAXIMUM_SCALES 10 -#define ROUND(x) ((int) ((x) + 0.5)) +/** + * GTK_PARAM_STATIC_STRINGS: + * + * Since: GTK 2.4 + **/ +#define GTK_PARAM_STATIC_STRINGS (G_PARAM_STATIC_NAME | \ + G_PARAM_STATIC_NICK | \ + G_PARAM_STATIC_BLURB) + +/** + * GTK_PARAM_READABLE: + * + * Since: GTK 2.4 + **/ +#define GTK_PARAM_READABLE (G_PARAM_READABLE | \ + GTK_PARAM_STATIC_STRINGS) + +/** + * GTK_PARAM_WRITABLE: + * + * Since: GTK 2.4 + **/ +#define GTK_PARAM_WRITABLE (G_PARAM_WRITABLE | \ + GTK_PARAM_STATIC_STRINGS) + +/** + * GTK_PARAM_READWRITE: + * + * Since: GTK 2.4 + **/ +#define GTK_PARAM_READWRITE (G_PARAM_READWRITE | \ + GTK_PARAM_STATIC_STRINGS) + + +/** + * SECTION: gimpruler + * @title: GtkSHRuler + * @short_description: A ruler widget with configurable unit and orientation. + * + * A ruler widget with configurable unit and orientation. + **/ + + +#define DEFAULT_RULER_FONT_SCALE PANGO_SCALE_SMALL +#define MINIMUM_INCR 5 + + +enum +{ + PROP_0, + PROP_ORIENTATION, + PROP_UNIT, + PROP_LOWER, + PROP_UPPER, + PROP_POSITION, + PROP_MAX_SIZE +}; + + +/* 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 +{ + GtkOrientation orientation; + GtkCMUnit unit; + gdouble lower; + gdouble upper; + gdouble position; + gdouble max_size; + + GdkWindow *input_window; + cairo_surface_t *backing_store; + PangoLayout *layout; + gdouble font_scale; + + gint xsrc; + gint ysrc; + + GList *track_widgets; +} GtkSHRulerPrivate; + +#define GTK_SHRULER_GET_PRIVATE(ruler) \ + G_TYPE_INSTANCE_GET_PRIVATE (ruler, GTK_TYPE_SHRULER, GtkSHRulerPrivate) + + +static const struct +{ + const gdouble ruler_scale[16]; + const gint subdivide[3]; +} ruler_metric = +{ + { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000 }, + { 1, 5, 10 } +}; + + +static void gtk_shruler_dispose (GObject *object); +static void gtk_shruler_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_shruler_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void gtk_shruler_realize (GtkWidget *widget); +static void gtk_shruler_unrealize (GtkWidget *widget); +static void gtk_shruler_map (GtkWidget *widget); +static void gtk_shruler_unmap (GtkWidget *widget); +static void gtk_shruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_shruler_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_shruler_style_set (GtkWidget *widget, + GtkStyle *prev_style); +static gboolean gtk_shruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gboolean gtk_shruler_expose (GtkWidget *widget, + GdkEventExpose *event); + +static void gtk_shruler_draw_ticks (GtkSHRuler *ruler); +static void gtk_shruler_make_pixmap (GtkSHRuler *ruler); + +static PangoLayout * gtk_shruler_get_layout (GtkWidget *widget, + const gchar *text); + + +G_DEFINE_TYPE (GtkSHRuler, gtk_shruler, GTK_TYPE_WIDGET) + +#define parent_class gtk_shruler_parent_class + + +static void +gtk_shruler_class_init (GtkSHRulerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = gtk_shruler_dispose; + object_class->set_property = gtk_shruler_set_property; + object_class->get_property = gtk_shruler_get_property; + + widget_class->realize = gtk_shruler_realize; + widget_class->unrealize = gtk_shruler_unrealize; + widget_class->map = gtk_shruler_map; + widget_class->unmap = gtk_shruler_unmap; + widget_class->size_allocate = gtk_shruler_size_allocate; + widget_class->size_request = gtk_shruler_size_request; + widget_class->style_set = gtk_shruler_style_set; + widget_class->motion_notify_event = gtk_shruler_motion_notify; + widget_class->expose_event = gtk_shruler_expose; + + g_type_class_add_private (object_class, sizeof (GtkSHRulerPrivate)); + + g_object_class_install_property (object_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + "Orientation", + "The orientation of the ruler", + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_LOWER, + gtk_param_spec_unit ("unit", + "Unit", + "Unit of ruler", + TRUE, TRUE, + CM_UNIT_PIXEL, + GTK_PARAM_READWRITE)); + + 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, + GTK_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, + GTK_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, + GTK_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, + GTK_PARAM_READWRITE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_double ("font-scale", + NULL, NULL, + 0.0, + G_MAXDOUBLE, + DEFAULT_RULER_FONT_SCALE, + GTK_PARAM_READABLE)); +} + +static void +gtk_shruler_init (GtkSHRuler *ruler) +{ + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + + gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE); + + priv->orientation = GTK_ORIENTATION_HORIZONTAL; + priv->unit = GTK_PIXELS; + priv->lower = 0; + priv->upper = 0; + priv->position = 0; + priv->max_size = 0; + priv->backing_store = NULL; + priv->font_scale = DEFAULT_RULER_FONT_SCALE; +} + +static void +gtk_shruler_dispose (GObject *object) +{ + GtkSHRuler *ruler = GTK_SHRULER (object); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + + while (priv->track_widgets) + gtk_shruler_remove_track_widget (ruler, priv->track_widgets->data); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gtk_shruler_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkSHRuler *ruler = GTK_SHRULER (object); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + + switch (prop_id) + { + case PROP_ORIENTATION: + priv->orientation = g_value_get_enum (value); + gtk_widget_queue_resize (GTK_WIDGET (ruler)); + break; + + case PROP_UNIT: + gtk_shruler_set_unit (ruler, g_value_get_int (value)); + break; + + case PROP_LOWER: + gtk_shruler_set_range (ruler, + g_value_get_double (value), + priv->upper, + priv->max_size); + break; + case PROP_UPPER: + gtk_shruler_set_range (ruler, + priv->lower, + g_value_get_double (value), + priv->max_size); + break; + + case PROP_POSITION: + gtk_shruler_set_position (ruler, g_value_get_double (value)); + break; + + case PROP_MAX_SIZE: + gtk_shruler_set_range (ruler, + priv->lower, + priv->upper, + g_value_get_double (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_shruler_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkSHRuler *ruler = GTK_SHRULER (object); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + + switch (prop_id) + { + case PROP_ORIENTATION: + g_value_set_enum (value, priv->orientation); + break; + + case PROP_UNIT: + g_value_set_int (value, priv->unit); + break; + + 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; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * gtk_shruler_new: + * @orientation: the ruler's orientation. + * + * Creates a new ruler. + * + * Return value: a new #GtkSHRuler widget. + * + * Since: GTK 2.8 + **/ +GtkWidget * +gtk_shruler_new (GtkOrientation orientation) +{ + return g_object_new (GTK_TYPE_SHRULER, + "orientation", orientation, + NULL); +} + +static void +gtk_shruler_update_position (GtkSHRuler *ruler, + gdouble x, + gdouble y) +{ + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + gdouble lower; + gdouble upper; + + gtk_widget_get_allocation (GTK_WIDGET (ruler), &allocation); + gtk_shruler_get_range (ruler, &lower, &upper, NULL); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_shruler_set_position (ruler, + lower + + (upper - lower) * x / allocation.width); + } + else + { + gtk_shruler_set_position (ruler, + lower + + (upper - lower) * y / allocation.height); + } +} + +/* Returns TRUE if a translation should be done */ +static gboolean +gtk_widget_get_translation_to_window (GtkWidget *widget, + GdkWindow *window, + int *x, + int *y) +{ + GdkWindow *w, *widget_window; + + if (! gtk_widget_get_has_window (widget)) + { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + + *x = -allocation.x; + *y = -allocation.y; + } + else + { + *x = 0; + *y = 0; + } + + widget_window = gtk_widget_get_window (widget); + + for (w = window; + w && w != widget_window; + w = gdk_window_get_effective_parent (w)) + { + gdouble px, py; + + gdk_window_coords_to_parent (w, *x, *y, &px, &py); + + *x += px; + *y += py; + } + + if (w == NULL) + { + *x = 0; + *y = 0; + return FALSE; + } + + return TRUE; +} + +static void +gtk_shruler_event_to_widget_coords (GtkWidget *widget, + GdkWindow *window, + gdouble event_x, + gdouble event_y, + gint *widget_x, + gint *widget_y) +{ + gint tx, ty; + + if (gtk_widget_get_translation_to_window (widget, window, &tx, &ty)) + { + event_x += tx; + event_y += ty; + } + + *widget_x = event_x; + *widget_y = event_y; +} + +static gboolean +gtk_shruler_track_widget_motion_notify (GtkWidget *widget, + GdkEventMotion *mevent, + GtkSHRuler *ruler) +{ + gint widget_x; + gint widget_y; + gint ruler_x; + gint ruler_y; + + widget = gtk_get_event_widget ((GdkEvent *) mevent); + + gtk_shruler_event_to_widget_coords (widget, mevent->window, + mevent->x, mevent->y, + &widget_x, &widget_y); + + if (gtk_widget_translate_coordinates (widget, GTK_WIDGET (ruler), + widget_x, widget_y, + &ruler_x, &ruler_y)) + { + gtk_shruler_update_position (ruler, ruler_x, ruler_y); + } + + return FALSE; +} + +/** + * gtk_shruler_add_track_widget: + * @ruler: a #GtkSHRuler + * @widget: the track widget to add + * + * Adds a "track widget" to the ruler. The ruler will connect to + * GtkWidget:motion-notify-event: on the track widget and update its + * position marker accordingly. The marker is correctly updated also + * for the track widget's children, regardless of whether they are + * ordinary children of off-screen children. + * + * Since: GTK 2.8 + */ +void +gtk_shruler_add_track_widget (GtkSHRuler *ruler, + GtkWidget *widget) +{ + GtkSHRulerPrivate *priv; + + g_return_if_fail (GTK_IS_SHRULER (ruler)); + g_return_if_fail (GTK_IS_WIDGET (ruler)); + + priv = GTK_SHRULER_GET_PRIVATE (ruler); + + g_return_if_fail (g_list_find (priv->track_widgets, widget) == NULL); + + priv->track_widgets = g_list_prepend (priv->track_widgets, widget); + + g_signal_connect (widget, "motion-notify-event", + G_CALLBACK (gtk_shruler_track_widget_motion_notify), + ruler); + g_signal_connect_swapped (widget, "destroy", + G_CALLBACK (gtk_shruler_remove_track_widget), + ruler); +} + +/** + * gtk_shruler_remove_track_widget: + * @ruler: a #GtkSHRuler + * @widget: the track widget to remove + * + * Removes a previously added track widget from the ruler. See + * gtk_shruler_add_track_widget(). + * + * Since: GTK 2.8 + */ +void +gtk_shruler_remove_track_widget (GtkSHRuler *ruler, + GtkWidget *widget) +{ + GtkSHRulerPrivate *priv; + + g_return_if_fail (GTK_IS_SHRULER (ruler)); + g_return_if_fail (GTK_IS_WIDGET (ruler)); + + priv = GTK_SHRULER_GET_PRIVATE (ruler); + + g_return_if_fail (g_list_find (priv->track_widgets, widget) != NULL); + + priv->track_widgets = g_list_remove (priv->track_widgets, widget); + + g_signal_handlers_disconnect_by_func (widget, + gtk_shruler_track_widget_motion_notify, + ruler); + g_signal_handlers_disconnect_by_func (widget, + gtk_shruler_remove_track_widget, + ruler); +} + +/** + * gtk_shruler_set_unit: + * @ruler: a #GtkSHRuler + * @unit: the #GtkCMUnit to set the ruler to + * + * This sets the unit of the ruler. + * + * Since: GTK 2.8 + */ +void +gtk_shruler_set_unit (GtkSHRuler *ruler, + GtkCMUnit unit) +{ + GtkSHRulerPrivate *priv; + + g_return_if_fail (GTK_IS_SHRULER (ruler)); + + priv = GTK_SHRULER_GET_PRIVATE (ruler); + + if (priv->unit != unit) + { + priv->unit = unit; + g_object_notify (G_OBJECT (ruler), "unit"); + + gtk_widget_queue_draw (GTK_WIDGET (ruler)); + } +} -static void gtk_shruler_class_init (GtkSHRulerClass *klass); -static void gtk_shruler_init (GtkSHRuler *hruler); -static void gtk_shruler_draw_ticks (GtkRuler *ruler); +/** + * gtk_shruler_get_unit: + * @ruler: a #GtkSHRuler + * + * Return value: the unit currently used in the @ruler widget. + * + * Since: GTK 2.8 + **/ +GtkCMUnit +gtk_shruler_get_unit (GtkSHRuler *ruler) +{ + g_return_val_if_fail (GTK_IS_SHRULER (ruler), 0); -GType -gtk_shruler_get_type(void) + return GTK_SHRULER_GET_PRIVATE (ruler)->unit; +} + +/** + * gtk_shruler_set_position: + * @ruler: a #GtkSHRuler + * @position: the position to set the ruler to + * + * This sets the position of the ruler. + * + * Since: GTK 2.8 + */ +void +gtk_shruler_set_position (GtkSHRuler *ruler, + gdouble position) { - static GType shruler_type = 0; + GtkSHRulerPrivate *priv; - if ( !shruler_type ) { - static const GTypeInfo shruler_info = { - sizeof (GtkSHRulerClass), + g_return_if_fail (GTK_IS_SHRULER (ruler)); - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, + priv = GTK_SHRULER_GET_PRIVATE (ruler); - (GClassInitFunc) gtk_shruler_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ + if (priv->position != position) + { + priv->position = position; + g_object_notify (G_OBJECT (ruler), "position"); + } +} + +/** + * gtk_shruler_get_position: + * @ruler: a #GtkSHRuler + * + * Return value: the current position of the @ruler widget. + * + * Since: GTK 2.8 + **/ +gdouble +gtk_shruler_get_position (GtkSHRuler *ruler) +{ + g_return_val_if_fail (GTK_IS_SHRULER (ruler), 0.0); - sizeof (GtkSHRuler), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_shruler_init, - }; - /* inherit from GtkHRuler */ - shruler_type = g_type_register_static (GTK_TYPE_HRULER, "GtkSHRuler", &shruler_info, (GTypeFlags)0); - } - return shruler_type; + return GTK_SHRULER_GET_PRIVATE (ruler)->position; +} + +/** + * gtk_shruler_set_range: + * @ruler: a #GtkSHRuler + * @lower: the lower limit of the ruler + * @upper: the upper limit of 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: GTK 2.8 + */ +void +gtk_shruler_set_range (GtkSHRuler *ruler, + gdouble lower, + gdouble upper, + gdouble max_size) +{ + GtkSHRulerPrivate *priv; + + g_return_if_fail (GTK_IS_SHRULER (ruler)); + + priv = GTK_SHRULER_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->max_size != max_size) + { + priv->max_size = max_size; + g_object_notify (G_OBJECT (ruler), "max-size"); + } + g_object_thaw_notify (G_OBJECT (ruler)); + + gtk_widget_queue_draw (GTK_WIDGET (ruler)); +} + +/** + * gtk_shruler_get_range: + * @ruler: a #GtkSHRuler + * @lower: location to store lower limit of the ruler, or %NULL + * @upper: location to store upper limit of 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 #GtkSHRuler. + * See gtk_shruler_set_range(). + * + * Since: GTK 2.8 + **/ +void +gtk_shruler_get_range (GtkSHRuler *ruler, + gdouble *lower, + gdouble *upper, + gdouble *max_size) +{ + GtkSHRulerPrivate *priv; + + g_return_if_fail (GTK_IS_SHRULER (ruler)); + + priv = GTK_SHRULER_GET_PRIVATE (ruler); + + if (lower) + *lower = priv->lower; + if (upper) + *upper = priv->upper; + if (max_size) + *max_size = priv->max_size; } static void -gtk_shruler_class_init(GtkSHRulerClass * klass) +gtk_shruler_realize (GtkWidget *widget) { - GtkWidgetClass * widget_class; - GtkRulerClass * hruler_class; + GtkSHRuler *ruler = GTK_SHRULER (widget); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + GdkWindowAttr attributes; + gint attributes_mask; - widget_class = GTK_WIDGET_CLASS(klass); - hruler_class = GTK_RULER_CLASS(klass); + GTK_WIDGET_CLASS (gtk_shruler_parent_class)->realize (widget); - /* just neglect motion notify events */ - widget_class->motion_notify_event = NULL /* gtk_shruler_motion_notify */; + gtk_widget_get_allocation (widget, &allocation); - /* we want the old ruler draw ticks... */ - /* ruler_class->draw_ticks = gtk_hruler_draw_ticks; */ - hruler_class->draw_ticks = gtk_shruler_draw_ticks; - - /* unimplemented draw pos */ - hruler_class->draw_pos = NULL; -/* - hruler_class->draw_pos = gtk_shruler_draw_pos; -*/ + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = (gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + priv->input_window = gdk_window_new (gtk_widget_get_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (priv->input_window, ruler); + + gtk_shruler_make_pixmap (ruler); } static void -gtk_shruler_init (GtkSHRuler * shruler) +gtk_shruler_unrealize (GtkWidget *widget) { - GtkWidget * widget; - - widget = GTK_WIDGET (shruler); - widget->requisition.width = widget->style->xthickness * 2 + 1; - widget->requisition.height = widget->style->ythickness * 2 + RULER_HEIGHT; + GtkSHRuler *ruler = GTK_SHRULER (widget); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + + if (priv->backing_store) + { + cairo_surface_destroy (priv->backing_store); + priv->backing_store = NULL; + } + + if (priv->layout) + { + g_object_unref (priv->layout); + priv->layout = NULL; + } + + if (priv->input_window) + { + gdk_window_destroy (priv->input_window); + priv->input_window = NULL; + } + + GTK_WIDGET_CLASS (gtk_shruler_parent_class)->unrealize (widget); +} + +static void +gtk_shruler_map (GtkWidget *widget) +{ + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (widget); + + GTK_WIDGET_CLASS (parent_class)->map (widget); + + if (priv->input_window) + gdk_window_show (priv->input_window); } +static void +gtk_shruler_unmap (GtkWidget *widget) +{ + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (widget); + + if (priv->input_window) + gdk_window_hide (priv->input_window); + + GTK_WIDGET_CLASS (parent_class)->unmap (widget); +} + +static void +gtk_shruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkSHRuler *ruler = GTK_SHRULER (widget); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) + { + gdk_window_move_resize (priv->input_window, + allocation->x, allocation->y, + allocation->width, allocation->height); -GtkWidget* -gtk_shruler_new(void) + gtk_shruler_make_pixmap (ruler); + } +} + +static void +gtk_shruler_size_request (GtkWidget *widget, + GtkRequisition *requisition) { - return GTK_WIDGET( g_object_new( gtk_shruler_get_type(), NULL ) ); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (widget); + GtkStyle *style = gtk_widget_get_style (widget); + PangoLayout *layout; + PangoRectangle ink_rect; + gint size; + + layout = gtk_shruler_get_layout (widget, "0123456789"); + pango_layout_get_pixel_extents (layout, &ink_rect, NULL); + + size = 2 + ink_rect.height * 1.7; + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + requisition->width = style->xthickness * 2 + 1; + requisition->height = style->ythickness * 2 + size; + } + else + { + requisition->width = style->xthickness * 2 + size; + requisition->height = style->ythickness * 2 + 1; + } } static void -gtk_shruler_draw_ticks(GtkRuler *ruler) +gtk_shruler_style_set (GtkWidget *widget, + GtkStyle *prev_style) { - GtkWidget *widget; - cairo_t *cr; - gint i; - gint width, height; - gint xthickness; - gint ythickness; - gint pos; + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (widget); + + GTK_WIDGET_CLASS (gtk_shruler_parent_class)->style_set (widget, prev_style); - cm_return_if_fail (ruler != NULL); - cm_return_if_fail (GTK_IS_HRULER (ruler)); + gtk_widget_style_get (widget, + "font-scale", &priv->font_scale, + NULL); - if (!gtkut_widget_is_drawable (GTK_WIDGET(ruler))) - return; + if (priv->layout) + { + g_object_unref (priv->layout); + priv->layout = NULL; + } +} - widget = GTK_WIDGET (ruler); - - cr = gdk_cairo_create(ruler->backing_store); - cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); - cairo_set_line_width(cr, 1.); - gdk_cairo_set_source_color(cr, &gtk_widget_get_style(widget)->text[GTK_STATE_NORMAL]); +static gboolean +gtk_shruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkSHRuler *ruler = GTK_SHRULER (widget); - xthickness = widget->style->xthickness; - ythickness = widget->style->ythickness; + gdk_event_request_motions (event); - width = widget->allocation.width; - height = widget->allocation.height - ythickness * 2; - - gtk_paint_box (widget->style, ruler->backing_store, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, widget, "hruler", - 0, 0, - widget->allocation.width, widget->allocation.height); + gtk_shruler_update_position (ruler, event->x, event->y); - /* assume ruler->max_size has the char width */ - /* i is increment of char_width, pos is label number - * y position is based on height of widget itself */ - for ( i = 0, pos = 0; i < widget->allocation.width - xthickness; i += ruler->max_size, pos++ ) { - gint length = height / 8; - - if ( pos % 10 == 0 ) length = ( 2 * height / 3 ); - else if ( pos % 5 == 0 ) length = ( height / 3 ); - - cairo_move_to(cr, i, height + ythickness); - cairo_line_to(cr, i, height - length); - cairo_stroke(cr); - - if ( pos % 10 == 0 ) { - gchar buf[8]; - PangoLayout *layout; + return FALSE; +} + +static gboolean +gtk_shruler_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + if (gtk_widget_is_drawable (widget)) + { + GtkSHRuler *ruler = GTK_SHRULER (widget); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + cairo_t *cr; - /* draw label */ - g_snprintf(buf, sizeof buf, "%d", pos); + gtk_shruler_draw_ticks (ruler); - layout = gtk_widget_create_pango_layout - (GTK_WIDGET(ruler), buf); + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + gdk_cairo_region (cr, event->region); + cairo_clip (cr); - cairo_move_to(cr, i+2, 0); - pango_cairo_show_layout(cr, layout); + gtk_widget_get_allocation (widget, &allocation); + cairo_translate (cr, allocation.x, allocation.y); - g_object_unref(layout); - } - } + cairo_set_source_surface (cr, priv->backing_store, 0, 0); + cairo_paint (cr); - cairo_destroy(cr); + cairo_destroy (cr); + } + + return FALSE; } + +static void +gtk_shruler_draw_ticks (GtkSHRuler *ruler) +{ + GtkWidget *widget = GTK_WIDGET (ruler); + GtkStyle *style = gtk_widget_get_style (widget); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + GtkStateType state = gtk_widget_get_state (widget); + GtkAllocation allocation; + cairo_t *cr; + gint i; + gint width, height; + gint xthickness; + gint ythickness; + gint 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 start, end, cur; + gchar unit_str[32]; + gint digit_height; + gint digit_offset; + gint text_size; + gint pos; + gdouble max_size; + GtkCMUnit unit; + PangoLayout *layout; + PangoRectangle logical_rect, ink_rect; + + if (! gtk_widget_is_drawable (widget)) + return; + + gtk_widget_get_allocation (widget, &allocation); + + xthickness = style->xthickness; + ythickness = style->ythickness; + + layout = gtk_shruler_get_layout (widget, "0123456789"); + pango_layout_get_extents (layout, &ink_rect, &logical_rect); + + digit_height = PANGO_PIXELS (ink_rect.height) + 2; + digit_offset = ink_rect.y; + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + width = allocation.width; + height = allocation.height - ythickness * 2; + } + else + { + width = allocation.height; + height = allocation.width - ythickness * 2; + } + + cr = cairo_create (priv->backing_store); + gdk_cairo_set_source_color (cr, &style->bg[state]); + +#if 0 + gtk_paint_box (style, priv->backing_store, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, + priv->orientation == GTK_ORIENTATION_HORIZONTAL ? + "hruler" : "vruler", + 0, 0, + allocation.width, allocation.height); +#else + cairo_paint (cr); #endif + + gdk_cairo_set_source_color (cr, &style->fg[state]); + + gtk_shruler_get_range (ruler, &lower, &upper, &max_size); + + 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. + * + * We calculate the text size as for the vruler instead of + * actually measuring the text width, so that the result for the + * scale looks consistent with an accompanying vruler. + */ + scale = ceil (max_size); + g_snprintf (unit_str, sizeof (unit_str), "%d", scale); + text_size = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < G_N_ELEMENTS (ruler_metric.ruler_scale); scale++) + if (ruler_metric.ruler_scale[scale] * fabs (increment) > 2 * text_size) + break; + + if (scale == G_N_ELEMENTS (ruler_metric.ruler_scale)) + scale = G_N_ELEMENTS (ruler_metric.ruler_scale) - 1; + + unit = gtk_shruler_get_unit (ruler); + + /* drawing starts here */ + length = 0; + for (i = G_N_ELEMENTS (ruler_metric.subdivide) - 1; i >= 0; i--) + { + gdouble subd_incr; + + /* hack to get proper subdivisions at full pixels */ + if (unit == CM_UNIT_PIXEL && scale == 1 && i == 1) + subd_incr = 1.0; + else + subd_incr = ((gdouble) ruler_metric.ruler_scale[scale] / + (gdouble) ruler_metric.subdivide[i]); + + if (subd_incr * fabs (increment) <= MINIMUM_INCR) + continue; + + /* don't subdivide pixels */ + if (unit == CM_UNIT_PIXEL && subd_incr < 1.0) + continue; + + 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) + { + if (((int)cur) % 10 == 0) + length = height * 2 / 3; + else if (((int)cur) % 5 == 0) + length = height / 3; + else + length = height / 4; + + pos = ROUND ((cur - lower) * increment); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + cairo_rectangle (cr, + pos, height + ythickness - length, + 1, length); + } + else + { + cairo_rectangle (cr, + height + xthickness - length, pos, + length, 1); + } + + /* draw label */ + if (i == 0 && ((int)cur) % 10 == 0) + { + g_snprintf (unit_str, sizeof (unit_str), "%d", (int) cur); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + pango_layout_set_text (layout, unit_str, -1); + pango_layout_get_extents (layout, &logical_rect, NULL); + + cairo_move_to (cr, + pos + 2, + ythickness + PANGO_PIXELS (logical_rect.y - digit_offset)); + pango_cairo_show_layout (cr, layout); + } + else + { + gint j; + + 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); + + cairo_move_to (cr, + xthickness + 1, + pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset)); + pango_cairo_show_layout (cr, layout); + } + } + } + } + } + + cairo_fill (cr); +out: + cairo_destroy (cr); +} + +static void +gtk_shruler_make_pixmap (GtkSHRuler *ruler) +{ + GtkWidget *widget = GTK_WIDGET (ruler); + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + + if (priv->backing_store) + cairo_surface_destroy (priv->backing_store); + + priv->backing_store = + gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR, + allocation.width, + allocation.height); +} + + +static PangoLayout * +gtk_shruler_create_layout (GtkWidget *widget, + const gchar *text) +{ + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (widget); + PangoLayout *layout; + PangoAttrList *attrs; + PangoAttribute *attr; + + layout = gtk_widget_create_pango_layout (widget, text); + + attrs = pango_attr_list_new (); + + attr = pango_attr_scale_new (priv->font_scale); + attr->start_index = 0; + attr->end_index = -1; + pango_attr_list_insert (attrs, attr); + + pango_layout_set_attributes (layout, attrs); + pango_attr_list_unref (attrs); + + return layout; +} + +static PangoLayout * +gtk_shruler_get_layout (GtkWidget *widget, + const gchar *text) +{ + GtkSHRulerPrivate *priv = GTK_SHRULER_GET_PRIVATE (widget); + + if (priv->layout) + { + pango_layout_set_text (priv->layout, text, -1); + return priv->layout; + } + + priv->layout = gtk_shruler_create_layout (widget, text); + + return priv->layout; +} diff --git a/src/gtk/gtkshruler.h b/src/gtk/gtkshruler.h @@ -1,60 +1,79 @@ -/* GTKSHRuler - * Copyright (C) 2000-2011 Alfons Hoogervorst & The Claws Mail Team +/* LIBGTK - The GTK 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 Library General Public + * 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 3 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 - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. */ #ifndef __GTK_SHRULER_H__ #define __GTK_SHRULER_H__ +#include "gtkunit.h" -#include <gdk/gdk.h> -#include <gtk/gtk.h> - -#if !GTK_CHECK_VERSION(2,24,0) - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define GTK_SHRULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), gtk_shruler_get_type (), GtkSHRuler)) -#define GTK_SHRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), gtk_shruler_get_type (), GtkSHRulerClass)) -#define GTK_IS_SHRULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), gtk_shruler_get_type ())) +G_BEGIN_DECLS +#define GTK_TYPE_SHRULER (gtk_shruler_get_type ()) +#define GTK_SHRULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SHRULER, GtkSHRuler)) +#define GTK_SHRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SHRULER, GtkSHRulerClass)) +#define GTK_IS_SHRULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SHRULER)) +#define GTK_IS_SHRULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SHRULER)) +#define GTK_SHRULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SHRULER, GtkSHRulerClass)) typedef struct _GtkSHRuler GtkSHRuler; typedef struct _GtkSHRulerClass GtkSHRulerClass; struct _GtkSHRuler { - GtkHRuler ruler; + GtkWidget parent_instance; }; struct _GtkSHRulerClass { - GtkHRulerClass parent_class; + GtkWidgetClass parent_class; + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); }; -GType gtk_shruler_get_type (void); -GtkWidget* gtk_shruler_new (void); +GType gtk_shruler_get_type (void) G_GNUC_CONST; + +GtkWidget * gtk_shruler_new (GtkOrientation orientation); + +void gtk_shruler_add_track_widget (GtkSHRuler *ruler, + GtkWidget *widget); +void gtk_shruler_remove_track_widget (GtkSHRuler *ruler, + GtkWidget *widget); -#ifdef __cplusplus -} -#endif /* __cplusplus */ +void gtk_shruler_set_unit (GtkSHRuler *ruler, + GtkCMUnit unit); +GtkCMUnit gtk_shruler_get_unit (GtkSHRuler *ruler); +void gtk_shruler_set_position (GtkSHRuler *ruler, + gdouble position); +gdouble gtk_shruler_get_position (GtkSHRuler *ruler); +void gtk_shruler_set_range (GtkSHRuler *ruler, + gdouble lower, + gdouble upper, + gdouble max_size); +void gtk_shruler_get_range (GtkSHRuler *ruler, + gdouble *lower, + gdouble *upper, + gdouble *max_size); +G_END_DECLS #endif /* __GTK_SHRULER_H__ */ -#endif diff --git a/src/gtk/gtkunit.c b/src/gtk/gtkunit.c @@ -0,0 +1,699 @@ +/* LIBGTK - The GTK Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpunit.c + * Copyright (C) 2003 Michael Natterer <mitch@gimp.org> + * + * 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 3 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, see + * <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "gtkunit.h" + +#include <string.h> + +#include <glib-object.h> + + +GtkCMUnitVtable _gtk_unit_vtable = { NULL, }; + + +void +gtk_base_init (GtkCMUnitVtable *vtable) +{ + static gboolean gtk_base_initialized = FALSE; + + g_return_if_fail (vtable != NULL); + + if (gtk_base_initialized) + g_error ("gtk_base_init() must only be called once!"); + + _gtk_unit_vtable = *vtable; + + gtk_base_initialized = TRUE; +} + + +/** + * SECTION: gimpunit + * @title: gimpunit + * @short_description: Provides a collection of predefined units and + * functions for creating user-defined units. + * @see_also: #GtkCMUnitMenu, #GtkSizeEntry. + * + * Provides a collection of predefined units and functions for + * creating user-defined units. + **/ + + +static void unit_to_string (const GValue *src_value, + GValue *dest_value); +static void string_to_unit (const GValue *src_value, + GValue *dest_value); + +GType +gtk_unit_get_type (void) +{ + static GType unit_type = 0; + + if (! unit_type) + { + const GTypeInfo type_info = { 0, }; + + unit_type = g_type_register_static (G_TYPE_INT, "GtkCMUnit", + &type_info, 0); + + g_value_register_transform_func (unit_type, G_TYPE_STRING, + unit_to_string); + g_value_register_transform_func (G_TYPE_STRING, unit_type, + string_to_unit); + } + + return unit_type; +} + +static void +unit_to_string (const GValue *src_value, + GValue *dest_value) +{ + GtkCMUnit unit = (GtkCMUnit) g_value_get_int (src_value); + + g_value_set_string (dest_value, gtk_unit_get_identifier (unit)); +} + +static void +string_to_unit (const GValue *src_value, + GValue *dest_value) +{ + const gchar *str; + gint num_units; + gint i; + + str = g_value_get_string (src_value); + + if (!str || !*str) + goto error; + + num_units = gtk_unit_get_number_of_units (); + + for (i = CM_UNIT_PIXEL; i < num_units; i++) + if (strcmp (str, gtk_unit_get_identifier (i)) == 0) + break; + + if (i == num_units) + { + if (strcmp (str, gtk_unit_get_identifier (CM_UNIT_PERCENT)) == 0) + i = CM_UNIT_PERCENT; + else + goto error; + } + + g_value_set_int (dest_value, i); + return; + + error: + g_warning ("Can't convert string to GtkCMUnit."); +} + + +/** + * gtk_unit_get_number_of_units: + * + * Returns the number of units which are known to the #GtkCMUnit system. + * + * Returns: The number of defined units. + **/ +gint +gtk_unit_get_number_of_units (void) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_number_of_units != NULL, + CM_UNIT_END); + + return _gtk_unit_vtable.unit_get_number_of_units (); +} + +/** + * gtk_unit_get_number_of_built_in_units: + * + * Returns the number of #GtkCMUnit's which are hardcoded in the unit system + * (UNIT_INCH, UNIT_MM, UNIT_POINT, UNIT_PICA and the two "pseudo unit" + * UNIT_PIXEL). + * + * Returns: The number of built-in units. + **/ +gint +gtk_unit_get_number_of_built_in_units (void) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_number_of_built_in_units + != NULL, CM_UNIT_END); + + return _gtk_unit_vtable.unit_get_number_of_built_in_units (); +} + +/** + * gtk_unit_new: + * @identifier: The unit's identifier string. + * @factor: The unit's factor (how many units are in one inch). + * @digits: The unit's suggested number of digits (see gtk_unit_get_digits()). + * @symbol: The symbol of the unit (e.g. "''" for inch). + * @abbreviation: The abbreviation of the unit. + * @singular: The singular form of the unit. + * @plural: The plural form of the unit. + * + * Returns the integer ID of the new #GtkCMUnit. + * + * Note that a new unit is always created with it's deletion flag + * set to %TRUE. You will have to set it to %FALSE with + * gtk_unit_set_deletion_flag() to make the unit definition persistent. + * + * Returns: The ID of the new unit. + **/ +GtkCMUnit +gtk_unit_new (gchar *identifier, + gdouble factor, + gint digits, + gchar *symbol, + gchar *abbreviation, + gchar *singular, + gchar *plural) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_new != NULL, CM_UNIT_INCH); + + return _gtk_unit_vtable.unit_new (identifier, factor, digits, + symbol, abbreviation, singular, plural); +} + +/** + * gtk_unit_get_deletion_flag: + * @unit: The unit you want to know the @deletion_flag of. + * + * Returns: The unit's @deletion_flag. + **/ +gboolean +gtk_unit_get_deletion_flag (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_deletion_flag != NULL, FALSE); + + return _gtk_unit_vtable.unit_get_deletion_flag (unit); +} + +/** + * gtk_unit_set_deletion_flag: + * @unit: The unit you want to set the @deletion_flag for. + * @deletion_flag: The new deletion_flag. + * + * Sets a #GtkCMUnit's @deletion_flag. If the @deletion_flag of a unit is + * %TRUE when GTK exits, this unit will not be saved in the users's + * "unitrc" file. + * + * Trying to change the @deletion_flag of a built-in unit will be silently + * ignored. + **/ +void +gtk_unit_set_deletion_flag (GtkCMUnit unit, + gboolean deletion_flag) +{ + g_return_if_fail (_gtk_unit_vtable.unit_set_deletion_flag != NULL); + + _gtk_unit_vtable.unit_set_deletion_flag (unit, deletion_flag); +} + +/** + * gtk_unit_get_factor: + * @unit: The unit you want to know the factor of. + * + * A #GtkCMUnit's @factor is defined to be: + * + * distance_in_units == (@factor * distance_in_inches) + * + * Returns 0 for @unit == CM_UNIT_PIXEL. + * + * Returns: The unit's factor. + **/ +gdouble +gtk_unit_get_factor (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_factor != NULL, 1.0); + + return _gtk_unit_vtable.unit_get_factor (unit); +} + +/** + * gtk_unit_get_digits: + * @unit: The unit you want to know the digits. + * + * Returns the number of digits an entry field should provide to get + * approximately the same accuracy as an inch input field with two digits. + * + * Returns 0 for @unit == CM_UNIT_PIXEL. + * + * Returns: The suggested number of digits. + **/ +gint +gtk_unit_get_digits (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_digits != NULL, 2); + + return _gtk_unit_vtable.unit_get_digits (unit); +} + +/** + * gtk_unit_get_identifier: + * @unit: The unit you want to know the identifier of. + * + * This is an unstranslated string and must not be changed or freed. + * + * Returns: The unit's identifier. + **/ +const gchar * +gtk_unit_get_identifier (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_identifier != NULL, NULL); + + return _gtk_unit_vtable.unit_get_identifier (unit); +} + +/** + * gtk_unit_get_symbol: + * @unit: The unit you want to know the symbol of. + * + * This is e.g. "''" for UNIT_INCH. + * + * NOTE: This string must not be changed or freed. + * + * Returns: The unit's symbol. + **/ +const gchar * +gtk_unit_get_symbol (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_symbol != NULL, NULL); + + return _gtk_unit_vtable.unit_get_symbol (unit); +} + +/** + * gtk_unit_get_abbreviation: + * @unit: The unit you want to know the abbreviation of. + * + * For built-in units, this function returns the translated abbreviation + * of the unit. + * + * NOTE: This string must not be changed or freed. + * + * Returns: The unit's abbreviation. + **/ +const gchar * +gtk_unit_get_abbreviation (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_abbreviation != NULL, NULL); + + return _gtk_unit_vtable.unit_get_abbreviation (unit); +} + +/** + * gtk_unit_get_singular: + * @unit: The unit you want to know the singular form of. + * + * For built-in units, this function returns the translated singular form + * of the unit's name. + * + * NOTE: This string must not be changed or freed. + * + * Returns: The unit's singular form. + **/ +const gchar * +gtk_unit_get_singular (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_singular != NULL, NULL); + + return _gtk_unit_vtable.unit_get_singular (unit); +} + +/** + * gtk_unit_get_plural: + * @unit: The unit you want to know the plural form of. + * + * For built-in units, this function returns the translated plural form + * of the unit's name. + * + * NOTE: This string must not be changed or freed. + * + * Returns: The unit's plural form. + **/ +const gchar * +gtk_unit_get_plural (GtkCMUnit unit) +{ + g_return_val_if_fail (_gtk_unit_vtable.unit_get_plural != NULL, NULL); + + return _gtk_unit_vtable.unit_get_plural (unit); +} + +static gint +print (gchar *buf, + gint len, + gint start, + const gchar *fmt, + ...) +{ + va_list args; + gint printed; + + va_start (args, fmt); + + printed = g_vsnprintf (buf + start, len - start, fmt, args); + if (printed < 0) + printed = len - start; + + va_end (args); + + return printed; +} + +/** + * gtk_unit_format_string: + * @format: A printf-like format string which is used to create the unit + * string. + * @unit: A unit. + * + * The @format string supports the following percent expansions: + * + * <informaltable pgwide="1" frame="none" role="enum"> + * <tgroup cols="2"><colspec colwidth="1*"/><colspec colwidth="8*"/> + * <tbody> + * <row> + * <entry>% f</entry> + * <entry>Factor (how many units make up an inch)</entry> + * </row> + * <row> + * <entry>% y</entry> + * <entry>Symbol (e.g. "''" for CM_UNIT_INCH)</entry> + * </row> + * <row> + * <entry>% a</entry> + * <entry>Abbreviation</entry> + * </row> + * <row> + * <entry>% s</entry> + * <entry>Singular</entry> + * </row> + * <row> + * <entry>% p</entry> + * <entry>Plural</entry> + * </row> + * <row> + * <entry>%%</entry> + * <entry>Literal percent</entry> + * </row> + * </tbody> + * </tgroup> + * </informaltable> + * + * Returns: A newly allocated string with above percent expressions + * replaced with the resp. strings for @unit. + * + * Since: GTK 2.8 + **/ +gchar * +gtk_unit_format_string (const gchar *format, + GtkCMUnit unit) +{ + gchar buffer[1024]; + gint i = 0; + + g_return_val_if_fail (format != NULL, NULL); + g_return_val_if_fail (unit == CM_UNIT_PERCENT || + (unit >= CM_UNIT_PIXEL && + unit < gtk_unit_get_number_of_units ()), NULL); + + while (i < (sizeof (buffer) - 1) && *format) + { + switch (*format) + { + case '%': + format++; + switch (*format) + { + case 0: + g_warning ("%s: unit-menu-format string ended within %%-sequence", + G_STRFUNC); + break; + + case '%': + buffer[i++] = '%'; + break; + + case 'f': /* factor (how many units make up an inch) */ + i += print (buffer, sizeof (buffer), i, "%f", + gtk_unit_get_factor (unit)); + break; + + case 'y': /* symbol ("''" for inch) */ + i += print (buffer, sizeof (buffer), i, "%s", + gtk_unit_get_symbol (unit)); + break; + + case 'a': /* abbreviation */ + i += print (buffer, sizeof (buffer), i, "%s", + gtk_unit_get_abbreviation (unit)); + break; + + case 's': /* singular */ + i += print (buffer, sizeof (buffer), i, "%s", + gtk_unit_get_singular (unit)); + break; + + case 'p': /* plural */ + i += print (buffer, sizeof (buffer), i, "%s", + gtk_unit_get_plural (unit)); + break; + + default: + g_warning ("%s: unit-menu-format contains unknown format " + "sequence '%%%c'", G_STRFUNC, *format); + break; + } + break; + + default: + buffer[i++] = *format; + break; + } + + format++; + } + + buffer[MIN (i, sizeof (buffer) - 1)] = 0; + + return g_strdup (buffer); +} + +/* + * GTK_TYPE_PARAM_UNIT + */ + +#define GTK_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GTK_TYPE_PARAM_UNIT, GtkParamSpecUnit)) + +typedef struct _GtkParamSpecUnit GtkParamSpecUnit; + +struct _GtkParamSpecUnit +{ + GParamSpecInt parent_instance; + + gboolean allow_percent; +}; + +static void gtk_param_unit_class_init (GParamSpecClass *class); +static gboolean gtk_param_unit_value_validate (GParamSpec *pspec, + GValue *value); + +/** + * gtk_param_unit_get_type: + * + * Reveals the object type + * + * Returns: the #GType for a unit param object + * + * Since: GTK 2.4 + **/ +GType +gtk_param_unit_get_type (void) +{ + static GType spec_type = 0; + + if (! spec_type) + { + const GTypeInfo type_info = + { + sizeof (GParamSpecClass), + NULL, NULL, + (GClassInitFunc) gtk_param_unit_class_init, + NULL, NULL, + sizeof (GtkParamSpecUnit), + 0, NULL, NULL + }; + + spec_type = g_type_register_static (G_TYPE_PARAM_INT, + "GtkParamUnit", + &type_info, 0); + } + + return spec_type; +} + +static void +gtk_param_unit_class_init (GParamSpecClass *class) +{ + class->value_type = GTK_TYPE_UNIT; + class->value_validate = gtk_param_unit_value_validate; +} + +static gboolean +gtk_param_unit_value_validate (GParamSpec *pspec, + GValue *value) +{ + GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec); + GtkParamSpecUnit *uspec = GTK_PARAM_SPEC_UNIT (pspec); + gint oval = value->data[0].v_int; + + if (uspec->allow_percent && value->data[0].v_int == CM_UNIT_PERCENT) + { + value->data[0].v_int = value->data[0].v_int; + } + else + { + value->data[0].v_int = CLAMP (value->data[0].v_int, + ispec->minimum, + gtk_unit_get_number_of_units () - 1); + } + + return value->data[0].v_int != oval; +} + +/** + * gtk_param_spec_unit: + * @name: Canonical name of the param + * @nick: Nickname of the param + * @blurb: Brief desciption of param. + * @allow_pixels: Whether "pixels" is an allowed unit. + * @allow_percent: Whether "perecent" is an allowed unit. + * @default_value: Unit to use if none is assigned. + * @flags: a combination of #GParamFlags + * + * Creates a param spec to hold a units param. + * See g_param_spec_internal() for more information. + * + * Returns: a newly allocated #GParamSpec instance + * + * Since: GTK 2.4 + **/ +GParamSpec * +gtk_param_spec_unit (const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean allow_pixels, + gboolean allow_percent, + GtkCMUnit default_value, + GParamFlags flags) +{ + GtkParamSpecUnit *pspec; + GParamSpecInt *ispec; + + pspec = g_param_spec_internal (GTK_TYPE_PARAM_UNIT, + name, nick, blurb, flags); + + ispec = G_PARAM_SPEC_INT (pspec); + + ispec->default_value = default_value; + ispec->minimum = allow_pixels ? CM_UNIT_PIXEL : CM_UNIT_INCH; + ispec->maximum = CM_UNIT_PERCENT - 1; + + pspec->allow_percent = allow_percent; + + return G_PARAM_SPEC (pspec); +} + +/** + * gtk_pixels_to_units: + * @pixels: value in pixels + * @unit: unit to convert to + * @resolution: resloution in DPI + * + * Converts a @value specified in pixels to @unit. + * + * Returns: @pixels converted to units. + * + * Since: GTK 2.8 + **/ +gdouble +gtk_pixels_to_units (gdouble pixels, + GtkCMUnit unit, + gdouble resolution) +{ + if (unit == CM_UNIT_PIXEL) + return pixels; + + return pixels * gtk_unit_get_factor (unit) / resolution; +} + +/** + * gtk_units_to_pixels: + * @value: value in units + * @unit: unit of @value + * @resolution: resloution in DPI + * + * Converts a @value specified in @unit to pixels. + * + * Returns: @value converted to pixels. + * + * Since: GTK 2.8 + **/ +gdouble +gtk_units_to_pixels (gdouble value, + GtkCMUnit unit, + gdouble resolution) +{ + if (unit == CM_UNIT_PIXEL) + return value; + + return value * resolution / gtk_unit_get_factor (unit); +} + +/** + * gtk_units_to_points: + * @value: value in units + * @unit: unit of @value + * @resolution: resloution in DPI + * + * Converts a @value specified in @unit to points. + * + * Returns: @value converted to points. + * + * Since: GTK 2.8 + **/ +gdouble +gtk_units_to_points (gdouble value, + GtkCMUnit unit, + gdouble resolution) +{ + if (unit == CM_UNIT_POINT) + return value; + + if (unit == CM_UNIT_PIXEL) + return (value * gtk_unit_get_factor (CM_UNIT_POINT) / resolution); + + return (value * + gtk_unit_get_factor (CM_UNIT_POINT) / gtk_unit_get_factor (unit)); +} diff --git a/src/gtk/gtkunit.h b/src/gtk/gtkunit.h @@ -0,0 +1,158 @@ +/* LIBGTK - The GTK Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpunit.h + * Copyright (C) 1999-2003 Michael Natterer <mitch@gimp.org> + * + * 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 3 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, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef __CM_UNIT_H__ +#define __CM_UNIT_H__ + +#include <glib-object.h> + +typedef enum /*< skip >*/ +{ + CM_UNIT_PIXEL = 0, + + CM_UNIT_INCH = 1, + CM_UNIT_MM = 2, + CM_UNIT_POINT = 3, + CM_UNIT_PICA = 4, + + CM_UNIT_END = 5, + + CM_UNIT_PERCENT = 65536 /*< pdb-skip >*/ +} GtkCMUnit; + +typedef struct _GtkCMUnitVtable GtkCMUnitVtable; + +struct _GtkCMUnitVtable +{ + gint (* unit_get_number_of_units) (void); + gint (* unit_get_number_of_built_in_units) (void); + + GtkCMUnit (* unit_new) (gchar *identifier, + gdouble factor, + gint digits, + gchar *symbol, + gchar *abbreviation, + gchar *singular, + gchar *plural); + gboolean (* unit_get_deletion_flag) (GtkCMUnit unit); + void (* unit_set_deletion_flag) (GtkCMUnit unit, + gboolean deletion_flag); + + gdouble (* unit_get_factor) (GtkCMUnit unit); + gint (* unit_get_digits) (GtkCMUnit unit); + const gchar * (* unit_get_identifier) (GtkCMUnit unit); + const gchar * (* unit_get_symbol) (GtkCMUnit unit); + const gchar * (* unit_get_abbreviation) (GtkCMUnit unit); + const gchar * (* unit_get_singular) (GtkCMUnit unit); + const gchar * (* unit_get_plural) (GtkCMUnit unit); + + void (* _reserved_1) (void); + void (* _reserved_2) (void); + void (* _reserved_3) (void); + void (* _reserved_4) (void); +}; + + +extern GtkCMUnitVtable _gimp_unit_vtable; + + +G_BEGIN_DECLS + +void gimp_base_init (GtkCMUnitVtable *vtable); + + +/* For information look into the C source or the html documentation */ + +/** + * GTK_TYPE_UNIT: + * + * #GTK_TYPE_UNIT is a #GType derived from #G_TYPE_INT. + **/ + +#define GTK_TYPE_UNIT (gtk_unit_get_type ()) +#define GTK_VALUE_HOLDS_UNIT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GTK_TYPE_UNIT)) + + +GType gtk_unit_get_type (void) G_GNUC_CONST; + + +/* + * GTK_TYPE_PARAM_UNIT + */ + +#define GTK_TYPE_PARAM_UNIT (gtk_param_unit_get_type ()) +#define GTK_IS_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GTK_TYPE_PARAM_UNIT)) + +GType gtk_param_unit_get_type (void) G_GNUC_CONST; + +GParamSpec * gtk_param_spec_unit (const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean allow_pixels, + gboolean allow_percent, + GtkCMUnit default_value, + GParamFlags flags); + + + +gint gtk_unit_get_number_of_units (void); +gint gtk_unit_get_number_of_built_in_units (void) G_GNUC_CONST; + +GtkCMUnit gtk_unit_new (gchar *identifier, + gdouble factor, + gint digits, + gchar *symbol, + gchar *abbreviation, + gchar *singular, + gchar *plural); + +gboolean gtk_unit_get_deletion_flag (GtkCMUnit unit); +void gtk_unit_set_deletion_flag (GtkCMUnit unit, + gboolean deletion_flag); + +gdouble gtk_unit_get_factor (GtkCMUnit unit); + +gint gtk_unit_get_digits (GtkCMUnit unit); + +const gchar * gtk_unit_get_identifier (GtkCMUnit unit); + +const gchar * gtk_unit_get_symbol (GtkCMUnit unit); +const gchar * gtk_unit_get_abbreviation (GtkCMUnit unit); +const gchar * gtk_unit_get_singular (GtkCMUnit unit); +const gchar * gtk_unit_get_plural (GtkCMUnit unit); + +gchar * gtk_unit_format_string (const gchar *format, + GtkCMUnit unit); + +gdouble gtk_pixels_to_units (gdouble pixels, + GtkCMUnit unit, + gdouble resolution); +gdouble gtk_units_to_pixels (gdouble value, + GtkCMUnit unit, + gdouble resolution); +gdouble gtk_units_to_points (gdouble value, + GtkCMUnit unit, + gdouble resolution); + + +G_END_DECLS + +#endif /* __CM_UNIT_H__ */