5ae84d00425089e8441321f287396ad77dbd1d2c
[pspp-builds.git] / src / ui / gui / sheet / psppire-axis.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 2009  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 <ui/gui/psppire-marshal.h>
22 #include <libpspp/tower.h>
23 #include <libpspp/pool.h>
24 #include "psppire-axis.h"
25 #include <math.h>
26 #include <libpspp/misc.h>
27
28
29 /* Signals */
30 enum
31   {
32     RESIZE_UNIT,
33     n_signals
34   };
35
36 static guint signals[n_signals] ;
37
38 /* --- prototypes --- */
39 static void psppire_axis_class_init (PsppireAxisClass   *class);
40 static void psppire_axis_init   (PsppireAxis            *axis);
41 static void psppire_axis_finalize   (GObject            *object);
42
43
44 /* --- variables --- */
45 static GObjectClass     *parent_class = NULL;
46
47
48 struct axis_node
49 {
50   struct tower_node pixel_node;
51   struct tower_node unit_node;
52 };
53
54 void
55 psppire_axis_dump (const PsppireAxis *a)
56 {
57   struct tower_node *n = tower_first (&a->unit_tower);
58
59   g_debug ("Axis %p", a);
60   while (n)
61     {
62       const struct axis_node *an = tower_data (n, struct axis_node, unit_node);
63       const struct tower_node *pn = &an->pixel_node;
64       g_debug ("%ld units of height %g",
65                n->size, pn->size / (gdouble) n->size);
66
67       n =  tower_next (&a->unit_tower, n);
68     }
69   g_debug ("\n");
70 }
71
72 /* Return the unit covered by PIXEL */
73 gint
74 psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel)
75 {
76   unsigned long int start;
77   struct tower_node *n;
78   struct axis_node *an;
79   gdouble fraction;
80
81   glong size = tower_height (&a->pixel_tower);
82
83   g_return_val_if_fail (pixel >= 0, -1);
84
85   if (pixel >= size)
86     {
87       gint n_items = tower_height (&a->unit_tower);
88       glong extra = pixel - size;
89
90       return n_items - 1 + DIV_RND_UP (extra,  a->default_size);
91     }
92
93
94   n = tower_lookup (&a->pixel_tower, pixel, &start);
95   an = tower_data (n, struct axis_node, pixel_node);
96
97   fraction = (pixel - start) / (gdouble) tower_node_get_size (&an->pixel_node);
98
99   return  tower_node_get_level (&an->unit_node)
100     + fraction * tower_node_get_size (&an->unit_node);
101 }
102
103
104 gint
105 psppire_axis_unit_count (const PsppireAxis *a)
106 {
107   glong padding = 0;
108   glong actual_size;
109
110   actual_size = tower_height (&a->pixel_tower);
111
112   if ( actual_size < a->min_extent )
113     padding = DIV_RND_UP (a->min_extent - actual_size, a->default_size);
114
115   return tower_height (&a->unit_tower) + padding;
116 }
117
118
119 /* Return the starting pixel of UNIT */
120 glong
121 psppire_axis_start_pixel (const PsppireAxis *a, gint unit)
122 {
123   gdouble fraction;
124   struct tower_node *n ;
125   struct axis_node *an;
126
127   unsigned long int start;
128
129   gint the_count, size ;
130
131   the_count =  tower_height (&a->unit_tower);
132   size = tower_height (&a->pixel_tower);
133
134   if ( unit >= the_count)
135     {
136       return  size + (unit - the_count) * a->default_size;
137     }
138
139   if ( unit < 0)
140     return -1;
141
142   if ( unit >= tower_height (&a->unit_tower))
143     return -1;
144
145   n = tower_lookup (&a->unit_tower, unit, &start);
146
147   an = tower_data (n, struct axis_node, unit_node);
148
149   fraction = (unit - start) / (gdouble) tower_node_get_size (&an->unit_node);
150
151   return  tower_node_get_level (&an->pixel_node) +
152     nearbyint (fraction * tower_node_get_size (&an->pixel_node));
153 }
154
155 gint
156 psppire_axis_unit_size (const PsppireAxis *axis, gint unit)
157 {
158   struct tower_node *n ;
159   struct axis_node *an;
160
161   unsigned long int start;
162
163   if  (unit >= tower_height (&axis->unit_tower))
164     return axis->default_size;
165
166   if ( unit < 0)
167     return 0;
168
169   if ( unit >= tower_height (&axis->unit_tower))
170     return 0;
171
172   n = tower_lookup (&axis->unit_tower, unit, &start);
173
174   an = tower_data (n, struct axis_node, unit_node);
175
176   return nearbyint (tower_node_get_size (&an->pixel_node)
177                      / (gdouble) tower_node_get_size (&an->unit_node));
178 }
179
180
181
182 /* --- functions --- */
183 /**
184  * psppire_axis_get_type:
185  * @returns: the type ID for accelerator groups.
186  */
187 GType
188 psppire_axis_get_type (void)
189 {
190   static GType object_type = 0;
191
192   if (!object_type)
193     {
194       static const GTypeInfo object_info = {
195         sizeof (PsppireAxisClass),
196         (GBaseInitFunc) NULL,
197         (GBaseFinalizeFunc) NULL,
198         (GClassInitFunc) psppire_axis_class_init,
199         NULL,   /* class_finalize */
200         NULL,   /* class_data */
201         sizeof (PsppireAxis),
202         0,      /* n_preallocs */
203         (GInstanceInitFunc) psppire_axis_init,
204       };
205
206       object_type = g_type_register_static (G_TYPE_OBJECT,
207                                             "PsppireAxis",
208                                             &object_info, 0);
209
210     }
211
212   return object_type;
213 }
214
215 enum
216   {
217     PROP_0,
218     PROP_MIN_EXTENT,
219     PROP_DEFAULT_SIZE
220   };
221
222
223 static void
224 psppire_axis_get_property (GObject         *object,
225                            guint            prop_id,
226                            GValue          *value,
227                            GParamSpec      *pspec)
228 {
229   PsppireAxis *axis = PSPPIRE_AXIS (object);
230
231   switch (prop_id)
232     {
233     case PROP_MIN_EXTENT:
234       g_value_set_long (value, axis->min_extent);
235       break;
236     case PROP_DEFAULT_SIZE:
237       g_value_set_int (value, axis->default_size);
238       break;
239     default:
240       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
241       break;
242     };
243 }
244
245
246 static void
247 psppire_axis_set_property (GObject         *object,
248                            guint            prop_id,
249                            const GValue    *value,
250                            GParamSpec      *pspec)
251 {
252   PsppireAxis *axis = PSPPIRE_AXIS (object);
253
254   switch (prop_id)
255     {
256     case PROP_MIN_EXTENT:
257       axis->min_extent = g_value_get_long (value);
258       break;
259     case PROP_DEFAULT_SIZE:
260       axis->default_size = g_value_get_int (value);
261       break;
262     default:
263       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
264       break;
265     };
266 }
267
268
269 static void
270 psppire_axis_class_init (PsppireAxisClass *class)
271 {
272   GObjectClass *object_class = G_OBJECT_CLASS (class);
273
274
275   GParamSpec *min_extent_spec;
276   GParamSpec *default_size_spec;
277
278   parent_class = g_type_class_peek_parent (class);
279
280   object_class->set_property = psppire_axis_set_property;
281   object_class->get_property = psppire_axis_get_property;
282
283
284   min_extent_spec =
285     g_param_spec_long ("minimum-extent",
286                        "Minimum Extent",
287                        "The smallest extent to which the axis will provide units (typically set to the height/width of the associated widget).",
288                        0, G_MAXLONG,
289                        0,
290                        G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
291
292   g_object_class_install_property (object_class,
293                                    PROP_MIN_EXTENT,
294                                    min_extent_spec);
295
296
297   default_size_spec =
298     g_param_spec_int ("default-size",
299                       "Default Size",
300                       "The size given to units which haven't been explicity inserted",
301                       0, G_MAXINT,
302                       25,
303                       G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
304
305
306   g_object_class_install_property (object_class,
307                                    PROP_DEFAULT_SIZE,
308                                    default_size_spec);
309
310
311   signals[RESIZE_UNIT] =
312     g_signal_new ("resize-unit",
313                   G_TYPE_FROM_CLASS (object_class),
314                   G_SIGNAL_RUN_LAST,
315                   0,
316                   NULL, NULL,
317                   psppire_marshal_VOID__INT_LONG,
318                   G_TYPE_NONE,
319                   2,
320                   G_TYPE_INT,
321                   G_TYPE_LONG
322                   );
323
324
325   object_class->finalize = psppire_axis_finalize;
326 }
327
328
329 static void
330 psppire_axis_init (PsppireAxis *axis)
331 {
332   tower_init (&axis->pixel_tower);
333   tower_init (&axis->unit_tower);
334
335   axis->pool = pool_create ();
336 }
337
338
339 static void
340 psppire_axis_finalize (GObject *object)
341 {
342   PsppireAxis *a = PSPPIRE_AXIS (object);
343   pool_destroy (a->pool);
344
345   G_OBJECT_CLASS (parent_class)->finalize (object);
346 }
347
348 /**
349  * psppire_axis_new:
350  * @returns: a new #PsppireAxis object
351  *
352  * Creates a new #PsppireAxis.
353  */
354 PsppireAxis*
355 psppire_axis_new (void)
356 {
357   return g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
358 }
359
360
361 \f
362
363 void
364 psppire_axis_append (PsppireAxis *a, gint size)
365 {
366   psppire_axis_append_n (a, 1, size);
367 }
368
369
370 void
371 psppire_axis_append_n (PsppireAxis *a, gint n_units, gint size)
372 {
373   struct axis_node *node;
374
375   if  (n_units == 0)
376     return;
377
378   node = pool_malloc (a->pool, sizeof *node);
379
380   tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL);
381   tower_insert (&a->pixel_tower, size * n_units, &node->pixel_node, NULL);
382 }
383
384
385 /* Split the node of both towers at POSN */
386 static void
387 split (PsppireAxis *a, gint posn)
388 {
389   unsigned long int existing_unit_size;
390   unsigned long int existing_pixel_size;
391   unsigned long int start;
392   gdouble fraction;
393   struct axis_node *new_node ;
394   struct tower_node *n;
395   struct axis_node *existing_node;
396
397   g_return_if_fail (posn <= tower_height (&a->unit_tower));
398
399   /* Nothing needs to be done */
400   if ( posn == 0 || posn  == tower_height (&a->unit_tower))
401     return;
402
403   n = tower_lookup (&a->unit_tower, posn, &start);
404
405   existing_node = tower_data (n, struct axis_node, unit_node);
406
407   /* Nothing needs to be done, if the range element is already split here */
408   if ( posn - start == 0)
409     return;
410
411   existing_unit_size = tower_node_get_size (&existing_node->unit_node);
412   existing_pixel_size = tower_node_get_size (&existing_node->pixel_node);
413
414   fraction = (posn - start) / (gdouble) existing_unit_size;
415
416   new_node = pool_malloc (a->pool, sizeof (*new_node));
417
418   tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start);
419
420   tower_resize (&a->pixel_tower, &existing_node->pixel_node,
421                 nearbyintf (fraction * existing_pixel_size));
422
423   tower_insert (&a->unit_tower,
424                 existing_unit_size - (posn - start),
425                 &new_node->unit_node,
426                 tower_next (&a->unit_tower, &existing_node->unit_node));
427
428
429   tower_insert (&a->pixel_tower,
430                 nearbyintf (existing_pixel_size * (1 - fraction)),
431                 &new_node->pixel_node,
432                 tower_next (&a->pixel_tower, &existing_node->pixel_node));
433 }
434
435
436 /* Insert a new unit of size SIZE before POSN */
437 void
438 psppire_axis_insert (PsppireAxis *a, gint posn, gint size)
439 {
440   struct axis_node *before = NULL;
441   struct axis_node *new_node;
442
443   g_return_if_fail ( posn >= 0);
444   g_return_if_fail ( posn <= tower_height (&a->unit_tower));
445
446   if ( posn < tower_height (&a->unit_tower))
447     {
448       unsigned long int start = 0;
449       struct tower_node *n;
450
451       split (a, posn);
452
453       n = tower_lookup (&a->unit_tower, posn, &start);
454       g_assert (posn == start);
455
456       before = tower_data (n, struct axis_node, unit_node);
457     }
458
459   new_node = pool_malloc (a->pool, sizeof (*new_node));
460
461   tower_insert (&a->unit_tower,
462                 1,
463                 &new_node->unit_node,
464                 before ? &before->unit_node : NULL);
465
466   tower_insert (&a->pixel_tower,
467                 size,
468                 &new_node->pixel_node,
469                 before ? &before->pixel_node : NULL);
470 }
471
472
473 /* Make the element at POSN singular.
474    Return a pointer to the node for this element */
475 static struct axis_node *
476 make_single (PsppireAxis *a, gint posn)
477 {
478   unsigned long int start;
479   struct tower_node *n;
480
481   g_return_val_if_fail (posn < tower_height (&a->unit_tower), NULL);
482
483   n = tower_lookup (&a->unit_tower, posn, &start);
484
485   if ( 1 != tower_node_get_size (n))
486     {
487       split (a, posn + 1);
488       n = tower_lookup (&a->unit_tower, posn, &start);
489
490       if ( 1 != tower_node_get_size (n))
491         {
492           split (a, posn);
493           n = tower_lookup (&a->unit_tower, posn, &start);
494         }
495     }
496
497   g_assert (1 == tower_node_get_size (n));
498
499   return tower_data (n, struct axis_node, unit_node);
500 }
501
502
503 void
504 psppire_axis_resize (PsppireAxis *axis, gint posn, glong size)
505 {
506   struct axis_node *an;
507   g_return_if_fail (posn >= 0);
508   g_return_if_fail (size > 0);
509
510   /* Silently ignore this request if the position is greater than the number of
511      units in the axis */
512   if (posn >= tower_height (&axis->unit_tower))
513     return ;
514
515   an = make_single (axis, posn);
516
517   tower_resize (&axis->pixel_tower, &an->pixel_node, size);
518
519   g_signal_emit (axis, signals[RESIZE_UNIT], 0, posn, size);
520 }
521
522
523
524
525
526
527 void
528 psppire_axis_clear (PsppireAxis *a)
529 {
530   pool_destroy (a->pool);
531   a->pool = pool_create ();
532
533   tower_init (&a->pixel_tower);
534   tower_init (&a->unit_tower);
535 }
536
537
538
539 void
540 psppire_axis_delete (PsppireAxis *a, gint first, gint n_units)
541 {
542   gint units_to_delete = n_units;
543   unsigned long int start;
544   struct tower_node *unit_node ;
545   g_return_if_fail (first + n_units <= tower_height (&a->unit_tower));
546
547   split (a, first);
548   split (a, first + n_units);
549
550   unit_node = tower_lookup (&a->unit_tower, first, &start);
551   g_assert (start == first);
552
553   while (units_to_delete > 0)
554     {
555       struct tower_node *next_unit_node;
556       struct axis_node *an = tower_data (unit_node,
557                                          struct axis_node, unit_node);
558
559       g_assert (unit_node == &an->unit_node);
560       g_assert (unit_node->size <= n_units);
561
562       units_to_delete -= unit_node->size;
563
564       next_unit_node = tower_next (&a->unit_tower, unit_node);
565
566       tower_delete (&a->unit_tower, unit_node);
567       tower_delete (&a->pixel_tower, &an->pixel_node);
568
569       pool_free (a->pool, an);
570
571       unit_node = next_unit_node;
572     }
573 }