X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fsheet%2Fpsppire-axis.c;h=5ae84d00425089e8441321f287396ad77dbd1d2c;hb=ebda03f4d53b24d1af3de9fd7dcbbf448401d5a9;hp=3aeea7c48c7ae15998af438323480733d4703e25;hpb=3c52a21736b3777ced3e47148fa2fc8f9eff59c8;p=pspp-builds.git diff --git a/src/ui/gui/sheet/psppire-axis.c b/src/ui/gui/sheet/psppire-axis.c index 3aeea7c4..5ae84d00 100644 --- a/src/ui/gui/sheet/psppire-axis.c +++ b/src/ui/gui/sheet/psppire-axis.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2008 Free Software Foundation + Copyright (C) 2008, 2009 Free Software Foundation This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,13 +18,12 @@ #include #include +#include #include #include -#include #include "psppire-axis.h" -#include -#include - +#include +#include /* Signals */ @@ -36,52 +35,182 @@ enum static guint signals[n_signals] ; +/* --- prototypes --- */ +static void psppire_axis_class_init (PsppireAxisClass *class); +static void psppire_axis_init (PsppireAxis *axis); +static void psppire_axis_finalize (GObject *object); -#define PSPPIRE_AXIS_GET_IFACE(obj) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PSPPIRE_TYPE_AXIS_IFACE, PsppireAxisIface)) -GType -psppire_axis_iface_get_type (void) +/* --- variables --- */ +static GObjectClass *parent_class = NULL; + + +struct axis_node +{ + struct tower_node pixel_node; + struct tower_node unit_node; +}; + +void +psppire_axis_dump (const PsppireAxis *a) { - static GType psppire_axis_iface_type = 0; + struct tower_node *n = tower_first (&a->unit_tower); - if (! psppire_axis_iface_type) + g_debug ("Axis %p", a); + while (n) { - static const GTypeInfo psppire_axis_iface_info = - { - sizeof (PsppireAxisIface), /* class_size */ - NULL, /* base init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; + const struct axis_node *an = tower_data (n, struct axis_node, unit_node); + const struct tower_node *pn = &an->pixel_node; + g_debug ("%ld units of height %g", + n->size, pn->size / (gdouble) n->size); + + n = tower_next (&a->unit_tower, n); + } + g_debug ("\n"); +} + +/* Return the unit covered by PIXEL */ +gint +psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel) +{ + unsigned long int start; + struct tower_node *n; + struct axis_node *an; + gdouble fraction; + + glong size = tower_height (&a->pixel_tower); + + g_return_val_if_fail (pixel >= 0, -1); - psppire_axis_iface_type = - g_type_register_static (G_TYPE_INTERFACE, "PsppireAxisIface", - &psppire_axis_iface_info, 0); + if (pixel >= size) + { + gint n_items = tower_height (&a->unit_tower); + glong extra = pixel - size; + + return n_items - 1 + DIV_RND_UP (extra, a->default_size); } - return psppire_axis_iface_type; + + n = tower_lookup (&a->pixel_tower, pixel, &start); + an = tower_data (n, struct axis_node, pixel_node); + + fraction = (pixel - start) / (gdouble) tower_node_get_size (&an->pixel_node); + + return tower_node_get_level (&an->unit_node) + + fraction * tower_node_get_size (&an->unit_node); } -G_DEFINE_ABSTRACT_TYPE(PsppireAxis, psppire_axis, G_TYPE_OBJECT); +gint +psppire_axis_unit_count (const PsppireAxis *a) +{ + glong padding = 0; + glong actual_size; + actual_size = tower_height (&a->pixel_tower); -/* --- prototypes --- */ -static void psppire_axis_class_init (PsppireAxisClass *class); -static void psppire_axis_init (PsppireAxis *axis); -static void psppire_axis_finalize (GObject *object); + if ( actual_size < a->min_extent ) + padding = DIV_RND_UP (a->min_extent - actual_size, a->default_size); + return tower_height (&a->unit_tower) + padding; +} -/* --- variables --- */ -static GObjectClass *parent_class = NULL; +/* Return the starting pixel of UNIT */ +glong +psppire_axis_start_pixel (const PsppireAxis *a, gint unit) +{ + gdouble fraction; + struct tower_node *n ; + struct axis_node *an; + + unsigned long int start; + + gint the_count, size ; + + the_count = tower_height (&a->unit_tower); + size = tower_height (&a->pixel_tower); + + if ( unit >= the_count) + { + return size + (unit - the_count) * a->default_size; + } + + if ( unit < 0) + return -1; + + if ( unit >= tower_height (&a->unit_tower)) + return -1; + + n = tower_lookup (&a->unit_tower, unit, &start); + + an = tower_data (n, struct axis_node, unit_node); + + fraction = (unit - start) / (gdouble) tower_node_get_size (&an->unit_node); + + return tower_node_get_level (&an->pixel_node) + + nearbyint (fraction * tower_node_get_size (&an->pixel_node)); +} + +gint +psppire_axis_unit_size (const PsppireAxis *axis, gint unit) +{ + struct tower_node *n ; + struct axis_node *an; + + unsigned long int start; + + if (unit >= tower_height (&axis->unit_tower)) + return axis->default_size; + + if ( unit < 0) + return 0; + + if ( unit >= tower_height (&axis->unit_tower)) + return 0; + + n = tower_lookup (&axis->unit_tower, unit, &start); + + an = tower_data (n, struct axis_node, unit_node); + + return nearbyint (tower_node_get_size (&an->pixel_node) + / (gdouble) tower_node_get_size (&an->unit_node)); +} + + + +/* --- functions --- */ +/** + * psppire_axis_get_type: + * @returns: the type ID for accelerator groups. + */ +GType +psppire_axis_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = { + sizeof (PsppireAxisClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) psppire_axis_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PsppireAxis), + 0, /* n_preallocs */ + (GInstanceInitFunc) psppire_axis_init, + }; + + object_type = g_type_register_static (G_TYPE_OBJECT, + "PsppireAxis", + &object_info, 0); + + } + return object_type; +} enum { @@ -136,16 +265,22 @@ psppire_axis_set_property (GObject *object, }; } + static void psppire_axis_class_init (PsppireAxisClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); + + GParamSpec *min_extent_spec; GParamSpec *default_size_spec; + parent_class = g_type_class_peek_parent (class); + object_class->set_property = psppire_axis_set_property; object_class->get_property = psppire_axis_get_property; + min_extent_spec = g_param_spec_long ("minimum-extent", "Minimum Extent", @@ -172,10 +307,6 @@ psppire_axis_class_init (PsppireAxisClass *class) PROP_DEFAULT_SIZE, default_size_spec); - parent_class = g_type_class_peek_parent (class); - - object_class->finalize = psppire_axis_finalize; - signals[RESIZE_UNIT] = g_signal_new ("resize-unit", @@ -189,113 +320,254 @@ psppire_axis_class_init (PsppireAxisClass *class) G_TYPE_INT, G_TYPE_LONG ); + + + object_class->finalize = psppire_axis_finalize; } static void psppire_axis_init (PsppireAxis *axis) { + tower_init (&axis->pixel_tower); + tower_init (&axis->unit_tower); + + axis->pool = pool_create (); } static void psppire_axis_finalize (GObject *object) { + PsppireAxis *a = PSPPIRE_AXIS (object); + pool_destroy (a->pool); + G_OBJECT_CLASS (parent_class)->finalize (object); } -gint -psppire_axis_unit_size (const PsppireAxis *a, gint unit) +/** + * psppire_axis_new: + * @returns: a new #PsppireAxis object + * + * Creates a new #PsppireAxis. + */ +PsppireAxis* +psppire_axis_new (void) +{ + return g_object_new (G_TYPE_PSPPIRE_AXIS, NULL); +} + + + + +void +psppire_axis_append (PsppireAxis *a, gint size) { - g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1); + psppire_axis_append_n (a, 1, size); +} + - g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_size, -1); +void +psppire_axis_append_n (PsppireAxis *a, gint n_units, gint size) +{ + struct axis_node *node; + if (n_units == 0) + return; - if (unit >= PSPPIRE_AXIS_GET_IFACE (a)->unit_count(a)) - return a->default_size; + node = pool_malloc (a->pool, sizeof *node); - return PSPPIRE_AXIS_GET_IFACE (a)->unit_size (a, unit); + tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL); + tower_insert (&a->pixel_tower, size * n_units, &node->pixel_node, NULL); } -gint -psppire_axis_unit_count (const PsppireAxis *a) + +/* Split the node of both towers at POSN */ +static void +split (PsppireAxis *a, gint posn) { - glong padding = 0; - glong actual_size; + unsigned long int existing_unit_size; + unsigned long int existing_pixel_size; + unsigned long int start; + gdouble fraction; + struct axis_node *new_node ; + struct tower_node *n; + struct axis_node *existing_node; - g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1); - g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_count, -1); + g_return_if_fail (posn <= tower_height (&a->unit_tower)); - actual_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a); + /* Nothing needs to be done */ + if ( posn == 0 || posn == tower_height (&a->unit_tower)) + return; + + n = tower_lookup (&a->unit_tower, posn, &start); + + existing_node = tower_data (n, struct axis_node, unit_node); + + /* Nothing needs to be done, if the range element is already split here */ + if ( posn - start == 0) + return; + + existing_unit_size = tower_node_get_size (&existing_node->unit_node); + existing_pixel_size = tower_node_get_size (&existing_node->pixel_node); + + fraction = (posn - start) / (gdouble) existing_unit_size; + + new_node = pool_malloc (a->pool, sizeof (*new_node)); + + tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start); + + tower_resize (&a->pixel_tower, &existing_node->pixel_node, + nearbyintf (fraction * existing_pixel_size)); + + tower_insert (&a->unit_tower, + existing_unit_size - (posn - start), + &new_node->unit_node, + tower_next (&a->unit_tower, &existing_node->unit_node)); - if ( actual_size < a->min_extent ) - padding = DIV_RND_UP (a->min_extent - actual_size, a->default_size); - return PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a) + padding; + tower_insert (&a->pixel_tower, + nearbyintf (existing_pixel_size * (1 - fraction)), + &new_node->pixel_node, + tower_next (&a->pixel_tower, &existing_node->pixel_node)); } -/* Return the starting pixel of UNIT */ -glong -psppire_axis_start_pixel (const PsppireAxis *a, gint unit) +/* Insert a new unit of size SIZE before POSN */ +void +psppire_axis_insert (PsppireAxis *a, gint posn, gint size) { - gint the_count, total_size ; - g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1); + struct axis_node *before = NULL; + struct axis_node *new_node; - the_count = PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a); - total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a); + g_return_if_fail ( posn >= 0); + g_return_if_fail ( posn <= tower_height (&a->unit_tower)); - if ( unit >= the_count) + if ( posn < tower_height (&a->unit_tower)) { - return total_size + (unit - the_count) * a->default_size; + unsigned long int start = 0; + struct tower_node *n; + + split (a, posn); + + n = tower_lookup (&a->unit_tower, posn, &start); + g_assert (posn == start); + + before = tower_data (n, struct axis_node, unit_node); } - return PSPPIRE_AXIS_GET_IFACE (a)->start_pixel (a, unit); -} + new_node = pool_malloc (a->pool, sizeof (*new_node)); + tower_insert (&a->unit_tower, + 1, + &new_node->unit_node, + before ? &before->unit_node : NULL); -/* Return the unit covered by PIXEL */ -gint -psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel) -{ - glong total_size; + tower_insert (&a->pixel_tower, + size, + &new_node->pixel_node, + before ? &before->pixel_node : NULL); +} - g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1); - g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a), -1); +/* Make the element at POSN singular. + Return a pointer to the node for this element */ +static struct axis_node * +make_single (PsppireAxis *a, gint posn) +{ + unsigned long int start; + struct tower_node *n; - g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_at_pixel, -1); + g_return_val_if_fail (posn < tower_height (&a->unit_tower), NULL); - total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a); + n = tower_lookup (&a->unit_tower, posn, &start); - if (pixel >= total_size) + if ( 1 != tower_node_get_size (n)) { - gint n_items = PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a); - glong extra = pixel - total_size; - - return n_items - 1 + DIV_RND_UP (extra, a->default_size); + split (a, posn + 1); + n = tower_lookup (&a->unit_tower, posn, &start); + + if ( 1 != tower_node_get_size (n)) + { + split (a, posn); + n = tower_lookup (&a->unit_tower, posn, &start); + } } - return PSPPIRE_AXIS_GET_IFACE (a)->unit_at_pixel (a, pixel); + g_assert (1 == tower_node_get_size (n)); + + return tower_data (n, struct axis_node, unit_node); } -/* Set UNIT to size SIZE */ void -psppire_axis_resize (PsppireAxis *a, gint unit, glong size) +psppire_axis_resize (PsppireAxis *axis, gint posn, glong size) { - g_return_if_fail (PSPPIRE_IS_AXIS (a)); + struct axis_node *an; + g_return_if_fail (posn >= 0); + g_return_if_fail (size > 0); + + /* Silently ignore this request if the position is greater than the number of + units in the axis */ + if (posn >= tower_height (&axis->unit_tower)) + return ; + + an = make_single (axis, posn); + + tower_resize (&axis->pixel_tower, &an->pixel_node, size); + + g_signal_emit (axis, signals[RESIZE_UNIT], 0, posn, size); +} - g_return_if_fail (PSPPIRE_AXIS_GET_IFACE (a)); - g_return_if_fail (size > 0); - if (PSPPIRE_AXIS_GET_IFACE (a)->resize) - PSPPIRE_AXIS_GET_IFACE (a)->resize (a, unit, size); - g_signal_emit (a, signals [RESIZE_UNIT], 0, unit, size); + +void +psppire_axis_clear (PsppireAxis *a) +{ + pool_destroy (a->pool); + a->pool = pool_create (); + + tower_init (&a->pixel_tower); + tower_init (&a->unit_tower); } + +void +psppire_axis_delete (PsppireAxis *a, gint first, gint n_units) +{ + gint units_to_delete = n_units; + unsigned long int start; + struct tower_node *unit_node ; + g_return_if_fail (first + n_units <= tower_height (&a->unit_tower)); + + split (a, first); + split (a, first + n_units); + + unit_node = tower_lookup (&a->unit_tower, first, &start); + g_assert (start == first); + + while (units_to_delete > 0) + { + struct tower_node *next_unit_node; + struct axis_node *an = tower_data (unit_node, + struct axis_node, unit_node); + + g_assert (unit_node == &an->unit_node); + g_assert (unit_node->size <= n_units); + + units_to_delete -= unit_node->size; + + next_unit_node = tower_next (&a->unit_tower, unit_node); + + tower_delete (&a->unit_tower, unit_node); + tower_delete (&a->pixel_tower, &an->pixel_node); + + pool_free (a->pool, an); + + unit_node = next_unit_node; + } +}