5498525a0ef0e8e3ad1f7603591a5d88fb74be5a
[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 <libpspp/misc.h>
24 #include "psppire-axis.h"
25 #include <lib/gtksheet/psppire-marshal.h>
26 #include <gtk/gtk.h>
27
28
29
30 /* Signals */
31 enum
32   {
33     RESIZE_UNIT,
34     n_signals
35   };
36
37 static guint signals[n_signals] ;
38
39
40 #define PSPPIRE_AXIS_GET_IFACE(obj) \
41   (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PSPPIRE_TYPE_AXIS_IFACE, PsppireAxisIface))
42
43 GType
44 psppire_axis_iface_get_type (void)
45 {
46   static GType psppire_axis_iface_type = 0;
47
48   if (! psppire_axis_iface_type)
49     {
50       static const GTypeInfo psppire_axis_iface_info =
51       {
52         sizeof (PsppireAxisIface), /* class_size */
53         NULL,           /* base init */
54         NULL,           /* base_finalize */
55         NULL,
56         NULL,           /* class_finalize */
57         NULL,           /* class_data */
58         0,
59         0,              /* n_preallocs */
60         NULL
61       };
62
63       psppire_axis_iface_type =
64         g_type_register_static (G_TYPE_INTERFACE, "PsppireAxisIface",
65                                 &psppire_axis_iface_info, 0);
66     }
67
68   return psppire_axis_iface_type;
69 }
70
71 G_DEFINE_ABSTRACT_TYPE(PsppireAxis, psppire_axis, G_TYPE_OBJECT);
72
73
74
75 /* --- prototypes --- */
76 static void psppire_axis_class_init (PsppireAxisClass   *class);
77 static void psppire_axis_init   (PsppireAxis            *axis);
78 static void psppire_axis_finalize   (GObject            *object);
79
80
81 /* --- variables --- */
82 static GObjectClass     *parent_class = NULL;
83
84
85
86 enum
87   {
88     PROP_0,
89     PROP_MIN_EXTENT,
90     PROP_DEFAULT_SIZE
91   };
92
93
94 static void
95 psppire_axis_get_property (GObject         *object,
96                            guint            prop_id,
97                            GValue          *value,
98                            GParamSpec      *pspec)
99 {
100   PsppireAxis *axis = PSPPIRE_AXIS (object);
101
102   switch (prop_id)
103     {
104     case PROP_MIN_EXTENT:
105       g_value_set_long (value, axis->min_extent);
106       break;
107     case PROP_DEFAULT_SIZE:
108       g_value_set_int (value, axis->default_size);
109       break;
110     default:
111       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112       break;
113     };
114 }
115
116
117 static void
118 psppire_axis_set_property (GObject         *object,
119                            guint            prop_id,
120                            const GValue    *value,
121                            GParamSpec      *pspec)
122 {
123   PsppireAxis *axis = PSPPIRE_AXIS (object);
124
125   switch (prop_id)
126     {
127     case PROP_MIN_EXTENT:
128       axis->min_extent = g_value_get_long (value);
129       break;
130     case PROP_DEFAULT_SIZE:
131       axis->default_size = g_value_get_int (value);
132       break;
133     default:
134       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
135       break;
136     };
137 }
138
139 static void
140 psppire_axis_class_init (PsppireAxisClass *class)
141 {
142   GObjectClass *object_class = G_OBJECT_CLASS (class);
143   GParamSpec *min_extent_spec;
144   GParamSpec *default_size_spec;
145
146   object_class->set_property = psppire_axis_set_property;
147   object_class->get_property = psppire_axis_get_property;
148
149   min_extent_spec =
150     g_param_spec_long ("minimum-extent",
151                        "Minimum Extent",
152                        "The smallest extent to which the axis will provide units (typically set to the height/width of the associated widget).",
153                        0, G_MAXLONG,
154                        0,
155                        G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
156
157   g_object_class_install_property (object_class,
158                                    PROP_MIN_EXTENT,
159                                    min_extent_spec);
160
161
162   default_size_spec =
163     g_param_spec_int ("default-size",
164                       "Default Size",
165                       "The size given to units which haven't been explicity inserted",
166                       0, G_MAXINT,
167                       25,
168                       G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
169
170
171   g_object_class_install_property (object_class,
172                                    PROP_DEFAULT_SIZE,
173                                    default_size_spec);
174
175   parent_class = g_type_class_peek_parent (class);
176
177   object_class->finalize = psppire_axis_finalize;
178
179
180   signals[RESIZE_UNIT] =
181     g_signal_new ("resize-unit",
182                   G_TYPE_FROM_CLASS (object_class),
183                   G_SIGNAL_RUN_LAST,
184                   0,
185                   NULL, NULL,
186                   psppire_marshal_VOID__INT_LONG,
187                   G_TYPE_NONE,
188                   2,
189                   G_TYPE_INT,
190                   G_TYPE_LONG
191                   );
192 }
193
194
195 static void
196 psppire_axis_init (PsppireAxis *axis)
197 {
198 }
199
200
201 static void
202 psppire_axis_finalize (GObject *object)
203 {
204   G_OBJECT_CLASS (parent_class)->finalize (object);
205 }
206
207 gint
208 psppire_axis_unit_size (const PsppireAxis *a, gint unit)
209 {
210   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
211
212   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_size, -1);
213
214
215   if  (unit >= PSPPIRE_AXIS_GET_IFACE (a)->unit_count(a))
216     return a->default_size;
217
218   return PSPPIRE_AXIS_GET_IFACE (a)->unit_size (a, unit);
219 }
220
221 gint
222 psppire_axis_unit_count (const PsppireAxis *a)
223 {
224   glong padding = 0;
225   glong actual_size;
226
227   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
228   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_count, -1);
229
230   actual_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
231
232   if ( actual_size < a->min_extent )
233     padding = DIV_RND_UP (a->min_extent - actual_size, a->default_size);
234
235   return PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a) + padding;
236 }
237
238
239 /* Return the starting pixel of UNIT */
240 glong
241 psppire_axis_start_pixel (const PsppireAxis *a, gint unit)
242 {
243   gint the_count, total_size ;
244   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
245
246   the_count =  PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a);
247   total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
248
249   if ( unit >= the_count)
250     {
251       return  total_size + (unit - the_count) * a->default_size;
252     }
253
254   return PSPPIRE_AXIS_GET_IFACE (a)->start_pixel (a, unit);
255 }
256
257
258 /* Return the unit covered by PIXEL */
259 gint
260 psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel)
261 {
262   glong total_size;
263
264   g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
265
266   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a), -1);
267
268   g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_at_pixel, -1);
269
270   total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
271
272   if (pixel >= total_size)
273     {
274       gint n_items = PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a);
275       glong extra = pixel - total_size;
276
277       return n_items - 1 + DIV_RND_UP (extra,  a->default_size);
278     }
279
280   return PSPPIRE_AXIS_GET_IFACE (a)->unit_at_pixel (a, pixel);
281 }
282
283
284 /* Set UNIT to size SIZE */
285 void
286 psppire_axis_resize (PsppireAxis *a, gint unit, glong size)
287 {
288   g_return_if_fail (PSPPIRE_IS_AXIS (a));
289
290   g_return_if_fail (PSPPIRE_AXIS_GET_IFACE (a));
291
292   g_return_if_fail (size > 0);
293
294   if (PSPPIRE_AXIS_GET_IFACE (a)->resize)
295     PSPPIRE_AXIS_GET_IFACE (a)->resize (a, unit, size);
296
297
298   g_signal_emit (a, signals [RESIZE_UNIT], 0, unit, size);
299 }
300
301