92eba59ba1043afba7c10e8175521a32f0449150
[pspp-builds.git] / lib / gtksheet / psppire-axis.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include <string.h>
19 #include <stdlib.h>
20
21 #include <libpspp/tower.h>
22 #include <libpspp/pool.h>
23 #include "psppire-axis.h"
24 #include <gtk/gtk.h>
25
26
27 #define PSPPIRE_AXIS_GET_IFACE(obj) \
28   (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PSPPIRE_TYPE_AXIS_IFACE, PsppireAxisIface))
29
30 GType
31 psppire_axis_iface_get_type (void)
32 {
33   static GType psppire_axis_iface_type = 0;
34
35   if (! psppire_axis_iface_type)
36     {
37       static const GTypeInfo psppire_axis_iface_info =
38       {
39         sizeof (PsppireAxisIface), /* class_size */
40         NULL,           /* base init */
41         NULL,           /* base_finalize */
42         NULL,
43         NULL,           /* class_finalize */
44         NULL,           /* class_data */
45         0,
46         0,              /* n_preallocs */
47         NULL
48       };
49
50       psppire_axis_iface_type =
51         g_type_register_static (G_TYPE_INTERFACE, "PsppireAxisIface",
52                                 &psppire_axis_iface_info, 0);
53     }
54
55   return psppire_axis_iface_type;
56 }
57
58 G_DEFINE_ABSTRACT_TYPE(PsppireAxis, psppire_axis, G_TYPE_OBJECT);
59
60
61
62 /* --- prototypes --- */
63 static void psppire_axis_class_init (PsppireAxisClass   *class);
64 static void psppire_axis_init   (PsppireAxis            *axis);
65 static void psppire_axis_finalize   (GObject            *object);
66
67
68 /* --- variables --- */
69 static GObjectClass     *parent_class = NULL;
70
71
72
73 enum
74   {
75     PROP_0,
76     PROP_MIN_EXTENT,
77     PROP_DEFAULT_SIZE
78   };
79
80
81 static void
82 psppire_axis_get_property (GObject         *object,
83                            guint            prop_id,
84                            GValue          *value,
85                            GParamSpec      *pspec)
86 {
87   PsppireAxis *axis = PSPPIRE_AXIS (object);
88
89   switch (prop_id)
90     {
91     case PROP_MIN_EXTENT:
92       g_value_set_long (value, axis->min_extent);
93       break;
94     case PROP_DEFAULT_SIZE:
95       g_value_set_int (value, axis->default_size);
96       break;
97     default:
98       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
99       break;
100     };
101 }
102
103
104 static void
105 psppire_axis_set_property (GObject         *object,
106                            guint            prop_id,
107                            const GValue    *value,
108                            GParamSpec      *pspec)
109 {
110   PsppireAxis *axis = PSPPIRE_AXIS (object);
111
112   switch (prop_id)
113     {
114     case PROP_MIN_EXTENT:
115       axis->min_extent = g_value_get_long (value);
116       break;
117     case PROP_DEFAULT_SIZE:
118       axis->default_size = g_value_get_int (value);
119       break;
120     default:
121       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122       break;
123     };
124 }
125
126 static void
127 psppire_axis_class_init (PsppireAxisClass *class)
128 {
129   GObjectClass *object_class = G_OBJECT_CLASS (class);
130   GParamSpec *min_extent_spec;
131   GParamSpec *default_size_spec;
132
133   object_class->set_property = psppire_axis_set_property;
134   object_class->get_property = psppire_axis_get_property;
135
136   min_extent_spec =
137     g_param_spec_long ("minimum-extent",
138                        "Minimum Extent",
139                        "The smallest extent to which the axis will provide units (typically set to the height/width of the associated widget).",
140                        0, G_MAXLONG,
141                        0,
142                        G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
143
144   g_object_class_install_property (object_class,
145                                    PROP_MIN_EXTENT,
146                                    min_extent_spec);
147
148
149   default_size_spec =
150     g_param_spec_int ("default-size",
151                       "Default Size",
152                       "The size given to units which haven't been explicity inserted",
153                       0, G_MAXINT,
154                       25,
155                       G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
156
157
158   g_object_class_install_property (object_class,
159                                    PROP_DEFAULT_SIZE,
160                                    default_size_spec);
161
162   parent_class = g_type_class_peek_parent (class);
163
164   object_class->finalize = psppire_axis_finalize;
165 }
166
167
168 static void
169 psppire_axis_init (PsppireAxis *axis)
170 {
171 }
172
173
174 static void
175 psppire_axis_finalize (GObject *object)
176 {
177   G_OBJECT_CLASS (parent_class)->finalize (object);
178 }
179
180 gint
181 psppire_axis_unit_size (const PsppireAxis *a, gint unit)
182 {
183   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
184
185   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_size, -1);
186
187
188   if  (unit >= PSPPIRE_AXIS_GET_IFACE (a)->unit_count(a))
189     return a->default_size;
190
191   return PSPPIRE_AXIS_GET_IFACE (a)->unit_size (a, unit);
192 }
193
194 gint
195 psppire_axis_unit_count (const PsppireAxis *a)
196 {
197   glong padding = 0;
198   glong actual_size;
199
200   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
201   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_count, -1);
202
203   actual_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
204
205   if ( actual_size < a->min_extent )
206     padding = (a->min_extent - actual_size) / a->default_size;
207
208   return PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a) + padding;
209 }
210
211
212 /* Return the starting pixel of UNIT */
213 glong
214 psppire_axis_pixel_start (const PsppireAxis *a, gint unit)
215 {
216   gint the_count, total_size ;
217   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
218
219   the_count =  PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a);
220   total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
221
222   if ( unit >= the_count)
223     {
224       return  total_size + (unit - the_count) * a->default_size;
225     }
226
227   //  g_print ("%s %d\n", __FUNCTION__, unit);
228
229   return PSPPIRE_AXIS_GET_IFACE (a)->pixel_start (a, unit);
230 }
231
232
233 /* Return the unit covered by PIXEL */
234 gint
235 psppire_axis_get_unit_at_pixel (const PsppireAxis *a, glong pixel)
236 {
237   glong total_size;
238
239   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
240
241   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a), -1);
242
243   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->get_unit_at_pixel, -1);
244
245   total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
246
247   if (pixel >= total_size)
248     {
249       gint n_items = PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a);
250       glong extra = pixel - total_size;
251
252       return n_items - 1 + extra / a->default_size;
253     }
254
255   return PSPPIRE_AXIS_GET_IFACE (a)->get_unit_at_pixel (a, pixel);
256 }