619e8238dab5c66a5f6d10c738c1351a4fa0de4d
[pspp-builds.git] / 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   g_return_if_fail (n_units > 0);
268
269   node = pool_malloc (a->pool, sizeof *node);
270
271   tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL);
272   tower_insert (&a->pixel_tower, size * n_units, &node->pixel_node, NULL);
273 }
274
275
276 /* Split the node of both towers at POSN */
277 static void
278 split (PsppireAxisImpl *a, gint posn)
279 {
280   unsigned long int existing_unit_size;
281   unsigned long int existing_pixel_size;
282   unsigned long int start;
283   gfloat fraction;
284   struct axis_node *new_node ;
285   struct tower_node *n;
286   struct axis_node *existing_node;
287
288   g_return_if_fail (posn <= tower_height (&a->unit_tower));
289
290   /* Nothing needs to be done */
291   if ( posn == 0 || posn  == tower_height (&a->unit_tower))
292     return;
293
294   n = tower_lookup (&a->unit_tower, posn, &start);
295
296   existing_node = tower_data (n, struct axis_node, unit_node);
297
298   /* Nothing needs to be done, if the range element is already split here */
299   if ( posn - start == 0)
300     return;
301
302   existing_unit_size = tower_node_get_size (&existing_node->unit_node);
303   existing_pixel_size = tower_node_get_size (&existing_node->pixel_node);
304
305   fraction = (posn - start) / (gfloat) existing_unit_size;
306
307   new_node = pool_malloc (a->pool, sizeof (*new_node));
308
309   tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start);
310
311   tower_resize (&a->pixel_tower, &existing_node->pixel_node,
312                 nearbyintf (fraction * existing_pixel_size));
313
314   tower_insert (&a->unit_tower,
315                 existing_unit_size - (posn - start),
316                 &new_node->unit_node,
317                 tower_next (&a->unit_tower, &existing_node->unit_node));
318
319
320   tower_insert (&a->pixel_tower,
321                 nearbyintf (existing_pixel_size * (1 - fraction)),
322                 &new_node->pixel_node,
323                 tower_next (&a->pixel_tower, &existing_node->pixel_node));
324 }
325
326
327 /* Insert a new unit of size SIZE before POSN */
328 void
329 psppire_axis_impl_insert (PsppireAxisImpl *a, gint posn, gint size)
330 {
331   struct axis_node *before = NULL;
332   struct axis_node *new_node;
333
334   g_return_if_fail ( posn < tower_height (&a->unit_tower));
335   g_return_if_fail ( posn >= 0);
336
337   new_node = pool_malloc (a->pool, sizeof (*new_node));
338
339   if ( posn > 0)
340     {
341       unsigned long int start = 0;
342       struct tower_node *n;
343
344       split (a, posn);
345
346       n = tower_lookup (&a->unit_tower, posn, &start);
347       g_assert (posn == start);
348
349       before = tower_data (n, struct axis_node, unit_node);
350     }
351
352   tower_insert (&a->unit_tower,
353                 1,
354                 &new_node->unit_node,
355                 before ? &before->unit_node : NULL);
356
357   tower_insert (&a->pixel_tower,
358                 size,
359                 &new_node->pixel_node,
360                 before ? &before->pixel_node : NULL);
361 }
362
363
364 /* Make the element at POSN singular.
365    Return a pointer to the node for this element */
366 static struct axis_node *
367 make_single (PsppireAxisImpl *a, gint posn)
368 {
369   unsigned long int start;
370   struct tower_node *n;
371
372   g_return_val_if_fail (posn < tower_height (&a->unit_tower), NULL);
373
374   n = tower_lookup (&a->unit_tower, posn, &start);
375
376   if ( 1 != tower_node_get_size (n))
377     {
378       split (a, posn + 1);
379       n = tower_lookup (&a->unit_tower, posn, &start);
380
381       if ( 1 != tower_node_get_size (n))
382         {
383           split (a, posn);
384           n = tower_lookup (&a->unit_tower, posn, &start);
385         }
386     }
387
388   g_assert (1 == tower_node_get_size (n));
389
390   return tower_data (n, struct axis_node, unit_node);
391 }
392
393
394 static void
395 resize (PsppireAxis *axis, gint posn, glong size)
396 {
397   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
398
399   struct axis_node *an;
400   g_return_if_fail (posn >= 0);
401   g_return_if_fail (size > 0);
402
403   /* Silently ignore this request if the position is greater than the number of
404      units in the axis */
405   if (posn >= tower_height (&a->unit_tower))
406     return ;
407
408   an = make_single (a, posn);
409
410   tower_resize (&a->pixel_tower, &an->pixel_node, size);
411 }
412
413
414 void
415 psppire_axis_impl_resize (PsppireAxisImpl *a, gint posn, gint size)
416 {
417   resize (PSPPIRE_AXIS (a), posn, size);
418 }
419
420
421
422
423 void
424 psppire_axis_impl_clear (PsppireAxisImpl *a)
425 {
426   pool_destroy (a->pool);
427   a->pool = pool_create ();
428
429   tower_init (&a->pixel_tower);
430   tower_init (&a->unit_tower);
431 }
432
433
434
435 void
436 psppire_axis_impl_delete (PsppireAxisImpl *a, gint first, gint n_units)
437 {
438   gint units_to_delete = n_units;
439   unsigned long int start;
440   g_return_if_fail (first + n_units < tower_height (&a->unit_tower));
441
442   split (a, first);
443   split (a, first + n_units);
444
445   struct tower_node *unit_node = tower_lookup (&a->unit_tower, first, &start);
446   g_assert (start == first);
447
448   while (units_to_delete > 0)
449     {
450       struct tower_node *next_unit_node;
451       struct axis_node *an = tower_data (unit_node,
452                                          struct axis_node, unit_node);
453
454       g_assert (unit_node == &an->unit_node);
455       g_assert (unit_node->size <= n_units);
456
457       units_to_delete -= unit_node->size;
458
459       next_unit_node = tower_next (&a->unit_tower, unit_node);
460
461       tower_delete (&a->unit_tower, unit_node);
462       tower_delete (&a->pixel_tower, &an->pixel_node);
463
464       pool_free (a->pool, an);
465
466       unit_node = next_unit_node;
467     }
468 }