"Fossies" - the Fresh Open Source Software Archive

Member "gtkdatabox-1.0.0/gtk/gtkdatabox_ruler.c" (16 Apr 2021, 67658 Bytes) of package /linux/privat/gtkdatabox-1.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gtkdatabox_ruler.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.9.3.1_vs_1.0.0.

    1 /* $Id: gtkdatabox_ruler.c 4 2008-06-22 09:19:11Z rbock $ */
    2 /* GTK - The GIMP Toolkit
    3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
    4  *
    5  * This library is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU Lesser General Public
    7  * License as published by the Free Software Foundation; either
    8  * version 2 of the License, or (at your option) any later version.
    9  *
   10  * This library is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  * Lesser General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU Lesser General Public
   16  * License along with this library; if not, write to the
   17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   18  * Boston, MA 02110-1301 USA
   19  */
   20 
   21 /*
   22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
   23  * file for a list of people on the GTK+ Team.  See the ChangeLog
   24  * files for a list of changes.  These files are distributed with
   25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
   26  */
   27 
   28 /* Modified by Roland Bock 2007, see ChangeLog */
   29 
   30 #include <gtkdatabox_ruler.h>
   31 
   32 #include <math.h>
   33 #include <glib/gprintf.h>
   34 
   35 #include <string.h>
   36 
   37 #define RULER_SIZE          20
   38 
   39 #define ROUND(x) ((int) ((x) + 0.5))
   40 
   41 #define FORMAT_LENGTH 20 /* the length of the label format string */
   42 
   43 #define LINEAR_FORMAT_MARKUP "%%-+%dg"
   44 #define LOG_FORMAT_MARKUP "%%-%dg"
   45 
   46 #ifdef _MSC_VER
   47 #ifndef _DATABOX_LOG2_
   48 #define _DATABOX_LOG2_
   49 /*< private >*/
   50 #define log2(x) (log(x)/log(2))
   51 #endif /*_DATABOX_LOG2_ */
   52 #endif /*_MSC_VER */
   53 
   54 static void gtk_databox_ruler_draw_ticks (GtkDataboxRuler * ruler);
   55 static void gtk_databox_ruler_draw_pos (GtkDataboxRuler * ruler);
   56 static gint gtk_databox_ruler_motion_notify (GtkWidget * widget,
   57         GdkEventMotion * event);
   58 static void gtk_databox_ruler_realize (GtkWidget * widget);
   59 static void gtk_databox_ruler_unrealize (GtkWidget * widget);
   60 static void gtk_databox_ruler_size_allocate (GtkWidget * widget,
   61         GtkAllocation * allocation);
   62 static gint gtk_databox_ruler_draw (GtkWidget * widget,
   63     cairo_t * cr);
   64 static void gtk_databox_ruler_get_preferred_width (GtkWidget *widget,
   65     gint *minimal_width,
   66     gint *natural_width);
   67 static void gtk_databox_ruler_get_preferred_height (GtkWidget *widget,
   68     gint *minimal_height,
   69     gint *natural_height);
   70 static void gtk_databox_ruler_create_backing_surface (GtkDataboxRuler * ruler);
   71 static void gtk_databox_ruler_set_property (GObject * object,
   72         guint prop_id,
   73         const GValue * value,
   74         GParamSpec * pspec);
   75 static void gtk_databox_ruler_get_property (GObject * object,
   76         guint prop_id,
   77         GValue * value,
   78         GParamSpec * pspec);
   79 
   80 enum {
   81     PROP_0,
   82     PROP_LOWER,
   83     PROP_UPPER,
   84     PROP_POSITION,
   85     PROP_DRAW_POSITION,
   86     PROP_MAX_LENGTH,
   87     PROP_ORIENTATION,
   88     PROP_TEXT_ORIENTATION,
   89     PROP_TEXT_ALIGNMENT,
   90     PROP_TEXT_HOFFSET,
   91     PROP_DRAW_TICKS,
   92     PROP_DRAW_SUBTICKS,
   93     PROP_MANUAL_TICKS,
   94     PROP_MANUAL_TICK_CNT,
   95     PROP_MANUAL_TICK_LABELS,
   96     PROP_INVERT_EDGE,
   97     PROP_LINEAR_LABEL_FORMAT,
   98     PROP_LOG_LABEL_FORMAT,
   99     PROP_BOX_SHADOW,
  100     PROP_END_OF_LIST
  101 };
  102 
  103 struct _GtkDataboxRulerPrivate
  104 {
  105     cairo_surface_t *backing_surface;
  106     gint old_width;
  107     gint old_height;
  108 
  109     gint xsrc;
  110     gint ysrc;
  111     /* The lower limit of the ruler */
  112     gdouble lower;
  113     /* The upper limit of the ruler */
  114     gdouble upper;
  115     /* The position of the mark on the ruler */
  116     gdouble position;
  117     /* whether to draw the position arrows*/
  118     gboolean draw_position;
  119 
  120     /* The maximum length of the labels (in characters) */
  121     guint max_length;
  122     /* The scale type of the ruler */
  123     GtkDataboxScaleType scale_type;
  124     /* Orientation of the ruler */
  125     GtkOrientation orientation;
  126     /* Orientation of the tick marks on the vertical ruler */
  127     GtkOrientation text_orientation;
  128 
  129     /* Whether the horizontal text on the vertical ruler is aligned left or right or center */
  130     PangoAlignment text_alignment;
  131     /* horizontal tick offset (shift ticks left or right) */
  132     gint text_hoffset;
  133 
  134     /* The maximum height of text on the horizontal ruler */
  135     gint max_x_text_height;
  136     /* The maximum width of text on the horizontal ruler */
  137     gint max_y_text_width;
  138 
  139     /* When true draw the ticks */
  140     gboolean draw_ticks;
  141 
  142     /* When true draw the subticks */
  143     gboolean draw_subticks;
  144 
  145     /* Whether the ruler is inverted (i.e. drawn with the edge on the left or right, top or bottom) */
  146     gboolean invert_edge;
  147 
  148     /* Strings used to mark up the g_sprintf label format - one for log scaling and one for linear scaling */
  149     gchar linear_format[FORMAT_LENGTH], log_format[FORMAT_LENGTH];
  150 
  151     /* If we are manually setting ticks, this will be non-null */
  152     gfloat *manual_ticks;
  153     guint manual_tick_cnt;
  154     /* we have the option of manually setting the tick labels. */
  155     gchar **manual_tick_labels;
  156 
  157     GtkShadowType box_shadow; /* The type of shadow drawn on the ruler pixmap */
  158 };
  159 
  160 G_DEFINE_TYPE_WITH_PRIVATE (GtkDataboxRuler, gtk_databox_ruler, GTK_TYPE_WIDGET)
  161 
  162 static void gtk_databox_ruler_class_init (GtkDataboxRulerClass * class) {
  163     GObjectClass *gobject_class;
  164     GtkWidgetClass *widget_class;
  165 
  166     gobject_class = G_OBJECT_CLASS (class);
  167     widget_class = (GtkWidgetClass *) class;
  168 
  169     gobject_class->set_property = gtk_databox_ruler_set_property;
  170     gobject_class->get_property = gtk_databox_ruler_get_property;
  171 
  172     widget_class->realize = gtk_databox_ruler_realize;
  173     widget_class->unrealize = gtk_databox_ruler_unrealize;
  174     widget_class->size_allocate = gtk_databox_ruler_size_allocate;
  175     widget_class->draw = gtk_databox_ruler_draw;
  176     widget_class->motion_notify_event = gtk_databox_ruler_motion_notify;
  177     widget_class->get_preferred_width = gtk_databox_ruler_get_preferred_width;
  178     widget_class->get_preferred_height = gtk_databox_ruler_get_preferred_height;
  179 
  180     g_object_class_install_property (gobject_class,
  181                                      PROP_LOWER,
  182                                      g_param_spec_double ("lower",
  183                                              "Lower",
  184                                              "Lower limit of ruler",
  185                                              -G_MAXDOUBLE,
  186                                              G_MAXDOUBLE,
  187                                              0.0,
  188                                              G_PARAM_READWRITE));
  189 
  190     g_object_class_install_property (gobject_class,
  191                                      PROP_UPPER,
  192                                      g_param_spec_double ("upper",
  193                                              "Upper",
  194                                              "Upper limit of ruler",
  195                                              -G_MAXDOUBLE,
  196                                              G_MAXDOUBLE,
  197                                              0.0,
  198                                              G_PARAM_READWRITE));
  199 
  200     g_object_class_install_property (gobject_class,
  201                                      PROP_POSITION,
  202                                      g_param_spec_double ("position",
  203                                              "Position",
  204                                              "Position of mark on the ruler",
  205                                              -G_MAXDOUBLE,
  206                                              G_MAXDOUBLE,
  207                                              0.0,
  208                                              G_PARAM_READWRITE));
  209 
  210     g_object_class_install_property (gobject_class,
  211                                      PROP_DRAW_POSITION,
  212                                      g_param_spec_uint ("draw-position",
  213                                              "Draw Position Arrows",
  214                                              "Draw the position arrows: true or false",
  215                                              FALSE,
  216                                              TRUE,
  217                                              TRUE,
  218                                              G_PARAM_READWRITE));
  219 
  220     g_object_class_install_property (gobject_class,
  221                                      PROP_MAX_LENGTH,
  222                                      g_param_spec_uint ("max-length",
  223                                              "Max Length",
  224                                              "Maximum length of the labels (in digits)",
  225                                              2,
  226                                              GTK_DATABOX_RULER_MAX_MAX_LENGTH,
  227                                              6, G_PARAM_READWRITE));
  228     g_object_class_install_property (gobject_class,
  229                                      PROP_ORIENTATION,
  230                                      g_param_spec_uint ("orientation",
  231                                              "Orientation",
  232                                              "Orientation of the ruler: horizontal or vertical",
  233                                              GTK_ORIENTATION_HORIZONTAL,
  234                                              GTK_ORIENTATION_VERTICAL,
  235                                              GTK_ORIENTATION_HORIZONTAL,
  236                                              G_PARAM_READWRITE |
  237                                              G_PARAM_CONSTRUCT_ONLY));
  238     g_object_class_install_property (gobject_class,
  239                                      PROP_TEXT_ORIENTATION,
  240                                      g_param_spec_uint ("text-orientation",
  241                                              "Text Orientation",
  242                                              "Orientation of the tick mark text (on the vertical ruler): horizontal or vertical",
  243                                              GTK_ORIENTATION_HORIZONTAL,
  244                                              GTK_ORIENTATION_VERTICAL,
  245                                              GTK_ORIENTATION_VERTICAL,
  246                                              G_PARAM_READWRITE));
  247     g_object_class_install_property (gobject_class,
  248                                      PROP_TEXT_ALIGNMENT,
  249                                      g_param_spec_uint ("text-alignment",
  250                                              "Text Alignment",
  251                                              "Alignment of the tick mark text (on the vertical ruler when using horizonal text): { PANGO_ALIGN_LEFT, PANGO_ALIGN_CENTER, PANGO_ALIGN_RIGHT}",
  252                                              PANGO_ALIGN_LEFT,
  253                                              PANGO_ALIGN_RIGHT,
  254                                              PANGO_ALIGN_LEFT,
  255                                              G_PARAM_READWRITE));
  256     g_object_class_install_property (gobject_class,
  257                                      PROP_TEXT_HOFFSET,
  258                                      g_param_spec_uint ("text-hoffset",
  259                                              "Text Horizonal offset",
  260                                              "Move the tick mark text left or right : pixels",
  261                                              0,
  262                                              20,
  263                                              0,
  264                                              G_PARAM_READWRITE));
  265     g_object_class_install_property (gobject_class,
  266                                      PROP_DRAW_TICKS,
  267                                      g_param_spec_uint ("draw-ticks",
  268                                              "Draw Ticks",
  269                                              "Draw the Ticks: true or false",
  270                                              FALSE,
  271                                              TRUE,
  272                                              TRUE,
  273                                              G_PARAM_READWRITE));
  274     g_object_class_install_property (gobject_class,
  275                                      PROP_DRAW_SUBTICKS,
  276                                      g_param_spec_uint ("draw-subticks",
  277                                              "Draw Subticks",
  278                                              "Draw the subticks: true or false",
  279                                              FALSE,
  280                                              TRUE,
  281                                              TRUE,
  282                                              G_PARAM_READWRITE));
  283     g_object_class_install_property (gobject_class,
  284                                      PROP_MANUAL_TICKS,
  285                                      g_param_spec_pointer ("manual-ticks",
  286                                              "Manual Ticks",
  287                                              "Manually specify the tick locations",
  288                                              G_PARAM_READWRITE));
  289     g_object_class_install_property (gobject_class,
  290                                      PROP_MANUAL_TICK_CNT,
  291                                      g_param_spec_uint ("manual-tick-cnt",
  292                                              "Manual Tick Count",
  293                                              "The number of manual ticks in the manual_tick array: horizontal or vertical",
  294                                              0,
  295                                              G_MAXUINT,
  296                                              0,
  297                                              G_PARAM_READWRITE));
  298     g_object_class_install_property (gobject_class,
  299                                      PROP_MANUAL_TICK_LABELS,
  300                                      g_param_spec_pointer ("manual-tick-labels",
  301                                              "Manual Tick Labels",
  302                                              "Manually specify the tick labels",
  303                                              G_PARAM_READWRITE));
  304     g_object_class_install_property (gobject_class,
  305                                      PROP_INVERT_EDGE,
  306                                      g_param_spec_uint ("invert-edge",
  307                                              "Invert Edge",
  308                                              "Invert the Edge - the edge is drawn inverted: true or false",
  309                                              FALSE,
  310                                              TRUE,
  311                                              FALSE,
  312                                              G_PARAM_READWRITE));
  313     g_object_class_install_property (gobject_class,
  314                                      PROP_LINEAR_LABEL_FORMAT,
  315                                      g_param_spec_string ("linear-label-format",
  316                                              "Linear Label Format",
  317                                              "Linear Label format mark up strings: marked up formatting strings for linear labels (i.e. \"%%-+%dg\")",
  318                                              LINEAR_FORMAT_MARKUP,
  319                                              G_PARAM_READWRITE));
  320     g_object_class_install_property (gobject_class,
  321                                      PROP_LOG_LABEL_FORMAT,
  322                                      g_param_spec_string ("log-label-format",
  323                                              "Log Label Format",
  324                                              "Log Label format mark up strings: marked up formatting strings for log labels (i.e. \"%%-%dg\")",
  325                                              LOG_FORMAT_MARKUP,
  326                                              G_PARAM_READWRITE));
  327     g_object_class_install_property (gobject_class,
  328                                      PROP_BOX_SHADOW,
  329                                      g_param_spec_uint ("box-shadow",
  330                                              "Box Shadow",
  331                                              "Style of the box shadow: GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT",
  332                                              GTK_SHADOW_NONE,
  333                                              GTK_SHADOW_ETCHED_OUT,
  334                                              GTK_SHADOW_OUT,
  335                                              G_PARAM_READWRITE));
  336 }
  337 
  338 static void
  339 gtk_databox_ruler_init (GtkDataboxRuler * ruler) {
  340     ruler->priv = g_new0 (GtkDataboxRulerPrivate, 1);
  341     ruler->priv->backing_surface = NULL;
  342     ruler->priv->xsrc = 0;
  343     ruler->priv->ysrc = 0;
  344     ruler->priv->lower = 0;
  345     ruler->priv->upper = 0;
  346     ruler->priv->position = 0;
  347     ruler->priv->draw_position = TRUE;
  348     ruler->priv->max_length = 6;
  349     ruler->priv->scale_type = GTK_DATABOX_SCALE_LINEAR;
  350     ruler->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
  351     ruler->priv->text_orientation = GTK_ORIENTATION_VERTICAL;
  352     ruler->priv->text_hoffset=0;
  353     ruler->priv->max_x_text_height = 0;
  354     ruler->priv->max_y_text_width = 0;
  355     ruler->priv->draw_ticks = TRUE;
  356     ruler->priv->draw_subticks = TRUE;
  357     ruler->priv->invert_edge = FALSE;
  358     g_stpcpy(ruler->priv->linear_format, LINEAR_FORMAT_MARKUP);
  359     g_stpcpy(ruler->priv->log_format, LOG_FORMAT_MARKUP);
  360     ruler->priv->manual_ticks=NULL;
  361     ruler->priv->manual_tick_cnt=0;
  362     ruler->priv->manual_tick_labels=NULL;
  363     ruler->priv->box_shadow=GTK_SHADOW_OUT;
  364 }
  365 
  366 /**
  367  * gtk_databox_ruler_new:
  368  * @orientation: orientation of the ruler
  369  *
  370  * Creates a new #GtkDataboxRuler widget with the given @orientation (horizontal or vertical).
  371  *
  372  * Return value: A new #GtkDataboxRuler
  373  **/
  374 GtkWidget *
  375 gtk_databox_ruler_new (GtkOrientation orientation) {
  376     return g_object_new (GTK_DATABOX_TYPE_RULER, "orientation", orientation,
  377                          NULL);
  378 }
  379 
  380 static gint
  381 gtk_databox_ruler_motion_notify (GtkWidget * widget, GdkEventMotion * event) {
  382     GtkDataboxRuler *ruler;
  383     gint x;
  384     gint y;
  385     GtkAllocation allocation;
  386 
  387     ruler = GTK_DATABOX_RULER (widget);
  388     gtk_widget_get_allocation(widget, &allocation);
  389 
  390     if (gtk_databox_ruler_get_draw_position (ruler)) {
  391 
  392         if (event->is_hint) {
  393             gdk_window_get_device_position (gtk_widget_get_window(widget), event->device, &x, &y, NULL);
  394         } else {
  395             x = event->x;
  396             y = event->y;
  397         }
  398 
  399         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
  400             ruler->priv->position =
  401                 ruler->priv->lower +
  402                 ((ruler->priv->upper - ruler->priv->lower) * x) / allocation.width;
  403         else
  404             ruler->priv->position =
  405                 ruler->priv->lower +
  406                 ((ruler->priv->upper - ruler->priv->lower) * y) / allocation.height;
  407 
  408         g_object_notify (G_OBJECT (ruler), "position");
  409 
  410         /*  Make sure the ruler has been allocated already  */
  411         if (ruler->priv->backing_surface != NULL)
  412             if (ruler->priv->draw_position)
  413                 gtk_databox_ruler_draw_pos (ruler);
  414     }
  415     return FALSE;
  416 }
  417 
  418 static void
  419 gtk_databox_ruler_set_property (GObject * object,
  420                                 guint prop_id,
  421                                 const GValue * value, GParamSpec * pspec) {
  422     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (object);
  423 
  424     switch (prop_id) {
  425     case PROP_LOWER:
  426         gtk_databox_ruler_set_range (ruler, g_value_get_double (value),
  427                                      ruler->priv->upper, ruler->priv->position);
  428         break;
  429     case PROP_UPPER:
  430         gtk_databox_ruler_set_range (ruler, ruler->priv->lower,
  431                                      g_value_get_double (value),
  432                                      ruler->priv->position);
  433         break;
  434     case PROP_POSITION:
  435         gtk_databox_ruler_set_range (ruler, ruler->priv->lower, ruler->priv->upper,
  436                                      g_value_get_double (value));
  437         break;
  438     case PROP_DRAW_POSITION:
  439         gtk_databox_ruler_set_draw_position (ruler, (gboolean) g_value_get_boolean (value));
  440         break;
  441     case PROP_MAX_LENGTH:
  442         gtk_databox_ruler_set_max_length (ruler, g_value_get_uint (value));
  443         break;
  444     case PROP_ORIENTATION:
  445         gtk_databox_ruler_set_orientation (ruler, (GtkOrientation) g_value_get_uint (value));
  446         break;
  447     case PROP_TEXT_ORIENTATION:
  448         gtk_databox_ruler_set_text_orientation (ruler, (GtkOrientation) g_value_get_uint (value));
  449         break;
  450     case PROP_TEXT_ALIGNMENT:
  451         gtk_databox_ruler_set_text_alignment (ruler, (PangoAlignment) g_value_get_uint (value));
  452         break;
  453     case PROP_TEXT_HOFFSET:
  454         gtk_databox_ruler_set_text_hoffset (ruler, (GtkOrientation) g_value_get_uint (value));
  455         break;
  456     case PROP_DRAW_TICKS:
  457         gtk_databox_ruler_set_draw_ticks (ruler, (gboolean) g_value_get_boolean (value));
  458         break;
  459     case PROP_DRAW_SUBTICKS:
  460         gtk_databox_ruler_set_draw_subticks (ruler, (gboolean) g_value_get_boolean (value));
  461         break;
  462     case PROP_MANUAL_TICKS:
  463         gtk_databox_ruler_set_manual_ticks (ruler, (gfloat *) g_value_get_pointer (value));
  464         break;
  465     case PROP_MANUAL_TICK_CNT:
  466         gtk_databox_ruler_set_manual_tick_cnt (ruler, g_value_get_uint (value));
  467         break;
  468     case PROP_MANUAL_TICK_LABELS:
  469         gtk_databox_ruler_set_manual_tick_labels (ruler, (gchar **) g_value_get_pointer (value));
  470         break;
  471     case PROP_INVERT_EDGE:
  472         gtk_databox_ruler_set_invert_edge (ruler, (gboolean) g_value_get_boolean (value));
  473         break;
  474     case PROP_LINEAR_LABEL_FORMAT:
  475         gtk_databox_ruler_set_linear_label_format (ruler, (gchar *) g_value_get_string (value));
  476         break;
  477     case PROP_LOG_LABEL_FORMAT:
  478         gtk_databox_ruler_set_log_label_format (ruler, (gchar *) g_value_get_string (value));
  479         break;
  480     case PROP_BOX_SHADOW:
  481         gtk_databox_ruler_set_box_shadow (ruler, (GtkShadowType) g_value_get_uint (value));
  482         break;
  483     default:
  484         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  485         break;
  486     }
  487 }
  488 
  489 static void
  490 gtk_databox_ruler_get_property (GObject * object,
  491                                 guint prop_id,
  492                                 GValue * value, GParamSpec * pspec) {
  493     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (object);
  494 
  495     switch (prop_id) {
  496     case PROP_LOWER:
  497         g_value_set_double (value, ruler->priv->lower);
  498         break;
  499     case PROP_UPPER:
  500         g_value_set_double (value, ruler->priv->upper);
  501         break;
  502     case PROP_POSITION:
  503         g_value_set_double (value, ruler->priv->position);
  504         break;
  505     case PROP_DRAW_POSITION:
  506         g_value_set_boolean (value, ruler->priv->draw_position);
  507         break;
  508     case PROP_MAX_LENGTH:
  509         g_value_set_uint (value, ruler->priv->max_length);
  510         break;
  511     case PROP_ORIENTATION:
  512         g_value_set_uint (value, ruler->priv->orientation);
  513         break;
  514     case PROP_TEXT_ORIENTATION:
  515         g_value_set_uint (value, ruler->priv->text_orientation);
  516         break;
  517     case PROP_TEXT_ALIGNMENT:
  518         g_value_set_uint (value, ruler->priv->text_alignment);
  519         break;
  520     case PROP_TEXT_HOFFSET:
  521         g_value_set_uint (value, ruler->priv->text_hoffset);
  522         break;
  523     case PROP_DRAW_TICKS:
  524         g_value_set_boolean (value, ruler->priv->draw_ticks);
  525         break;
  526     case PROP_DRAW_SUBTICKS:
  527         g_value_set_boolean (value, ruler->priv->draw_subticks);
  528         break;
  529     case PROP_MANUAL_TICKS:
  530         g_value_set_pointer (value, ruler->priv->manual_ticks);
  531         break;
  532     case PROP_MANUAL_TICK_CNT:
  533         g_value_set_uint (value, ruler->priv->manual_tick_cnt);
  534         break;
  535     case PROP_MANUAL_TICK_LABELS:
  536         g_value_set_pointer (value, ruler->priv->manual_tick_labels);
  537         break;
  538     case PROP_INVERT_EDGE:
  539         g_value_set_boolean (value, ruler->priv->invert_edge);
  540         break;
  541     case PROP_LINEAR_LABEL_FORMAT:
  542         g_value_set_string (value, ruler->priv->linear_format);
  543         break;
  544     case PROP_LOG_LABEL_FORMAT:
  545         g_value_set_string (value, ruler->priv->log_format);
  546         break;
  547     case PROP_BOX_SHADOW:
  548         g_value_set_uint (value, ruler->priv->box_shadow);
  549         break;
  550     default:
  551         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  552         break;
  553     }
  554 }
  555 
  556 /**
  557  * gtk_databox_ruler_set_range:
  558  * @ruler: a #GtkDataboxRuler
  559  * @lower: lower limit of the ruler
  560  * @upper: upper limit of the ruler
  561  * @position: current position of the mark on the ruler
  562  *
  563  * Sets values indicating the range and current position of a #GtkDataboxRuler.
  564  *
  565  * See gtk_databox_ruler_get_range().
  566  **/
  567 void
  568 gtk_databox_ruler_set_range (GtkDataboxRuler * ruler,
  569                              gdouble lower, gdouble upper, gdouble position) {
  570     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  571 
  572     g_object_freeze_notify (G_OBJECT (ruler));
  573     if (ruler->priv->lower != lower) {
  574         ruler->priv->lower = lower;
  575         g_object_notify (G_OBJECT (ruler), "lower");
  576     }
  577     if (ruler->priv->upper != upper) {
  578         ruler->priv->upper = upper;
  579         g_object_notify (G_OBJECT (ruler), "upper");
  580     }
  581     if (ruler->priv->position != position) {
  582         ruler->priv->position = position;
  583         g_object_notify (G_OBJECT (ruler), "position");
  584     }
  585     g_object_thaw_notify (G_OBJECT (ruler));
  586 
  587     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  588         gtk_widget_queue_draw (GTK_WIDGET (ruler));
  589 }
  590 
  591 /**
  592  * gtk_databox_ruler_set_max_length:
  593  * @ruler: A #GtkDataboxRuler widget
  594  * @max_length: Maximum length (digits) of tick labels
  595  *
  596  * This function sets the maximum number of digits to be used for each tick
  597  * label of the @ruler.
  598  *
  599  * The @max_length cannot be smaller than 2 and not bigger than
  600  * #GTK_DATABOX_RULER_MAX_MAX_LENGTH.
  601  *
  602  */
  603 void
  604 gtk_databox_ruler_set_max_length (GtkDataboxRuler * ruler, guint max_length) {
  605     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  606     g_return_if_fail (max_length < GTK_DATABOX_RULER_MAX_MAX_LENGTH + 1);
  607 
  608     g_object_freeze_notify (G_OBJECT (ruler));
  609     if (ruler->priv->max_length != max_length) {
  610         ruler->priv->max_length = max_length;
  611         g_object_notify (G_OBJECT (ruler), "max-length");
  612     }
  613     g_object_thaw_notify (G_OBJECT (ruler));
  614 
  615     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  616         gtk_widget_queue_draw (GTK_WIDGET (ruler));
  617 }
  618 
  619 /**
  620  * gtk_databox_ruler_set_scale_type:
  621  * @ruler: A #GtkDataboxRuler widget
  622  * @scale_type: The new scale type for @ruler (linear or logarithmic)
  623  *
  624  * This function sets the scale type of the @ruler.
  625  *
  626  */
  627 void
  628 gtk_databox_ruler_set_scale_type (GtkDataboxRuler * ruler,
  629                                   GtkDataboxScaleType scale_type) {
  630     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  631 
  632     if (ruler->priv->scale_type != scale_type) {
  633         ruler->priv->scale_type = scale_type;
  634         /* g_object_notify (G_OBJECT (ruler), "scale-type"); */
  635     }
  636 
  637     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  638         gtk_widget_queue_draw (GTK_WIDGET (ruler));
  639 }
  640 
  641 /**
  642  * gtk_databox_ruler_set_orientation:
  643  * @ruler: a #GtkDataboxRuler
  644  * @orientation: new orientation of the ruler
  645  *
  646  * Sets the orientation of the @ruler (horizontal or vertical).
  647  **/
  648 void
  649 gtk_databox_ruler_set_orientation (GtkDataboxRuler * ruler,
  650                                    GtkOrientation orientation) {
  651     GtkWidget *widget;
  652     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  653 
  654     if (ruler->priv->orientation != orientation) {
  655         ruler->priv->orientation = orientation;
  656         g_object_notify (G_OBJECT (ruler), "orientation");
  657     }
  658 
  659     widget = GTK_WIDGET (ruler);
  660 
  661     // get the padding
  662     GtkRequisition gtkRequisition;
  663     GtkStyleContext *context= gtk_widget_get_style_context (widget);
  664     GtkBorder padding;
  665     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
  666 
  667     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
  668         gtkRequisition.width = (padding.left+padding.right) * 2 + 1;
  669         gtkRequisition.height = (padding.top+padding.bottom) * 2 + RULER_SIZE;
  670     } else {
  671             gtkRequisition.height = (padding.top+padding.bottom) * 2 + 1;
  672         if (ruler->priv->max_y_text_width==0)
  673             gtkRequisition.width = (padding.left+padding.right) * 2 + RULER_SIZE;
  674         else
  675             gtkRequisition.width = (padding.left+padding.right) + ruler->priv->max_y_text_width;
  676     }
  677     gtk_widget_set_size_request(widget, gtkRequisition.width, gtkRequisition.height);
  678 
  679     if (gtk_widget_is_drawable (widget)) {
  680         gtk_widget_queue_resize (widget);
  681         gtk_widget_queue_draw (widget);
  682     }
  683 }
  684 
  685 static void gtk_databox_ruler_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
  686 {
  687     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
  688     GtkOrientation orientation;
  689     gint width;
  690     GtkStyleContext *context= gtk_widget_get_style_context (widget);
  691     GtkBorder padding;
  692     gint xthickness;
  693     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
  694     xthickness=padding.left+padding.right;
  695 
  696     orientation = ruler->priv->orientation;
  697 
  698     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
  699         width = xthickness * 2 + 1;
  700     }
  701     else
  702     {
  703         if (ruler->priv->max_y_text_width==0)
  704             width = xthickness * 2 + RULER_SIZE;
  705         else
  706             width = ruler->priv->max_y_text_width;
  707     }
  708         *minimal_width = *natural_width = width;
  709 }
  710 
  711 static void gtk_databox_ruler_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)
  712 {
  713     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
  714     GtkOrientation orientation;
  715     gint height;
  716 
  717     GtkStyleContext *context= gtk_widget_get_style_context (widget);
  718     GtkBorder padding;
  719     gint ythickness;
  720     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
  721     ythickness=padding.top+padding.bottom;
  722 
  723     orientation = ruler->priv->orientation;
  724 
  725     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
  726         height = ythickness * 2 + RULER_SIZE;
  727     } else {
  728         height = ythickness * 2 + 1;
  729     }
  730     *minimal_height = *natural_height = height;
  731 }
  732 
  733 
  734 /**
  735  * gtk_databox_ruler_get_orientation
  736  * @ruler: a #GtkDataboxRuler
  737  *
  738  * Gets the orientation of the @ruler (horizontal or vertical).
  739  *
  740  * Return value: Orientation of the @ruler.
  741  **/
  742 GtkOrientation
  743 gtk_databox_ruler_get_orientation (GtkDataboxRuler * ruler) {
  744 
  745     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  746 
  747     return ruler->priv->orientation;
  748 }
  749 
  750 /**
  751  * gtk_databox_ruler_set_text_orientation
  752  * @ruler: a #GtkDataboxRuler
  753  * @orientation: new orientation of the tick marks in the vertical ruler
  754  *
  755  * Sets the text orientation of the @ruler (vertical).
  756  **/
  757 void
  758 gtk_databox_ruler_set_text_orientation (GtkDataboxRuler * ruler,
  759                                         GtkOrientation orientation) {
  760     GtkWidget *widget;
  761     GtkRequisition gtkRequisition;
  762     GtkStyleContext *context;
  763     GtkBorder padding;
  764     gint minimal_height, natural_height;
  765 
  766     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  767 
  768     /* check this is a vertical ruler */
  769     if (ruler->priv->orientation != GTK_ORIENTATION_VERTICAL)
  770         return;
  771 
  772     if (ruler->priv->text_orientation != orientation) {
  773         ruler->priv->text_orientation = orientation;
  774         g_object_notify (G_OBJECT (ruler), "text-orientation");
  775     }
  776 
  777     widget = GTK_WIDGET (ruler);
  778 
  779     // get the padding
  780     context= gtk_widget_get_style_context (widget);
  781     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
  782     gtk_databox_ruler_get_preferred_height (widget, &minimal_height, &natural_height);
  783     gtkRequisition.height=natural_height;
  784     if (ruler->priv->max_y_text_width==0)
  785         gtkRequisition.width = (padding.left + padding.right) * 2 + RULER_SIZE;
  786     else
  787     {
  788         gtkRequisition.width = ruler->priv->max_y_text_width;
  789     }
  790     gtk_widget_set_size_request(widget, gtkRequisition.width, gtkRequisition.height);
  791 
  792     if (gtk_widget_is_drawable (widget))
  793         gtk_widget_queue_draw (widget);
  794 }
  795 
  796 /**
  797  * gtk_databox_ruler_get_text_orientation
  798  * @ruler: a #GtkDataboxRuler
  799  *
  800  * Gets the text orientation of the @ruler (horizontal or vertical).
  801  * Horizontal rulers always have horizontal text
  802  *
  803  * Return value: Text orientation of the @ruler.
  804  **/
  805 GtkOrientation
  806 gtk_databox_ruler_get_text_orientation (GtkDataboxRuler * ruler) {
  807 
  808     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  809 
  810     return ruler->priv->text_orientation;
  811 }
  812 
  813 /**
  814  * gtk_databox_ruler_set_text_alignment
  815  * @ruler: a #GtkDataboxRuler
  816  * @alignment: new alignment of the tick label in the vertical ruler when horizontal text is set
  817  *
  818  * Sets the text alignment of the @ruler (vertical with horizontal text).
  819  **/
  820 void
  821 gtk_databox_ruler_set_text_alignment (GtkDataboxRuler * ruler,
  822                                         PangoAlignment alignment) {
  823     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  824 
  825     /* check this is a vertical ruler */
  826     if (ruler->priv->orientation != GTK_ORIENTATION_VERTICAL)
  827         return;
  828 
  829     if (ruler->priv->text_alignment != alignment) {
  830         ruler->priv->text_alignment = alignment;
  831         g_object_notify (G_OBJECT (ruler), "text-alignment");
  832     }
  833 
  834     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  835         gtk_widget_queue_draw (GTK_WIDGET (ruler));
  836 }
  837 
  838 /**
  839  * gtk_databox_ruler_get_text_alignment
  840  * @ruler: a #GtkDataboxRuler
  841  *
  842  * Gets the text alignment of the @ruler (vertical).
  843  * Vertical rulers with vertical text do not use this flag
  844  *
  845  * Return value: Text alignment of the @ruler.
  846  **/
  847 PangoAlignment
  848 gtk_databox_ruler_get_text_alignment (GtkDataboxRuler * ruler) {
  849 
  850     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  851 
  852     return ruler->priv->text_alignment;
  853 }
  854 
  855 /**
  856  * gtk_databox_ruler_set_text_hoffset
  857  * @ruler: a #GtkDataboxRuler
  858  * @offset: new x offset of the tick label in the ruler
  859  *
  860  * Sets the text x (horizontal) offset of the @ruler.
  861  **/
  862 void
  863 gtk_databox_ruler_set_text_hoffset (GtkDataboxRuler * ruler,
  864                                         gint offset) {
  865     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  866 
  867     if (ruler->priv->text_hoffset != offset) {
  868         ruler->priv->text_hoffset = offset;
  869         g_object_notify (G_OBJECT (ruler), "text-hoffset");
  870     }
  871 
  872     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  873         gtk_widget_queue_draw (GTK_WIDGET (ruler));
  874 }
  875 
  876 /**
  877  * gtk_databox_ruler_get_text_hoffset
  878  * @ruler: a #GtkDataboxRuler
  879  *
  880  * Gets the text x (horizontal) offset of the @ruler.
  881  *
  882  * Return value: Text horizontal (x) offset of the @ruler.
  883  **/
  884 gint
  885 gtk_databox_ruler_get_text_hoffset (GtkDataboxRuler * ruler) {
  886 
  887     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  888 
  889     return ruler->priv->text_hoffset;
  890 }
  891 
  892 /**
  893  * gtk_databox_ruler_set_draw_position
  894  * @ruler: a #GtkDataboxRuler
  895  * @draw: whether to draw the position arrows on the ruler at all
  896  *
  897  * Sets the option for drawing the position arrows. If false, don't draw any arrows,
  898  * If true draw arrows.
  899  **/
  900 void
  901 gtk_databox_ruler_set_draw_position(GtkDataboxRuler * ruler, gboolean draw) {
  902     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  903 
  904     if (ruler->priv->draw_position!= draw) {
  905         ruler->priv->draw_position = draw;
  906         g_object_notify (G_OBJECT (ruler), "draw-position");
  907 
  908         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  909             gtk_widget_queue_draw (GTK_WIDGET (ruler));
  910     }
  911 }
  912 
  913 /**
  914  * gtk_databox_ruler_get_draw_position
  915  * @ruler: a #GtkDataboxRuler
  916  *
  917  * Gets the draw position arrows option from the @ruler (horizontal or vertical).
  918  *
  919  * Return value: Position drawing option of the @ruler.
  920  **/
  921 gboolean
  922 gtk_databox_ruler_get_draw_position(GtkDataboxRuler * ruler) {
  923 
  924     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  925 
  926     return ruler->priv->draw_position;
  927 }
  928 
  929 /**
  930  * gtk_databox_ruler_set_draw_ticks
  931  * @ruler: a #GtkDataboxRuler
  932  * @draw: whether to draw the ticks on the ruler at all
  933  *
  934  * Sets the option for drawing the ticks. If false, don't draw any ticks,
  935  * If true draw major ticks and subticks if the draw_subticks boolean is set.
  936  **/
  937 void
  938 gtk_databox_ruler_set_draw_ticks(GtkDataboxRuler * ruler, gboolean draw) {
  939     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  940 
  941     if (ruler->priv->draw_ticks!= draw) {
  942         ruler->priv->draw_ticks = draw;
  943         g_object_notify (G_OBJECT (ruler), "draw-ticks");
  944 
  945         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  946             gtk_widget_queue_draw (GTK_WIDGET (ruler));
  947     }
  948 }
  949 
  950 /**
  951  * gtk_databox_ruler_get_draw_ticks
  952  * @ruler: a #GtkDataboxRuler
  953  *
  954  * Gets the draw ticks option from the @ruler (horizontal or vertical).
  955  *
  956  * Return value: Tick drawing option of the @ruler.
  957  **/
  958 gboolean
  959 gtk_databox_ruler_get_draw_ticks(GtkDataboxRuler * ruler) {
  960 
  961     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  962 
  963     return ruler->priv->draw_ticks;
  964 }
  965 
  966 /**
  967  * gtk_databox_ruler_set_draw_subticks
  968  * @ruler: a #GtkDataboxRuler
  969  * @draw: whether to draw the subticks on the ruler
  970  *
  971  * Sets the option for drawing the subticks
  972  **/
  973 void
  974 gtk_databox_ruler_set_draw_subticks(GtkDataboxRuler * ruler, gboolean draw) {
  975     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
  976 
  977     if (ruler->priv->draw_subticks!= draw) {
  978         ruler->priv->draw_subticks = draw;
  979         g_object_notify (G_OBJECT (ruler), "draw-subticks");
  980 
  981         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
  982             gtk_widget_queue_draw (GTK_WIDGET (ruler));
  983     }
  984 }
  985 
  986 /**
  987  * gtk_databox_ruler_get_draw_subticks
  988  * @ruler: a #GtkDataboxRuler
  989  *
  990  * Gets the draw subticks option from the @ruler (horizontal or vertical).
  991  *
  992  * Return value: Subtick drawing option of the @ruler.
  993  **/
  994 gboolean
  995 gtk_databox_ruler_get_draw_subticks(GtkDataboxRuler * ruler) {
  996 
  997     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
  998 
  999     return ruler->priv->draw_subticks;
 1000 }
 1001 
 1002 /**
 1003  * gtk_databox_ruler_set_manual_ticks
 1004  * @ruler: a #GtkDataboxRuler
 1005  * @manual_ticks: sets the pointer to the hline values for the @ruler
 1006  *
 1007  * Sets the ticks for the @ruler (horizontal or vertical).
 1008  **/
 1009 void
 1010 gtk_databox_ruler_set_manual_ticks (GtkDataboxRuler * ruler, gfloat *manual_ticks) {
 1011     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1012 
 1013     ruler->priv->manual_ticks = manual_ticks;
 1014 
 1015     g_object_notify (G_OBJECT(ruler), "manual-ticks");
 1016 }
 1017 
 1018 /**
 1019  * gtk_databox_ruler_get_manual_ticks
 1020  * @ruler: a #GtkDataboxRuler
 1021  *
 1022  * Gets the pointer to the manual tick values for the @ruler.
 1023  *
 1024  * Return value: Pointer to the manual tick values for the @ruler.
 1025  **/
 1026 gfloat*
 1027 gtk_databox_ruler_get_manual_ticks (GtkDataboxRuler * ruler) {
 1028     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
 1029 
 1030     return ruler->priv->manual_ticks;
 1031 }
 1032 
 1033 /**
 1034  * gtk_databox_ruler_set_manual_tick_cnt
 1035  * @ruler: a #GtkDataboxRuler
 1036  * @manual_tick_cnt: sets the number of manual ticks for the @ruler
 1037  *
 1038  * Sets the number of manual ticks for the @ruler (horizontal or vertical).
 1039  **/
 1040 void
 1041 gtk_databox_ruler_set_manual_tick_cnt (GtkDataboxRuler *ruler, guint manual_tick_cnt) {
 1042     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1043 
 1044     ruler->priv->manual_tick_cnt = manual_tick_cnt;
 1045 
 1046     g_object_notify (G_OBJECT(ruler), "manual-tick-cnt");
 1047 }
 1048 
 1049 /**
 1050  * gtk_databox_ruler_get_manual_tick_cnt
 1051  * @ruler: a #GtkDataboxRuler
 1052  *
 1053  * Gets the number manual tick values for the @ruler.
 1054  *
 1055  * Return value: The number of manual tick values for the @ruler.
 1056  **/
 1057 guint
 1058 gtk_databox_ruler_get_manual_tick_cnt (GtkDataboxRuler * ruler) {
 1059     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
 1060 
 1061     return ruler->priv->manual_tick_cnt;
 1062 }
 1063 
 1064 /**
 1065  * gtk_databox_ruler_set_manual_tick_labels
 1066  * @ruler: a #GtkDataboxRuler
 1067  * @manual_tick_labels: sets the pointer to the labels for the ticks on the @ruler
 1068  *
 1069  * Note: This function should be preceeded by calls to gtk_databox_ruler_set_manual_ticks() and  gtk_databox_ruler_set_manual_tick_cnt().
 1070  *       The number of tick labels should match gtk_databox_ruler_get_manual_tick_cnt().
 1071  *
 1072  * Sets the tick labels of the @ruler (horizontal or vertical).
 1073  **/
 1074 void
 1075 gtk_databox_ruler_set_manual_tick_labels (GtkDataboxRuler *ruler, gchar **manual_tick_labels) {
 1076     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1077 
 1078     ruler->priv->manual_tick_labels = manual_tick_labels;
 1079 
 1080     g_object_notify (G_OBJECT(ruler), "manual-tick-labels");
 1081 }
 1082 
 1083 /**
 1084  * gtk_databox_ruler_get_manual_tick_labels
 1085  * @ruler: a #GtkDataboxRuler
 1086  *
 1087  * Gets the pointer to the manual tick labels for the @ruler.
 1088  *
 1089  * Return value: Pointer to the manual tick labels for the @ruler.
 1090  **/
 1091 gchar**
 1092 gtk_databox_ruler_get_manual_tick_labels (GtkDataboxRuler * ruler) {
 1093     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
 1094 
 1095     return ruler->priv->manual_tick_labels;
 1096 }
 1097 
 1098 /**
 1099  * gtk_databox_ruler_set_invert_edge
 1100  * @ruler: a #GtkDataboxRuler
 1101  * @invert: whether to draw the ruler detail with the edge inverted
 1102  *
 1103  * Sets the option for drawing the ruler detail on the opposite edge
 1104  **/
 1105 void
 1106 gtk_databox_ruler_set_invert_edge(GtkDataboxRuler * ruler, gboolean invert) {
 1107     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1108 
 1109     if (ruler->priv->invert_edge!= invert) {
 1110         ruler->priv->invert_edge = invert;
 1111         g_object_notify (G_OBJECT (ruler), "invert-edge");
 1112 
 1113         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
 1114             gtk_widget_queue_draw (GTK_WIDGET (ruler));
 1115     }
 1116 }
 1117 
 1118 /**
 1119  * gtk_databox_ruler_get_invert_edge
 1120  * @ruler: a #GtkDataboxRuler
 1121  *
 1122  * Gets the invert edge option from the @ruler (horizontal or vertical).
 1123  *
 1124  * Return value: Edge inversion option of the @ruler.
 1125  **/
 1126 gboolean
 1127 gtk_databox_ruler_get_invert_edge(GtkDataboxRuler * ruler) {
 1128 
 1129     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
 1130 
 1131     return ruler->priv->invert_edge;
 1132 }
 1133 
 1134 /**
 1135  * gtk_databox_ruler_set_linear_label_format
 1136  * @ruler: a #GtkDataboxRuler
 1137  * @format: How to format the labels for linear rulers
 1138  *
 1139  * Sets the meta @format string for the labels of linear rulers, for example "%%+-%dg" will become "%+-#g" where # is the int variable
 1140  **/
 1141 void
 1142 gtk_databox_ruler_set_linear_label_format(GtkDataboxRuler * ruler, gchar *format) {
 1143     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1144 
 1145     if (g_strcmp0(ruler->priv->linear_format, format)!=0) {
 1146         if (strlen(format)>FORMAT_LENGTH) {
 1147             g_warning("maximum format length = %d chars exceeded, truncating to the maximum from %d",FORMAT_LENGTH,(int)strlen(format));
 1148             format[FORMAT_LENGTH]='\0';
 1149         }
 1150 
 1151         g_stpcpy(ruler->priv->linear_format, format);
 1152         g_object_notify (G_OBJECT (ruler), "linear-label-format");
 1153 
 1154         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
 1155             gtk_widget_queue_draw (GTK_WIDGET (ruler));
 1156     }
 1157 }
 1158 
 1159 /**
 1160  * gtk_databox_ruler_get_linear_label_format
 1161  * @ruler: a #GtkDataboxRuler
 1162  *
 1163  * Gets the linear label meta format of the @ruler (horizontal or vertical).
 1164  *
 1165  * Return value: The string meta format the @ruler NULL on failure.
 1166  **/
 1167 gchar*
 1168 gtk_databox_ruler_get_linear_label_format(GtkDataboxRuler * ruler) {
 1169 
 1170     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
 1171 
 1172     return ruler->priv->linear_format;
 1173 }
 1174 
 1175 /**
 1176  * gtk_databox_ruler_set_log_label_format
 1177  * @ruler: a #GtkDataboxRuler
 1178  * @format: How to format the labels for log scaled rulers
 1179  *
 1180  * Sets the meta @format string for the labels of log scaled rulers, for example "%%-%dg" will become "%-#g" where # is the int variable
 1181  **/
 1182 void
 1183 gtk_databox_ruler_set_log_label_format(GtkDataboxRuler * ruler, gchar *format) {
 1184     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1185 
 1186     if (g_strcmp0(ruler->priv->log_format, format)!=0) {
 1187         if (strlen(format)>FORMAT_LENGTH) {
 1188             g_warning("maximum format length = %d chars exceeded, truncating to the maximum from %d",FORMAT_LENGTH,(int)strlen(format));
 1189             format[FORMAT_LENGTH]='\0';
 1190         }
 1191 
 1192         g_stpcpy(ruler->priv->log_format, format);
 1193         g_object_notify (G_OBJECT (ruler), "log-label-format");
 1194 
 1195         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
 1196             gtk_widget_queue_draw (GTK_WIDGET (ruler));
 1197     }
 1198 }
 1199 
 1200 /**
 1201  * gtk_databox_ruler_get_log_label_format
 1202  * @ruler: a #GtkDataboxRuler
 1203  *
 1204  * Gets the log label meta format of the @ruler (horizontal or vertical).
 1205  *
 1206  * Return value: The string meta format the @ruler, NULL on failure.
 1207  **/
 1208 gchar*
 1209 gtk_databox_ruler_get_log_label_format(GtkDataboxRuler * ruler) {
 1210 
 1211     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
 1212 
 1213     return ruler->priv->log_format;
 1214 }
 1215 
 1216 /**
 1217  * gtk_databox_ruler_get_range
 1218  * @ruler: a #GtkDataboxRuler
 1219  * @lower: location to store lower limit of the ruler, or %NULL
 1220  * @upper: location to store upper limit of the ruler, or %NULL
 1221  * @position: location to store the current position of the mark on the ruler, or %NULL
 1222  *
 1223  * Retrieves values indicating the range and current position of a #GtkDataboxRuler.
 1224  * See gtk_databox_ruler_set_range().
 1225  **/
 1226 void
 1227 gtk_databox_ruler_get_range (GtkDataboxRuler * ruler,
 1228                              gdouble * lower,
 1229                              gdouble * upper, gdouble * position) {
 1230     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1231 
 1232     if (lower)
 1233         *lower = ruler->priv->lower;
 1234     if (upper)
 1235         *upper = ruler->priv->upper;
 1236     if (position)
 1237         *position = ruler->priv->position;
 1238 }
 1239 
 1240 /**
 1241  * gtk_databox_ruler_get_max_length
 1242  * @ruler: A #GtkDataboxRuler widget
 1243  *
 1244  * This function returns the maximum number of digits to be used for each tick
 1245  * label of the @ruler.
 1246  *
 1247  * Return value: The maximum length of the tick labels.
 1248  *
 1249  */
 1250 guint
 1251 gtk_databox_ruler_get_max_length (GtkDataboxRuler * ruler) {
 1252     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), 0);
 1253 
 1254     return ruler->priv->max_length;
 1255 }
 1256 
 1257 /**
 1258  * gtk_databox_ruler_get_scale_type
 1259  * @ruler: A #GtkDataboxRuler widget
 1260  *
 1261  * This function returns the scale type of the @ruler (linear or logarithmic).
 1262  *
 1263  * Return value: The scale type (linear or logarithmic)
 1264  *
 1265  */
 1266 GtkDataboxScaleType
 1267 gtk_databox_ruler_get_scale_type (GtkDataboxRuler * ruler) {
 1268     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), 0);
 1269 
 1270     return ruler->priv->scale_type;
 1271 }
 1272 
 1273 /**
 1274  * gtk_databox_ruler_set_box_shadow
 1275  * @ruler: a #GtkDataboxRuler
 1276  * @which_shadow: How to render the box shadow on the ruler edges.
 1277  *
 1278  * Sets the shadow type when using gtk_paint_box. This will draw the desired edge shadow.
 1279  **/
 1280 void
 1281 gtk_databox_ruler_set_box_shadow(GtkDataboxRuler * ruler, GtkShadowType which_shadow) {
 1282     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
 1283     g_return_if_fail (which_shadow<=GTK_SHADOW_ETCHED_OUT);
 1284 
 1285     if (ruler->priv->box_shadow!=which_shadow) {
 1286         ruler->priv->box_shadow=which_shadow;
 1287         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
 1288             gtk_widget_queue_draw (GTK_WIDGET (ruler));
 1289     }
 1290 }
 1291 
 1292 /**
 1293  * gtk_databox_ruler_get_box_shadow
 1294  * @ruler: a #GtkDataboxRuler
 1295  *
 1296  * Gets the type of shadow being rendered to the @ruler (GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT).
 1297  *
 1298  * Return value: The currently used shadow type of the @ruler, -1 on failure.
 1299  **/
 1300 GtkShadowType
 1301 gtk_databox_ruler_get_box_shadow(GtkDataboxRuler * ruler) {
 1302 
 1303     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
 1304 
 1305     return ruler->priv->box_shadow;
 1306 }
 1307 
 1308 static void
 1309 gtk_databox_ruler_draw_ticks (GtkDataboxRuler * ruler) {
 1310     GtkWidget *widget = GTK_WIDGET (ruler);
 1311     cairo_t *cr;
 1312     GtkStyleContext *stylecontext = gtk_widget_get_style_context (widget);
 1313     gint i;
 1314     gint width, height;
 1315     gint xthickness;
 1316     gint ythickness;
 1317     gint length;
 1318     gdouble lower, upper;   /* Upper and lower limits */
 1319     gdouble increment;      /* pixel per value unit */
 1320     gint power;
 1321     gint digit;
 1322     gdouble subd_incr;
 1323     gdouble start, end, cur, cur_text;
 1324     gchar unit_str[GTK_DATABOX_RULER_MAX_MAX_LENGTH + 1];   /* buffer for writing numbers */
 1325     gint digit_width;
 1326     gint text_width;
 1327     gint pos;
 1328     gint y_loc, x_loc;
 1329     gint subtick_start;
 1330     gchar format_string[FORMAT_LENGTH];
 1331     PangoMatrix matrix = PANGO_MATRIX_INIT;
 1332     PangoContext *context;
 1333     PangoLayout *layout;
 1334     PangoRectangle logical_rect, ink_rect;
 1335     GtkAllocation allocation;
 1336     GdkRGBA fg_color;
 1337 
 1338     GtkBorder padding;
 1339     gtk_style_context_get_padding (stylecontext, gtk_widget_get_state_flags (widget), &padding);
 1340     xthickness=padding.left+padding.right;
 1341     ythickness=padding.top+padding.bottom;
 1342 
 1343     if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR)
 1344         if (ruler->priv->max_length==1)
 1345             g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->linear_format, ruler->priv->max_length);
 1346         else
 1347             g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->linear_format, ruler->priv->max_length - 1);
 1348     else if (ruler->priv->max_length==1)
 1349         g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->log_format, ruler->priv->max_length);
 1350     else
 1351         g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->log_format, ruler->priv->max_length - 1);
 1352 
 1353     if (!gtk_widget_is_drawable (GTK_WIDGET (ruler)))
 1354         return;
 1355 
 1356     gtk_widget_get_allocation(widget, &allocation);
 1357     stylecontext = gtk_widget_get_style_context(widget);
 1358 
 1359     layout = gtk_widget_create_pango_layout (widget, "E+-012456789");
 1360 
 1361     if ((ruler->priv->orientation == GTK_ORIENTATION_VERTICAL) && (ruler->priv->text_orientation == GTK_ORIENTATION_VERTICAL)) {
 1362         /* vertical ruler with vertical text */
 1363         context = gtk_widget_get_pango_context (widget);
 1364         pango_context_set_base_gravity (context, PANGO_GRAVITY_WEST);
 1365         pango_matrix_rotate (&matrix, 90.);
 1366         pango_context_set_matrix (context, &matrix);
 1367         pango_layout_context_changed(layout);
 1368     }
 1369 
 1370     pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
 1371 
 1372     digit_width = ceil ((logical_rect.width) / 12);
 1373 
 1374     width = allocation.width;
 1375     height = allocation.height;
 1376 
 1377     cr = cairo_create(ruler->priv->backing_surface);
 1378     gtk_render_background (stylecontext, cr, 0.0, 0.0, width, height);
 1379 
 1380     gtk_style_context_get_color(stylecontext, GTK_STATE_FLAG_NORMAL, &fg_color);
 1381     gdk_cairo_set_source_rgba (cr, &fg_color);
 1382 
 1383     gtk_render_frame(stylecontext, cr, 0.0, 0.0, width, height);
 1384 
 1385     /* only draw the bottom line IF we are drawing ticks */
 1386     if (ruler->priv->draw_ticks) {
 1387         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
 1388             cairo_rectangle (cr, 0, height - ythickness, width, ythickness);
 1389         }
 1390         else {
 1391             cairo_rectangle (cr, width-xthickness, 0, xthickness, height);
 1392         }
 1393     }
 1394 
 1395     if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR) {
 1396         upper = ruler->priv->upper;
 1397         lower = ruler->priv->lower;
 1398     } else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2) {
 1399         if (ruler->priv->upper <= 0 || ruler->priv->lower <= 0) {
 1400             g_warning
 1401             ("For logarithmic scaling, the visible limits must by larger than 0!");
 1402         }
 1403         upper = log2 (ruler->priv->upper);
 1404         lower = log2 (ruler->priv->lower);
 1405     } else {
 1406         if (ruler->priv->upper <= 0 || ruler->priv->lower <= 0) {
 1407             g_warning
 1408             ("For logarithmic scaling, the visible limits must by larger than 0!");
 1409         }
 1410         upper = log10 (ruler->priv->upper);
 1411         lower = log10 (ruler->priv->lower);
 1412     }
 1413 
 1414     if ((upper - lower) == 0)
 1415     {
 1416         cairo_destroy (cr);
 1417         g_object_unref (layout);
 1418         return;
 1419     }
 1420 
 1421     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1422         increment = (gdouble) width / (upper - lower);
 1423     else
 1424         increment = (gdouble) height / (upper - lower);
 1425 
 1426 
 1427     /* determine the scale, i.e. the distance between the most significant ticks
 1428      *
 1429      * the ticks have to be farther apart than the length of the displayed numbers
 1430      */
 1431     if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR) {
 1432         text_width = (ruler->priv->max_length) * digit_width + 1;
 1433 
 1434         for (power = -20; power < 21; power++) {
 1435             if ((digit = 1) * pow (10, power) * fabs (increment) > text_width)
 1436                 break;
 1437             if ((digit = 2.5) * pow (10, power) * fabs (increment) > text_width)
 1438                 break;
 1439             if ((digit = 5) * pow (10, power) * fabs (increment) > text_width)
 1440                 break;
 1441         }
 1442 
 1443 
 1444         if (power == 21) {
 1445             power = 20;
 1446             digit = 5;
 1447         }
 1448         subd_incr = digit * pow (10, power);
 1449     } else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2) {
 1450         subd_incr = 1.;
 1451     } else {
 1452         subd_incr = 1.;
 1453     }
 1454 
 1455     length = (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1456              ? height - 5 : width - 5;
 1457 
 1458     if (ruler->priv->manual_ticks==NULL)
 1459         if (lower < upper) {
 1460             start = floor (lower / subd_incr) * subd_incr;
 1461             end = ceil (upper / subd_incr) * subd_incr;
 1462         } else {
 1463             start = floor (upper / subd_incr) * subd_incr;
 1464             end = ceil (lower / subd_incr) * subd_incr;
 1465         }
 1466     else { /* we are manually setting the tick labels and marks. */
 1467         start = 0.;
 1468         end = (gfloat)ruler->priv->manual_tick_cnt-1;
 1469         subd_incr=1.;
 1470     }
 1471 
 1472 
 1473     for (cur = start; cur <= end; cur += subd_incr) {
 1474         if (ruler->priv->manual_ticks==NULL)
 1475             pos = ROUND (((cur_text=cur) - lower) * increment);
 1476         else {
 1477             /* manual ticks must be positioned according to the scale */
 1478             if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR)
 1479                 cur_text=ruler->priv->manual_ticks[(int)cur];
 1480             else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2)
 1481                 cur_text=log2(ruler->priv->manual_ticks[(int)cur]);
 1482             else
 1483                 cur_text=log10(ruler->priv->manual_ticks[(int)cur]);
 1484             pos = ROUND ((cur_text - lower) * increment);
 1485             cur_text=ruler->priv->manual_ticks[(int)cur];
 1486         }
 1487         /*draw main ticks*/
 1488         if (ruler->priv->draw_ticks) {
 1489             if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1490                 cairo_rectangle (cr, pos, height + ythickness - length, 1, length);
 1491             else
 1492                 cairo_rectangle (cr, width + xthickness - length, pos, length, 1);
 1493         }
 1494 
 1495 
 1496         /* draw label */
 1497         /* if manual tick labels are present, display them instead of calculated labels */
 1498         if ((ruler->priv->manual_ticks!=NULL) && (ruler->priv->manual_tick_cnt!=0) && (ruler->priv->manual_tick_labels!=NULL))
 1499             pango_layout_set_text (layout, ruler->priv->manual_tick_labels[(int)cur], -1);
 1500         else {
 1501             if ((ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR) || (ruler->priv->manual_ticks!=NULL)) {
 1502                 if (ABS (cur_text) < 0.1 * subd_incr)   /* Rounding errors occur and might make "0" look funny without this check */
 1503                     cur_text = 0;
 1504 
 1505                 g_snprintf (unit_str, ruler->priv->max_length + 1, format_string, cur_text);
 1506             } else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2)
 1507                 g_snprintf (unit_str, ruler->priv->max_length + 1, format_string, pow (2, cur_text));
 1508             else
 1509                 g_snprintf (unit_str, ruler->priv->max_length + 1, format_string, pow (10, cur_text));
 1510 
 1511             pango_layout_set_text (layout, unit_str, -1);
 1512         }
 1513         pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
 1514 
 1515         /* remember the pixel extents for sizing later. */
 1516         if ((ruler->priv->orientation == GTK_ORIENTATION_VERTICAL) & (ruler->priv->max_y_text_width<logical_rect.width)) {
 1517             if (ruler->priv->text_orientation ==GTK_ORIENTATION_VERTICAL)
 1518                 ruler->priv->max_y_text_width=logical_rect.height;
 1519             else
 1520                 ruler->priv->max_y_text_width=logical_rect.width;
 1521             gtk_widget_set_size_request(GTK_WIDGET(ruler), ruler->priv->max_y_text_width, ruler->priv->max_x_text_height);
 1522         } else if (ruler->priv->max_x_text_height<logical_rect.height) {
 1523             ruler->priv->max_x_text_height=logical_rect.height;
 1524             gtk_widget_set_size_request(GTK_WIDGET(ruler), ruler->priv->max_y_text_width, ruler->priv->max_x_text_height);
 1525         }
 1526 
 1527 
 1528 
 1529         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL){
 1530             if (!ruler->priv->draw_ticks) /* if ticks aren't present, draw a little lower */
 1531                 pos=pos - logical_rect.width+2+ruler->priv->text_hoffset;
 1532             gtk_render_layout(stylecontext, cr, pos + 2, ythickness - 1, layout);
 1533         } else {
 1534             y_loc=pos - logical_rect.width - 2; /* standard vertical text y alignment */
 1535             /*y_loc=pos-2;*/ /* standard vertical text y alignment */
 1536             if (ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) /* if ticks are present, then draw a little higher */
 1537                 y_loc=pos - logical_rect.width*2/3; /* horizontal text y alignment */
 1538             if ((ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) & (!ruler->priv->draw_ticks)) /* if ticks aren't present, draw a little lower */
 1539                 y_loc=pos - logical_rect.width/3;
 1540 
 1541             x_loc=xthickness-1+ruler->priv->text_hoffset;
 1542             if ((ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) & (ruler->priv->text_alignment == PANGO_ALIGN_RIGHT)) /* set right adjusted text */
 1543                 x_loc=width-ink_rect.width-2+ruler->priv->text_hoffset; /* shift 2 pixels left to give a better aesthetic */
 1544             if ((ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) & (ruler->priv->text_alignment == PANGO_ALIGN_CENTER)) /* set centrally adjusted text */
 1545                 x_loc=(width-ink_rect.width)/2-2+ruler->priv->text_hoffset;
 1546             gtk_render_layout(stylecontext, cr, x_loc, y_loc, layout);
 1547         }
 1548 
 1549         /* Draw sub-ticks */
 1550         if (ruler->priv->draw_subticks & ruler->priv->draw_ticks) {
 1551             if (!ruler->priv->invert_edge) /* sub-ticks on the bottom */
 1552                 subtick_start=length / 2;
 1553             else
 1554                 subtick_start=length;
 1555 
 1556             if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR)
 1557                 for (i = 1; i < 5; ++i) {
 1558                     pos = ROUND ((cur - lower + subd_incr / 5 * i) * increment);
 1559 
 1560                     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1561                         cairo_rectangle (cr, pos, height + ythickness - subtick_start, 1, length / 2);
 1562                     else
 1563                         cairo_rectangle (cr, width + xthickness - subtick_start, pos, length / 2, 1);
 1564                 }
 1565             else  if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2)
 1566                 for (i = 1; i < 8; ++i) {
 1567                     pos = ROUND ((cur - lower + log2 (i)) * increment);
 1568 
 1569                     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1570                         cairo_rectangle (cr, pos, height + ythickness - subtick_start, 1, length / 2);
 1571                     else
 1572                         cairo_rectangle (cr, width + xthickness - subtick_start, pos, length / 2, 1);
 1573                 }
 1574             else
 1575                 for (i = 2; i < 10; ++i) {
 1576                     pos = ROUND ((cur - lower + log10 (i)) * increment);
 1577 
 1578                     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1579                         cairo_rectangle (cr, pos, height + ythickness - subtick_start, 1, length / 2);
 1580                     else
 1581                         cairo_rectangle (cr, width + xthickness - subtick_start, pos, length / 2, 1);
 1582                 }
 1583         }
 1584     }
 1585 
 1586     cairo_fill (cr);
 1587 //out:
 1588     cairo_destroy (cr);
 1589     g_object_unref (layout);
 1590 }
 1591 
 1592 static void
 1593 gtk_databox_ruler_draw_pos (GtkDataboxRuler * ruler) {
 1594     GtkWidget *widget = GTK_WIDGET (ruler);
 1595     GtkStyleContext *stylecontext = gtk_widget_get_style_context(widget);
 1596     gint x, y;
 1597     gint width, height;
 1598     gint bs_width, bs_height;
 1599     gint ythickness;
 1600     gdouble increment;
 1601     GdkDrawingContext *drawc;
 1602     cairo_region_t *crr;
 1603     cairo_t *cr;
 1604     GtkAllocation allocation;
 1605     GdkRGBA fg_color;
 1606 
 1607     GtkStyleContext *context= gtk_widget_get_style_context (widget);
 1608     GtkBorder padding;
 1609     gint xthickness;
 1610     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
 1611     xthickness=padding.left+padding.right;
 1612     ythickness=padding.top+padding.bottom;
 1613 
 1614     if (gtk_widget_is_drawable (widget)) {
 1615         gtk_widget_get_allocation(widget, &allocation);
 1616         width = allocation.width - xthickness * 2;
 1617         height = allocation.height - ythickness * 2;
 1618 
 1619         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
 1620             bs_width = height / 2 + 2;
 1621             bs_width |= 1;      /* make sure it's odd */
 1622             bs_height = bs_width / 2 + 1;
 1623             if (ruler->priv->invert_edge)
 1624                 bs_height=-bs_height;
 1625         } else {
 1626             bs_height = width / 2 + 2;
 1627             bs_height |= 1; /* make sure it's odd */
 1628             bs_width = bs_height / 2 + 1;
 1629             if (ruler->priv->invert_edge)
 1630                 bs_width=-bs_width;
 1631         }
 1632 
 1633         if (!ruler->priv->invert_edge && (bs_width < 0) && (bs_height < 0))
 1634             return; /* return if negative values and not inverted */
 1635 
 1636         if (ruler->priv->invert_edge && (bs_width > 0) && (bs_height > 0))
 1637             return; /* return if positive values and inverted */
 1638 
 1639         crr = gdk_window_get_visible_region (gtk_widget_get_window (widget));
 1640         drawc = gdk_window_begin_draw_frame (gtk_widget_get_window (widget), crr);
 1641         cr = gdk_drawing_context_get_cairo_context (drawc);
 1642 
 1643         /*  If a backing store exists, restore the ruler  */
 1644         if (ruler->priv->backing_surface)
 1645         {
 1646 /* TODO: HERE WE SHOULD REALLY CLIP THIS TO THE RECTANGLE OF THE ARROW */
 1647             cairo_set_source_surface(cr, ruler->priv->backing_surface, 0, 0);
 1648             cairo_paint(cr);
 1649         }
 1650 
 1651         gtk_style_context_get_color(stylecontext, gtk_style_context_get_state(stylecontext), &fg_color);
 1652         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
 1653             increment = (gdouble) width / (ruler->priv->upper - ruler->priv->lower);
 1654 
 1655             x = ROUND ((ruler->priv->position - ruler->priv->lower) * increment) +
 1656                 (xthickness - bs_width) / 2 - 1;
 1657             y = (height + bs_height) / 2 + ythickness;
 1658 
 1659             gdk_cairo_set_source_rgba (cr, &fg_color);
 1660 
 1661             cairo_move_to (cr, x, y);
 1662             cairo_line_to (cr, x + bs_width / 2., y + bs_height);
 1663             cairo_line_to (cr, x + bs_width, y);
 1664         } else {
 1665             increment = (gdouble) height / (ruler->priv->upper - ruler->priv->lower);
 1666 
 1667             x = (width + bs_width) / 2 + xthickness;
 1668             y = ROUND ((ruler->priv->position - ruler->priv->lower) * increment) +
 1669                 (ythickness - bs_height) / 2 - 1;
 1670 
 1671             gdk_cairo_set_source_rgba (cr, &fg_color);
 1672 
 1673             cairo_move_to (cr, x, y);
 1674             cairo_line_to (cr, x + bs_width, y + bs_height / 2.);
 1675             cairo_line_to (cr, x, y + bs_height);
 1676         }
 1677         cairo_fill (cr);
 1678 
 1679         gdk_window_end_draw_frame (gtk_widget_get_window (widget), drawc);
 1680         cairo_region_destroy (crr);
 1681 
 1682         /* remember the rectangle of the arrow - so that it may be cleared on re-run */
 1683         ruler->priv->xsrc = x;
 1684         ruler->priv->ysrc = y;
 1685         if (ruler->priv->invert_edge) { /* inverted edges need clearing in the negative direction */
 1686             if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
 1687                 ruler->priv->ysrc = y+bs_height; /* bs_height is negative */
 1688             else
 1689                 ruler->priv->xsrc = x+bs_width; /* bs_width is negative */
 1690         }
 1691     }
 1692 }
 1693 
 1694 
 1695 static void
 1696 gtk_databox_ruler_realize (GtkWidget * widget) {
 1697     GtkDataboxRuler *ruler;
 1698     GdkWindowAttr attributes;
 1699     gint attributes_mask;
 1700     GtkAllocation allocation;
 1701     GtkStyleContext *stylecontext;
 1702 
 1703     ruler = GTK_DATABOX_RULER (widget);
 1704     gtk_widget_set_realized(GTK_WIDGET (ruler), TRUE);
 1705     gtk_widget_get_allocation(widget, &allocation);
 1706 
 1707     attributes.window_type = GDK_WINDOW_CHILD;
 1708     attributes.x = allocation.x;
 1709     attributes.y = allocation.y;
 1710     attributes.width = allocation.width;
 1711     attributes.height = allocation.height;
 1712     attributes.wclass = GDK_INPUT_OUTPUT;
 1713     attributes.visual = gtk_widget_get_visual (widget);
 1714     attributes.event_mask = gtk_widget_get_events (widget);
 1715     attributes.event_mask |= (GDK_EXPOSURE_MASK |
 1716                               GDK_POINTER_MOTION_MASK |
 1717                               GDK_POINTER_MOTION_HINT_MASK);
 1718 
 1719     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
 1720 
 1721     gtk_widget_set_window(widget,
 1722         gdk_window_new (gtk_widget_get_parent_window (widget), &attributes,
 1723                         attributes_mask));
 1724     gdk_window_set_user_data (gtk_widget_get_window(widget), ruler);
 1725 
 1726     stylecontext = gtk_widget_get_style_context(widget);
 1727 
 1728     gtk_style_context_add_class(stylecontext, GTK_STYLE_CLASS_BACKGROUND);
 1729 
 1730     gtk_databox_ruler_create_backing_surface (ruler);
 1731 }
 1732 
 1733 static void
 1734 gtk_databox_ruler_unrealize (GtkWidget * widget) {
 1735     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
 1736     gtk_widget_set_realized(widget, FALSE);
 1737 
 1738     if (ruler->priv->backing_surface)
 1739         cairo_surface_destroy (ruler->priv->backing_surface);
 1740     ruler->priv->backing_surface=NULL;
 1741 
 1742     if (GTK_WIDGET_CLASS (gtk_databox_ruler_parent_class)->unrealize)
 1743         (*GTK_WIDGET_CLASS (gtk_databox_ruler_parent_class)->unrealize) (widget);
 1744 }
 1745 
 1746 static void
 1747 gtk_databox_ruler_size_allocate (GtkWidget * widget,
 1748                                  GtkAllocation * allocation) {
 1749     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
 1750 
 1751     gtk_widget_set_allocation(widget, allocation);
 1752 
 1753     if (gtk_widget_get_realized (widget))
 1754         if (gtk_widget_is_drawable(widget)) {
 1755             gdk_window_move_resize (gtk_widget_get_window(widget),
 1756                                     allocation->x, allocation->y,
 1757                                     allocation->width, allocation->height);
 1758 
 1759             gtk_databox_ruler_create_backing_surface (ruler);
 1760         }
 1761 }
 1762 
 1763 static gint
 1764 gtk_databox_ruler_draw (GtkWidget * widget, cairo_t * cr){
 1765     GtkDataboxRuler *ruler;
 1766     GtkAllocation allocation;
 1767 
 1768     if (gtk_widget_is_drawable (widget)) {
 1769         ruler = GTK_DATABOX_RULER (widget);
 1770         gtk_widget_get_allocation(widget, &allocation);
 1771 
 1772         gtk_databox_ruler_draw_ticks (ruler);
 1773 
 1774         if (ruler->priv->backing_surface)
 1775         {
 1776             cairo_set_source_surface(cr, ruler->priv->backing_surface, 0, 0);
 1777             cairo_paint(cr);
 1778         }
 1779 
 1780 /* TODO: draw_pos also blits the backing_surface to the window, should make it happen only once) */
 1781         if (ruler->priv->draw_position)
 1782             gtk_databox_ruler_draw_pos (ruler);
 1783     }
 1784 
 1785     return FALSE;
 1786 }
 1787 
 1788 static void
 1789 gtk_databox_ruler_create_backing_surface (GtkDataboxRuler * ruler) {
 1790     GtkWidget *widget;
 1791     gint width;
 1792     gint height;
 1793     GtkAllocation allocation;
 1794     GdkDrawingContext *drawc;
 1795     cairo_region_t *crr;
 1796     cairo_t *cr;
 1797 
 1798     widget = GTK_WIDGET (ruler);
 1799     gtk_widget_get_allocation(widget, &allocation);
 1800     width = allocation.width;
 1801     height = allocation.height;
 1802 
 1803     if (ruler->priv->backing_surface) {
 1804         if ((width == ruler->priv->old_width) &&
 1805                 (height == ruler->priv->old_height))
 1806             return;
 1807 
 1808         cairo_surface_destroy(ruler->priv->backing_surface);
 1809     }
 1810 
 1811     ruler->priv->old_width = width;
 1812     ruler->priv->old_height = height;
 1813 
 1814     crr = gdk_window_get_visible_region (gtk_widget_get_window (widget));
 1815         drawc = gdk_window_begin_draw_frame (gtk_widget_get_window (widget), crr);
 1816         cr = gdk_drawing_context_get_cairo_context (drawc);
 1817 
 1818     ruler->priv->backing_surface = cairo_surface_create_similar(
 1819         cairo_get_target(cr),
 1820         CAIRO_CONTENT_COLOR,
 1821         width, height);
 1822 
 1823     ruler->priv->xsrc = 0;
 1824     ruler->priv->ysrc = 0;
 1825 
 1826     gdk_window_end_draw_frame (gtk_widget_get_window (widget), drawc);
 1827     cairo_region_destroy (crr);
 1828 }
 1829 
 1830 #define __GTK_DATABOX_RULER_C__