d2fff5b2fbe96a824ffd90ca4d6bce53c48c0bdb
[claws.git] / src / gtk / gtkshruler.c
1 /* GtkSHRuler
2  *
3  *  Copyright (C) 2000-2004 Alfons Hoogervorst & The Sylpheed Claws Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20  
21 /* I derived this class from hruler. S in HRuler could be read as
22  * Sylpheed (sylpheed.good-day.net), but also [S]ettable HRuler.
23  * I basically ripped apart the draw_ticks member of HRuler; it
24  * now draws the ticks at ruler->max_size. so gtk_ruler_set_range's
25  * last parameter has the distance between two ticks (which is
26  * the width of the fixed font character!
27  * 
28  * -- Alfons
29  */
30
31 #include <math.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <gtk/gtkhruler.h>
35 #include "gtkshruler.h"
36
37 #define RULER_HEIGHT          14
38 #define MINIMUM_INCR          5
39 #define MAXIMUM_SUBDIVIDE     5
40 #define MAXIMUM_SCALES        10
41
42 #define ROUND(x) ((int) ((x) + 0.5))
43
44 static void gtk_shruler_class_init      (GtkSHRulerClass *klass);
45 static void gtk_shruler_init            (GtkSHRuler      *hruler);
46 static void gtk_shruler_draw_ticks      (GtkRuler        *ruler);
47 #if 0
48 static void gtk_shruler_draw_pos        (GtkRuler        *ruler);
49 #endif
50
51 GType
52 gtk_shruler_get_type(void)
53 {
54         static GType shruler_type = 0;
55
56         if ( !shruler_type ) {
57                 static const GTypeInfo shruler_info = {
58                         sizeof (GtkSHRulerClass),
59
60                         (GBaseInitFunc) NULL,
61                         (GBaseFinalizeFunc) NULL,
62
63                         (GClassInitFunc) gtk_shruler_class_init,
64                         (GClassFinalizeFunc) NULL,
65                         NULL,   /* class_data */
66
67                         sizeof (GtkSHRuler),
68                         0,      /* n_preallocs */
69                         (GInstanceInitFunc) gtk_shruler_init,
70                 };
71                 /* inherit from GtkHRuler */
72                 shruler_type = g_type_register_static (GTK_TYPE_HRULER, "GtkSHRuler", &shruler_info, (GTypeFlags)0);
73         }
74         return shruler_type;
75 }
76
77 static void
78 gtk_shruler_class_init(GtkSHRulerClass * klass)
79 {
80         GtkWidgetClass * widget_class;
81         GtkRulerClass * hruler_class;
82
83         widget_class = (GtkWidgetClass*) klass;
84         hruler_class = (GtkRulerClass*) klass;
85
86         /* just neglect motion notify events */
87         widget_class->motion_notify_event = NULL /* gtk_shruler_motion_notify */;
88
89         /* we want the old ruler draw ticks... */
90         /* ruler_class->draw_ticks = gtk_hruler_draw_ticks; */
91         hruler_class->draw_ticks = gtk_shruler_draw_ticks;
92         
93         /* unimplemented draw pos */
94         hruler_class->draw_pos = NULL;
95 /*
96         hruler_class->draw_pos = gtk_shruler_draw_pos;
97 */
98 }
99
100 static void
101 gtk_shruler_init (GtkSHRuler * shruler)
102 {
103         GtkWidget * widget;
104         
105         widget = GTK_WIDGET (shruler);
106         widget->requisition.width = widget->style->xthickness * 2 + 1;
107         widget->requisition.height = widget->style->ythickness * 2 + RULER_HEIGHT;
108 }
109
110
111 GtkWidget*
112 gtk_shruler_new(void)
113 {
114         return GTK_WIDGET( g_object_new( gtk_shruler_get_type(), NULL ) );
115 }
116
117 static void
118 gtk_shruler_draw_ticks(GtkRuler *ruler)
119 {
120         GtkWidget *widget;
121         GdkGC *gc, *bg_gc;
122         gint i;
123         gint width, height;
124         gint xthickness;
125         gint ythickness;
126         gint pos;
127
128         g_return_if_fail (ruler != NULL);
129         g_return_if_fail (GTK_IS_HRULER (ruler));
130
131         if (!GTK_WIDGET_DRAWABLE (ruler)) 
132                 return;
133
134         widget = GTK_WIDGET (ruler);
135         
136         gc = widget->style->fg_gc[GTK_STATE_NORMAL];
137         bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
138
139         xthickness = widget->style->xthickness;
140         ythickness = widget->style->ythickness;
141
142         width = widget->allocation.width;
143         height = widget->allocation.height - ythickness * 2;
144   
145         gtk_paint_box (widget->style, ruler->backing_store,
146                        GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
147                        NULL, widget, "hruler",
148                        0, 0, 
149                        widget->allocation.width, widget->allocation.height);
150
151 #if 0
152         gdk_draw_line (ruler->backing_store, gc,
153                        xthickness,
154                        height + ythickness,
155                        widget->allocation.width - xthickness,
156                        height + ythickness);
157 #endif
158
159         /* assume ruler->max_size has the char width */    
160         /* i is increment of char_width,  pos is label number
161          * y position is based on height of widget itself
162          */
163         for ( i = 0, pos = 0; i < widget->allocation.width - xthickness; i += ruler->max_size, pos++ ) {        
164                 int length = height / 4;
165         
166                 if ( pos % 10 == 0 ) length = ( 3 * height / 4 );
167                 else if (pos % 5 == 0 ) length = ( height / 2 );
168                 
169                 gdk_draw_line(ruler->backing_store, gc,
170                               i, height, 
171                               i, height - length);                      
172                 
173                 if ( pos % 10 == 0 ) {
174                         gchar buf[8];
175                         PangoLayout *layout;
176
177                         /* draw label */
178                         g_snprintf(buf, sizeof buf, "%d", pos);
179                         
180                         layout = gtk_widget_create_pango_layout
181                                         (GTK_WIDGET(ruler), buf);
182                         
183                         gdk_draw_layout(ruler->backing_store, gc, i + 2,
184                                         (height / 12),
185                                         layout);
186                         
187                         g_object_unref(layout);
188             }
189         }
190 }
191
192 /* gtk_ruler_set_pos() - does not work yet, need to reimplement 
193  * gtk_ruler_draw_pos(). */
194 void
195 gtk_shruler_set_pos(GtkSHRuler * ruler, gfloat pos)
196 {
197         GtkRuler * ruler_;
198         g_return_if_fail( ruler != NULL );
199         
200         ruler_ = GTK_RULER(ruler);
201         
202         if ( pos < ruler_->lower ) 
203                 pos = ruler_->lower;
204         if ( pos > ruler_->upper )
205                 pos = ruler_->upper;
206         
207         ruler_->position = pos; 
208         
209         /*  Make sure the ruler has been allocated already  */
210         if ( ruler_->backing_store != NULL )
211                 gtk_ruler_draw_pos(ruler_);
212 }