Replaced implementation of psppire-axis.
[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 static gint
44 get_unit_at_pixel (const PsppireAxis *axis, glong pixel)
45 {
46   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
47
48   unsigned long int start;
49
50   struct tower_node *n = tower_lookup (&a->pixel_tower, pixel, &start);
51
52   struct axis_node *an = tower_data (n, struct axis_node, pixel_node);
53
54   gfloat fraction = (pixel - start) / (gfloat) tower_node_get_size (&an->pixel_node);
55
56   return  tower_node_get_level (&an->unit_node) + fraction * tower_node_get_size (&an->unit_node);
57 }
58
59
60 static gint
61 unit_count (const PsppireAxis *axis)
62 {
63   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
64
65   return tower_height (&a->unit_tower);
66 }
67
68
69 /* Returns the pixel at the start of UNIT */
70 static glong
71 pixel_start (const PsppireAxis *axis, gint unit)
72 {
73   gfloat fraction;
74   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
75   struct tower_node *n ;
76   struct axis_node *an;
77
78   unsigned long int start;
79
80   if ( unit < 0)
81     return -1;
82
83   if ( unit >= unit_count (axis))
84     return -1;
85
86   n = tower_lookup (&a->unit_tower, unit, &start);
87
88   an = tower_data (n, struct axis_node, unit_node);
89
90   fraction = (unit - start) / (gfloat) tower_node_get_size (&an->unit_node);
91
92   return  tower_node_get_level (&an->pixel_node) +
93     nearbyintf (fraction * tower_node_get_size (&an->pixel_node));
94 }
95
96
97 static gint
98 unit_size (const PsppireAxis *axis, gint unit)
99 {
100   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
101   struct tower_node *n ;
102   struct axis_node *an;
103
104   unsigned long int start;
105
106   if ( unit < 0)
107     return 0;
108
109   if ( unit >= unit_count (axis))
110     return 0;
111
112   n = tower_lookup (&a->unit_tower, unit, &start);
113
114   an = tower_data (n, struct axis_node, unit_node);
115
116   return nearbyintf (tower_node_get_size (&an->pixel_node)
117                      / (float) tower_node_get_size (&an->unit_node));
118 }
119
120
121 static glong
122 total_size (const PsppireAxis *axis)
123 {
124   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (axis);
125
126   return tower_height (&a->pixel_tower);
127 }
128
129
130
131
132 static void
133 psppire_impl_iface_init (PsppireAxisIface *iface)
134 {
135   iface->unit_size = unit_size;
136   iface->unit_count = unit_count;
137   iface->pixel_start = pixel_start;
138   iface->get_unit_at_pixel = get_unit_at_pixel;
139   iface->total_size = total_size;
140 }
141
142 /* --- functions --- */
143 /**
144  * psppire_axis_impl_get_type:
145  * @returns: the type ID for accelerator groups.
146  */
147 GType
148 psppire_axis_impl_get_type (void)
149 {
150   static GType object_type = 0;
151
152   if (!object_type)
153     {
154       static const GTypeInfo object_info = {
155         sizeof (PsppireAxisImplClass),
156         (GBaseInitFunc) NULL,
157         (GBaseFinalizeFunc) NULL,
158         (GClassInitFunc) psppire_axis_impl_class_init,
159         NULL,   /* class_finalize */
160         NULL,   /* class_data */
161         sizeof (PsppireAxisImpl),
162         0,      /* n_preallocs */
163         (GInstanceInitFunc) psppire_axis_impl_init,
164       };
165
166       static const GInterfaceInfo interface_info =
167       {
168         (GInterfaceInitFunc) psppire_impl_iface_init,
169         NULL,
170         NULL
171       };
172
173
174       object_type = g_type_register_static (G_TYPE_PSPPIRE_AXIS,
175                                             "PsppireAxisImpl",
176                                             &object_info, 0);
177
178
179       g_type_add_interface_static (object_type,
180                                    PSPPIRE_TYPE_AXIS_IFACE,
181                                    &interface_info);
182     }
183
184   return object_type;
185 }
186
187 static void
188 psppire_axis_impl_class_init (PsppireAxisImplClass *class)
189 {
190   GObjectClass *object_class = G_OBJECT_CLASS (class);
191   parent_class = g_type_class_peek_parent (class);
192
193   object_class->finalize = psppire_axis_impl_finalize;
194 }
195
196
197 static void
198 psppire_axis_impl_init (PsppireAxisImpl *axis)
199 {
200   tower_init (&axis->pixel_tower);
201   tower_init (&axis->unit_tower);
202
203   axis->pool = pool_create ();
204 }
205
206
207 static void
208 psppire_axis_impl_finalize (GObject *object)
209 {
210   PsppireAxisImpl *a = PSPPIRE_AXIS_IMPL (object);
211   pool_destroy (a->pool);
212
213   G_OBJECT_CLASS (parent_class)->finalize (object);
214 }
215
216 /**
217  * psppire_axis_impl_new:
218  * @returns: a new #PsppireAxisImpl object
219  *
220  * Creates a new #PsppireAxisImpl.
221  */
222 PsppireAxisImpl*
223 psppire_axis_impl_new (void)
224 {
225   return g_object_new (G_TYPE_PSPPIRE_AXIS_IMPL, NULL);
226 }
227
228
229 \f
230
231 void
232 psppire_axis_impl_append (PsppireAxisImpl *a, gint size)
233 {
234   psppire_axis_impl_append_n (a, 1, size);
235 }
236
237
238 void
239 psppire_axis_impl_append_n (PsppireAxisImpl *a, gint n_units, gint size)
240 {
241   struct axis_node *node = pool_alloc (a->pool, sizeof *node);
242
243
244   tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL);
245   tower_insert (&a->pixel_tower, size * n_units, &node->pixel_node, NULL);
246 }
247
248
249 /* Split the node of both towers at POSN */
250 static void
251 split (PsppireAxisImpl *a, gint posn)
252 {
253   unsigned long int existing_unit_size;
254   unsigned long int existing_pixel_size;
255   unsigned long int start;
256   gfloat fraction;
257   struct axis_node *new_node ;
258   struct tower_node *n = tower_lookup (&a->unit_tower, posn, &start);
259
260   struct axis_node *existing_node =
261     tower_data (n, struct axis_node, unit_node);
262
263   /* Nothing needs to be done, if the range element is already split here */
264   if ( posn - start == 0)
265     return;
266
267   existing_unit_size = tower_node_get_size (&existing_node->unit_node);
268   existing_pixel_size = tower_node_get_size (&existing_node->pixel_node);
269
270   fraction = (posn - start) / (gfloat) existing_unit_size;
271
272   new_node = pool_alloc (a->pool, sizeof (*new_node));
273
274   tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start);
275
276   tower_resize (&a->pixel_tower, &existing_node->pixel_node,
277                 nearbyintf (fraction * existing_pixel_size));
278
279   tower_insert (&a->unit_tower,
280                 existing_unit_size - (posn - start),
281                 &new_node->unit_node,
282                 tower_next (&a->unit_tower, &existing_node->unit_node));
283
284
285   tower_insert (&a->pixel_tower,
286                 nearbyintf (existing_pixel_size * (1 - fraction)),
287                 &new_node->pixel_node,
288                 tower_next (&a->pixel_tower, &existing_node->pixel_node));
289 }
290
291
292 /* Insert a new unit of size SIZE before POSN */
293 void
294 psppire_axis_impl_insert (PsppireAxisImpl *a, gint posn, gint size)
295 {
296   struct tower_node *n;
297   unsigned long int start;
298   struct axis_node *before;
299   struct axis_node *new_node = pool_alloc (a->pool, sizeof (*new_node));
300
301   split (a, posn);
302
303   n = tower_lookup (&a->unit_tower, posn, &start);
304   g_assert (posn == start);
305
306   before = tower_data (n, struct axis_node, unit_node);
307
308   tower_insert (&a->unit_tower,
309                 1,
310                 &new_node->unit_node,
311                 &before->unit_node);
312
313
314   tower_insert (&a->pixel_tower,
315                 size,
316                 &new_node->pixel_node,
317                 &before->pixel_node);
318 }
319
320
321 /* Make the element at POSN singular.
322    Return a pointer to the node for this element */
323 static struct axis_node *
324 make_single (PsppireAxisImpl *a, gint posn)
325 {
326   unsigned long int start;
327   struct tower_node *n;
328   n = tower_lookup (&a->unit_tower, posn, &start);
329
330   if ( 1 != tower_node_get_size (n))
331     {
332       split (a, posn + 1);
333       n = tower_lookup (&a->unit_tower, posn, &start);
334
335       if ( 1 != tower_node_get_size (n))
336         {
337           split (a, posn);
338           n = tower_lookup (&a->unit_tower, posn, &start);
339         }
340     }
341
342   g_assert (1 == tower_node_get_size (n));
343
344
345   return tower_data (n, struct axis_node, unit_node);
346 }
347
348 void
349 psppire_axis_impl_resize (PsppireAxisImpl *a, gint posn, gint size)
350 {
351   struct axis_node *an =  make_single (a, posn);
352
353   tower_resize (&a->pixel_tower, &an->pixel_node, size);
354 }
355
356
357
358 void
359 psppire_axis_impl_clear (PsppireAxisImpl *a)
360 {
361   pool_destroy (a->pool);
362   a->pool = pool_create ();
363
364   tower_init (&a->pixel_tower);
365   tower_init (&a->unit_tower);
366 }
367
368
369
370 void
371 psppire_axis_impl_delete (PsppireAxisImpl *a, gint first, gint n_cases)
372 {
373   gint i;
374   g_warning ("%s FIXME: This is an inefficient implementation", __FUNCTION__);
375
376   for (i = first; i < first + n_cases; ++i)
377     {
378       struct axis_node *an = make_single (a, i);
379
380       tower_delete (&a->unit_tower, &an->unit_node);
381       tower_delete (&a->pixel_tower, &an->pixel_node);
382     }
383 }