Written a proper implementation of psppire_axis_impl_delete
[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
200       object_type = g_type_register_static (G_TYPE_PSPPIRE_AXIS,
201                                             "PsppireAxisImpl",
202                                             &object_info, 0);
203
204
205       g_type_add_interface_static (object_type,
206                                    PSPPIRE_TYPE_AXIS_IFACE,
207                                    &interface_info);
208     }
209
210   return object_type;
211 }
212
213 static void
214 psppire_axis_impl_class_init (PsppireAxisImplClass *class)
215 {
216   GObjectClass *object_class = G_OBJECT_CLASS (class);
217   parent_class = g_type_class_peek_parent (class);
218
219   object_class->finalize = psppire_axis_impl_finalize;
220 }
221
222
223 static void
224 psppire_axis_impl_init (PsppireAxisImpl *axis)
225 {
226   tower_init (&axis->pixel_tower);
227   tower_init (&axis->unit_tower);
228
229   axis->pool = pool_create ();
230 }
231
232
233 static void
234 psppire_axis_impl_finalize (GObject *object)
235 {
236   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (object);
237   pool_destroy (a->pool);
238
239   G_OBJECT_CLASS (parent_class)->finalize (object);
240 }
241
242 /**
243  * psppire_axis_impl_new:
244  * @returns: a new #PsppireAxisImpl object
245  *
246  * Creates a new #PsppireAxisImpl.
247  */
248 PsppireAxisImpl*
249 psppire_axis_impl_new (void)
250 {
251   return g_object_new (G_TYPE_PSPPIRE_AXIS_IMPL, NULL);
252 }
253
254
255 \f
256
257 void
258 psppire_axis_impl_append (PsppireAxisImpl *a, gint size)
259 {
260   psppire_axis_impl_append_n (a, 1, size);
261 }
262
263
264 void
265 psppire_axis_impl_append_n (PsppireAxisImpl *a, gint n_units, gint size)
266 {
267   struct axis_node *node;
268
269   g_return_if_fail (n_units > 0);
270
271   node = pool_alloc (a->pool, sizeof *node);
272
273   tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL);
274   tower_insert (&a->pixel_tower, size * n_units, &node->pixel_node, NULL);
275 }
276
277
278 /* Split the node of both towers at POSN */
279 static void
280 split (PsppireAxisImpl *a, gint posn)
281 {
282   unsigned long int existing_unit_size;
283   unsigned long int existing_pixel_size;
284   unsigned long int start;
285   gfloat fraction;
286   struct axis_node *new_node ;
287   struct tower_node *n;
288   struct axis_node *existing_node;
289
290   g_return_if_fail (posn <= tower_height (&a->unit_tower));
291
292   /* Nothing needs to be done */
293   if ( posn == 0 || posn  == tower_height (&a->unit_tower))
294     return;
295
296   n = tower_lookup (&a->unit_tower, posn, &start);
297
298   existing_node = tower_data (n, struct axis_node, unit_node);
299
300   /* Nothing needs to be done, if the range element is already split here */
301   if ( posn - start == 0)
302     return;
303
304   existing_unit_size = tower_node_get_size (&existing_node->unit_node);
305   existing_pixel_size = tower_node_get_size (&existing_node->pixel_node);
306
307   fraction = (posn - start) / (gfloat) existing_unit_size;
308
309   new_node = pool_alloc (a->pool, sizeof (*new_node));
310
311   tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start);
312
313   tower_resize (&a->pixel_tower, &existing_node->pixel_node,
314                 nearbyintf (fraction * existing_pixel_size));
315
316   tower_insert (&a->unit_tower,
317                 existing_unit_size - (posn - start),
318                 &new_node->unit_node,
319                 tower_next (&a->unit_tower, &existing_node->unit_node));
320
321
322   tower_insert (&a->pixel_tower,
323                 nearbyintf (existing_pixel_size * (1 - fraction)),
324                 &new_node->pixel_node,
325                 tower_next (&a->pixel_tower, &existing_node->pixel_node));
326 }
327
328
329 /* Insert a new unit of size SIZE before POSN */
330 void
331 psppire_axis_impl_insert (PsppireAxisImpl *a, gint posn, gint size)
332 {
333   struct axis_node *before = NULL;
334   struct axis_node *new_node;
335
336   g_return_if_fail ( posn < tower_height (&a->unit_tower));
337   g_return_if_fail ( posn >= 0);
338
339   new_node = pool_alloc (a->pool, sizeof (*new_node));
340
341   if ( posn > 0)
342     {
343       unsigned long int start = 0;
344       struct tower_node *n;
345
346       split (a, posn);
347
348       n = tower_lookup (&a->unit_tower, posn, &start);
349       g_assert (posn == start);
350
351       before = tower_data (n, struct axis_node, unit_node);
352     }
353
354   tower_insert (&a->unit_tower,
355                 1,
356                 &new_node->unit_node,
357                 before ? &before->unit_node : NULL);
358
359
360   tower_insert (&a->pixel_tower,
361                 size,
362                 &new_node->pixel_node,
363                 before ? &before->pixel_node : NULL);
364 }
365
366
367 /* Make the element at POSN singular.
368    Return a pointer to the node for this element */
369 static struct axis_node *
370 make_single (PsppireAxisImpl *a, gint posn)
371 {
372   unsigned long int start;
373   struct tower_node *n;
374
375   g_return_val_if_fail (posn < tower_height (&a->unit_tower), NULL);
376
377   n = tower_lookup (&a->unit_tower, posn, &start);
378
379   if ( 1 != tower_node_get_size (n))
380     {
381       split (a, posn + 1);
382       n = tower_lookup (&a->unit_tower, posn, &start);
383
384       if ( 1 != tower_node_get_size (n))
385         {
386           split (a, posn);
387           n = tower_lookup (&a->unit_tower, posn, &start);
388         }
389     }
390
391   g_assert (1 == tower_node_get_size (n));
392
393
394   return tower_data (n, struct axis_node, unit_node);
395 }
396
397 static void
398 resize (PsppireAxis *axis, gint posn, glong size)
399 {
400   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
401
402   struct axis_node *an;
403   g_return_if_fail (posn >= 0);
404
405   /* Silently ignore this request if the position is greater than the number of
406      units in the axis */
407   if (posn >= tower_height (&a->unit_tower))
408     return ;
409
410   an = make_single (a, posn);
411
412   tower_resize (&a->pixel_tower, &an->pixel_node, size);
413 }
414
415
416 void
417 psppire_axis_impl_resize (PsppireAxisImpl *a, gint posn, gint size)
418 {
419   resize (PSPPIRE_AXIS (a), posn, size);
420 }
421
422
423
424
425 void
426 psppire_axis_impl_clear (PsppireAxisImpl *a)
427 {
428   pool_destroy (a->pool);
429   a->pool = pool_create ();
430
431   tower_init (&a->pixel_tower);
432   tower_init (&a->unit_tower);
433 }
434
435
436
437 void
438 psppire_axis_impl_delete (PsppireAxisImpl *a, gint first, gint n_units)
439 {
440   gint units_to_delete = n_units;
441   unsigned long int start;
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   struct tower_node *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
467       unit_node = next_unit_node;
468     }
469 }