More runtime warnings fixed
[pspp] / lib / gtksheet / psppire-axis-impl.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-impl.h"
24 #include <math.h>
25
26
27 /* --- prototypes --- */
28 static void psppire_axis_impl_class_init (PsppireAxisImplClass  *class);
29 static void psppire_axis_impl_init      (PsppireAxisImpl                *axis);
30 static void psppire_axis_impl_finalize   (GObject               *object);
31
32
33 /* --- variables --- */
34 static GObjectClass     *parent_class = NULL;
35
36
37 struct axis_node
38 {
39   struct tower_node pixel_node;
40   struct tower_node unit_node;
41 };
42
43 void
44 psppire_axis_impl_dump (const PsppireAxisImpl *a)
45 {
46   struct tower_node *n = tower_first (&a->unit_tower);
47
48   g_debug ("Axis %p", a);
49   while (n)
50     {
51       const struct axis_node *an = tower_data (n, struct axis_node, unit_node);
52       const struct tower_node *pn = &an->pixel_node;
53       g_debug ("%ld units of height %g",
54                n->size, pn->size / (float) n->size);
55
56       n =  tower_next (&a->unit_tower, n);
57     }
58   g_debug ("\n");
59 }
60
61 static gint
62 unit_at_pixel (const PsppireAxis *axis, glong pixel)
63 {
64   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
65
66   unsigned long int start;
67   struct tower_node *n;
68   struct axis_node *an;
69   gfloat fraction;
70
71   g_return_val_if_fail (pixel >= 0, -1);
72
73   n = tower_lookup (&a->pixel_tower, pixel, &start);
74   an = tower_data (n, struct axis_node, pixel_node);
75
76   fraction = (pixel - start) / (gfloat) tower_node_get_size (&an->pixel_node);
77
78   return  tower_node_get_level (&an->unit_node)
79     + fraction * tower_node_get_size (&an->unit_node);
80 }
81
82
83 static gint
84 unit_count (const PsppireAxis *axis)
85 {
86   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
87
88   return tower_height (&a->unit_tower);
89 }
90
91
92 /* Returns the pixel at the start of UNIT */
93 static glong
94 start_pixel (const PsppireAxis *axis, gint unit)
95 {
96   gfloat fraction;
97   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
98   struct tower_node *n ;
99   struct axis_node *an;
100
101   unsigned long int start;
102
103   if ( unit < 0)
104     return -1;
105
106   if ( unit >= unit_count (axis))
107     return -1;
108
109   n = tower_lookup (&a->unit_tower, unit, &start);
110
111   an = tower_data (n, struct axis_node, unit_node);
112
113   fraction = (unit - start) / (gfloat) tower_node_get_size (&an->unit_node);
114
115   return  tower_node_get_level (&an->pixel_node) +
116     nearbyintf (fraction * tower_node_get_size (&an->pixel_node));
117 }
118
119
120 static gint
121 unit_size (const PsppireAxis *axis, gint unit)
122 {
123   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
124   struct tower_node *n ;
125   struct axis_node *an;
126
127   unsigned long int start;
128
129   if ( unit < 0)
130     return 0;
131
132   if ( unit >= unit_count (axis))
133     return 0;
134
135   n = tower_lookup (&a->unit_tower, unit, &start);
136
137   an = tower_data (n, struct axis_node, unit_node);
138
139   return nearbyintf (tower_node_get_size (&an->pixel_node)
140                      / (float) tower_node_get_size (&an->unit_node));
141 }
142
143
144 static glong
145 total_size (const PsppireAxis *axis)
146 {
147   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
148
149   return tower_height (&a->pixel_tower);
150 }
151
152
153 static void resize (PsppireAxis *axis, gint posn, glong size);
154
155
156
157 static void
158 psppire_impl_iface_init (PsppireAxisIface *iface)
159 {
160   iface->unit_size = unit_size;
161   iface->unit_count = unit_count;
162   iface->start_pixel = start_pixel;
163   iface->unit_at_pixel = unit_at_pixel;
164   iface->total_size = total_size;
165   iface->resize = resize;
166 }
167
168 /* --- functions --- */
169 /**
170  * psppire_axis_impl_get_type:
171  * @returns: the type ID for accelerator groups.
172  */
173 GType
174 psppire_axis_impl_get_type (void)
175 {
176   static GType object_type = 0;
177
178   if (!object_type)
179     {
180       static const GTypeInfo object_info = {
181         sizeof (PsppireAxisImplClass),
182         (GBaseInitFunc) NULL,
183         (GBaseFinalizeFunc) NULL,
184         (GClassInitFunc) psppire_axis_impl_class_init,
185         NULL,   /* class_finalize */
186         NULL,   /* class_data */
187         sizeof (PsppireAxisImpl),
188         0,      /* n_preallocs */
189         (GInstanceInitFunc) psppire_axis_impl_init,
190       };
191
192       static const GInterfaceInfo interface_info =
193       {
194         (GInterfaceInitFunc) psppire_impl_iface_init,
195         NULL,
196         NULL
197       };
198
199       object_type = g_type_register_static (G_TYPE_PSPPIRE_AXIS,
200                                             "PsppireAxisImpl",
201                                             &object_info, 0);
202
203       g_type_add_interface_static (object_type,
204                                    PSPPIRE_TYPE_AXIS_IFACE,
205                                    &interface_info);
206     }
207
208   return object_type;
209 }
210
211 static void
212 psppire_axis_impl_class_init (PsppireAxisImplClass *class)
213 {
214   GObjectClass *object_class = G_OBJECT_CLASS (class);
215   parent_class = g_type_class_peek_parent (class);
216
217   object_class->finalize = psppire_axis_impl_finalize;
218 }
219
220
221 static void
222 psppire_axis_impl_init (PsppireAxisImpl *axis)
223 {
224   tower_init (&axis->pixel_tower);
225   tower_init (&axis->unit_tower);
226
227   axis->pool = pool_create ();
228 }
229
230
231 static void
232 psppire_axis_impl_finalize (GObject *object)
233 {
234   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (object);
235   pool_destroy (a->pool);
236
237   G_OBJECT_CLASS (parent_class)->finalize (object);
238 }
239
240 /**
241  * psppire_axis_impl_new:
242  * @returns: a new #PsppireAxisImpl object
243  *
244  * Creates a new #PsppireAxisImpl.
245  */
246 PsppireAxisImpl*
247 psppire_axis_impl_new (void)
248 {
249   return g_object_new (G_TYPE_PSPPIRE_AXIS_IMPL, NULL);
250 }
251
252
253 \f
254
255 void
256 psppire_axis_impl_append (PsppireAxisImpl *a, gint size)
257 {
258   psppire_axis_impl_append_n (a, 1, size);
259 }
260
261
262 void
263 psppire_axis_impl_append_n (PsppireAxisImpl *a, gint n_units, gint size)
264 {
265   struct axis_node *node;
266
267   if  (n_units == 0)
268     return;
269
270   node = pool_malloc (a->pool, sizeof *node);
271
272   tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL);
273   tower_insert (&a->pixel_tower, size * n_units, &node->pixel_node, NULL);
274 }
275
276
277 /* Split the node of both towers at POSN */
278 static void
279 split (PsppireAxisImpl *a, gint posn)
280 {
281   unsigned long int existing_unit_size;
282   unsigned long int existing_pixel_size;
283   unsigned long int start;
284   gfloat fraction;
285   struct axis_node *new_node ;
286   struct tower_node *n;
287   struct axis_node *existing_node;
288
289   g_return_if_fail (posn <= tower_height (&a->unit_tower));
290
291   /* Nothing needs to be done */
292   if ( posn == 0 || posn  == tower_height (&a->unit_tower))
293     return;
294
295   n = tower_lookup (&a->unit_tower, posn, &start);
296
297   existing_node = tower_data (n, struct axis_node, unit_node);
298
299   /* Nothing needs to be done, if the range element is already split here */
300   if ( posn - start == 0)
301     return;
302
303   existing_unit_size = tower_node_get_size (&existing_node->unit_node);
304   existing_pixel_size = tower_node_get_size (&existing_node->pixel_node);
305
306   fraction = (posn - start) / (gfloat) existing_unit_size;
307
308   new_node = pool_malloc (a->pool, sizeof (*new_node));
309
310   tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start);
311
312   tower_resize (&a->pixel_tower, &existing_node->pixel_node,
313                 nearbyintf (fraction * existing_pixel_size));
314
315   tower_insert (&a->unit_tower,
316                 existing_unit_size - (posn - start),
317                 &new_node->unit_node,
318                 tower_next (&a->unit_tower, &existing_node->unit_node));
319
320
321   tower_insert (&a->pixel_tower,
322                 nearbyintf (existing_pixel_size * (1 - fraction)),
323                 &new_node->pixel_node,
324                 tower_next (&a->pixel_tower, &existing_node->pixel_node));
325 }
326
327
328 /* Insert a new unit of size SIZE before POSN */
329 void
330 psppire_axis_impl_insert (PsppireAxisImpl *a, gint posn, gint size)
331 {
332   struct axis_node *before = NULL;
333   struct axis_node *new_node;
334
335   g_return_if_fail ( posn >= 0);
336   g_return_if_fail ( posn <= tower_height (&a->unit_tower));
337
338   if ( posn < tower_height (&a->unit_tower))
339     {
340       unsigned long int start = 0;
341       struct tower_node *n;
342
343       split (a, posn);
344
345       n = tower_lookup (&a->unit_tower, posn, &start);
346       g_assert (posn == start);
347
348       before = tower_data (n, struct axis_node, unit_node);
349     }
350
351   new_node = pool_malloc (a->pool, sizeof (*new_node));
352
353   tower_insert (&a->unit_tower,
354                 1,
355                 &new_node->unit_node,
356                 before ? &before->unit_node : NULL);
357
358   tower_insert (&a->pixel_tower,
359                 size,
360                 &new_node->pixel_node,
361                 before ? &before->pixel_node : NULL);
362 }
363
364
365 /* Make the element at POSN singular.
366    Return a pointer to the node for this element */
367 static struct axis_node *
368 make_single (PsppireAxisImpl *a, gint posn)
369 {
370   unsigned long int start;
371   struct tower_node *n;
372
373   g_return_val_if_fail (posn < tower_height (&a->unit_tower), NULL);
374
375   n = tower_lookup (&a->unit_tower, posn, &start);
376
377   if ( 1 != tower_node_get_size (n))
378     {
379       split (a, posn + 1);
380       n = tower_lookup (&a->unit_tower, posn, &start);
381
382       if ( 1 != tower_node_get_size (n))
383         {
384           split (a, posn);
385           n = tower_lookup (&a->unit_tower, posn, &start);
386         }
387     }
388
389   g_assert (1 == tower_node_get_size (n));
390
391   return tower_data (n, struct axis_node, unit_node);
392 }
393
394
395 static void
396 resize (PsppireAxis *axis, gint posn, glong size)
397 {
398   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
399
400   struct axis_node *an;
401   g_return_if_fail (posn >= 0);
402   g_return_if_fail (size > 0);
403
404   /* Silently ignore this request if the position is greater than the number of
405      units in the axis */
406   if (posn >= tower_height (&a->unit_tower))
407     return ;
408
409   an = make_single (a, posn);
410
411   tower_resize (&a->pixel_tower, &an->pixel_node, size);
412 }
413
414
415 void
416 psppire_axis_impl_resize (PsppireAxisImpl *a, gint posn, gint size)
417 {
418   resize (PSPPIRE_AXIS (a), posn, size);
419 }
420
421
422
423
424 void
425 psppire_axis_impl_clear (PsppireAxisImpl *a)
426 {
427   pool_destroy (a->pool);
428   a->pool = pool_create ();
429
430   tower_init (&a->pixel_tower);
431   tower_init (&a->unit_tower);
432 }
433
434
435
436 void
437 psppire_axis_impl_delete (PsppireAxisImpl *a, gint first, gint n_units)
438 {
439   gint units_to_delete = n_units;
440   unsigned long int start;
441   struct tower_node *unit_node ;
442   g_return_if_fail (first + n_units <= tower_height (&a->unit_tower));
443
444   split (a, first);
445   split (a, first + n_units);
446
447   unit_node = tower_lookup (&a->unit_tower, first, &start);
448   g_assert (start == first);
449
450   while (units_to_delete > 0)
451     {
452       struct tower_node *next_unit_node;
453       struct axis_node *an = tower_data (unit_node,
454                                          struct axis_node, unit_node);
455
456       g_assert (unit_node == &an->unit_node);
457       g_assert (unit_node->size <= n_units);
458
459       units_to_delete -= unit_node->size;
460
461       next_unit_node = tower_next (&a->unit_tower, unit_node);
462
463       tower_delete (&a->unit_tower, unit_node);
464       tower_delete (&a->pixel_tower, &an->pixel_node);
465
466       pool_free (a->pool, an);
467
468       unit_node = next_unit_node;
469     }
470 }