#include <libpspp/tower.h>
#include <libpspp/pool.h>
+#include <libpspp/misc.h>
#include "psppire-axis.h"
#include <gtk/gtk.h>
+#define PSPPIRE_AXIS_GET_IFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PSPPIRE_TYPE_AXIS_IFACE, PsppireAxisIface))
+
+GType
+psppire_axis_iface_get_type (void)
+{
+ static GType psppire_axis_iface_type = 0;
+
+ if (! psppire_axis_iface_type)
+ {
+ 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
+ };
+
+ psppire_axis_iface_type =
+ g_type_register_static (G_TYPE_INTERFACE, "PsppireAxisIface",
+ &psppire_axis_iface_info, 0);
+ }
+
+ return psppire_axis_iface_type;
+}
+
+G_DEFINE_ABSTRACT_TYPE(PsppireAxis, psppire_axis, G_TYPE_OBJECT);
+
+
+
/* --- prototypes --- */
static void psppire_axis_class_init (PsppireAxisClass *class);
static void psppire_axis_init (PsppireAxis *axis);
/* --- variables --- */
static GObjectClass *parent_class = NULL;
-/* --- functions --- */
-/**
- * psppire_axis_get_type:
- * @returns: the type ID for accelerator groups.
- */
-GType
-psppire_axis_get_type (void)
+
+
+enum
+ {
+ PROP_0,
+ PROP_MIN_EXTENT,
+ PROP_DEFAULT_SIZE
+ };
+
+
+static void
+psppire_axis_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- static GType object_type = 0;
+ PsppireAxis *axis = PSPPIRE_AXIS (object);
- if (!object_type)
+ switch (prop_id)
{
- 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,
- };
+ case PROP_MIN_EXTENT:
+ g_value_set_long (value, axis->min_extent);
+ break;
+ case PROP_DEFAULT_SIZE:
+ g_value_set_int (value, axis->default_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ };
+}
- object_type = g_type_register_static (G_TYPE_OBJECT,
- "PsppireAxis",
- &object_info, 0);
- }
- return object_type;
-}
+static void
+psppire_axis_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PsppireAxis *axis = PSPPIRE_AXIS (object);
+ switch (prop_id)
+ {
+ case PROP_MIN_EXTENT:
+ axis->min_extent = g_value_get_long (value);
+ break;
+ case PROP_DEFAULT_SIZE:
+ axis->default_size = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ };
+}
static void
psppire_axis_class_init (PsppireAxisClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GParamSpec *min_extent_spec;
+ GParamSpec *default_size_spec;
+
+ 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",
+ "The smallest extent to which the axis will provide units (typically set to the height/width of the associated widget).",
+ 0, G_MAXLONG,
+ 0,
+ G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
+
+ g_object_class_install_property (object_class,
+ PROP_MIN_EXTENT,
+ min_extent_spec);
+
+
+ default_size_spec =
+ g_param_spec_int ("default-size",
+ "Default Size",
+ "The size given to units which haven't been explicity inserted",
+ 0, G_MAXINT,
+ 25,
+ G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
+
+
+ g_object_class_install_property (object_class,
+ PROP_DEFAULT_SIZE,
+ default_size_spec);
parent_class = g_type_class_peek_parent (class);
object_class->finalize = psppire_axis_finalize;
}
+
static void
psppire_axis_init (PsppireAxis *axis)
{
- axis->pool = NULL;
- psppire_axis_clear (axis);
}
static void
psppire_axis_finalize (GObject *object)
{
- PsppireAxis *a = PSPPIRE_AXIS (object);
- pool_destroy (a->pool);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-/**
- * psppire_axis_new:
- * @returns: a new #PsppireAxis object
- *
- * Creates a new #PsppireAxis.
- */
-PsppireAxis*
-psppire_axis_new (void)
+gint
+psppire_axis_unit_size (const PsppireAxis *a, gint unit)
{
- return g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
-}
+ g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
+ g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_size, -1);
-gint
-psppire_axis_unit_size (PsppireAxis *a, gint unit)
-{
- const struct tower_node *node;
- if (unit >= tower_count (&a->tower))
- return 0;
- node = tower_get (&a->tower, unit);
+ if (unit >= PSPPIRE_AXIS_GET_IFACE (a)->unit_count(a))
+ return a->default_size;
- return tower_node_get_size (node);
+ return PSPPIRE_AXIS_GET_IFACE (a)->unit_size (a, unit);
}
gint
-psppire_axis_unit_count (PsppireAxis *a)
+psppire_axis_unit_count (const PsppireAxis *a)
{
- return tower_count (&a->tower);
-}
+ glong padding = 0;
+ glong actual_size;
-glong
-psppire_axis_pixel_start (PsppireAxis *a, gint unit)
-{
- const struct tower_node *node;
+ g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
+ g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_count, -1);
- if ( unit >= tower_count (&a->tower))
- return tower_height (&a->tower);
+ actual_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
- node = tower_get (&a->tower, unit);
+ if ( actual_size < a->min_extent )
+ padding = DIV_RND_UP (a->min_extent - actual_size, a->default_size);
- return tower_node_get_level (node);
+ return PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a) + padding;
}
-gint
-psppire_axis_get_unit_at_pixel (PsppireAxis *a, glong pixel)
-{
- const struct tower_node *node;
- unsigned long int node_start;
-
- if (pixel >= tower_height (&a->tower))
- return tower_count (&a->tower);
- node = tower_lookup (&a->tower, pixel, &node_start);
+/* Return the starting pixel of UNIT */
+glong
+psppire_axis_start_pixel (const PsppireAxis *a, gint unit)
+{
+ gint the_count, total_size ;
+ g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
- return tower_node_get_index (node);
-}
+ the_count = PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a);
+ total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
-void
-psppire_axis_append (PsppireAxis *a, gint size)
-{
- struct tower_node *new = pool_malloc (a->pool, sizeof *new);
+ if ( unit >= the_count)
+ {
+ return total_size + (unit - the_count) * a->default_size;
+ }
- tower_insert (&a->tower, size, new, NULL);
+ return PSPPIRE_AXIS_GET_IFACE (a)->start_pixel (a, unit);
}
-
-/* Insert a new unit of size SIZE before position POSN */
-void
-psppire_axis_insert (PsppireAxis *a, gint size, gint posn)
+/* Return the unit covered by PIXEL */
+gint
+psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel)
{
- struct tower_node *new = pool_malloc (a->pool, sizeof *new);
+ glong total_size;
- struct tower_node *before = NULL;
+ g_return_val_if_fail (PSPPIRE_IS_AXIS (a), -1);
- if ( posn != tower_count (&a->tower))
- before = tower_get (&a->tower, posn);
+ g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a), -1);
- tower_insert (&a->tower, size, new, before);
-}
+ g_return_val_if_fail (PSPPIRE_AXIS_GET_IFACE (a)->unit_at_pixel, -1);
+ total_size = PSPPIRE_AXIS_GET_IFACE (a)->total_size (a);
-void
-psppire_axis_remove (PsppireAxis *a, gint posn)
-{
- struct tower_node *node = tower_get (&a->tower, posn);
+ if (pixel >= total_size)
+ {
+ gint n_items = PSPPIRE_AXIS_GET_IFACE (a)->unit_count (a);
+ glong extra = pixel - total_size;
- tower_delete (&a->tower, node);
+ return n_items - 1 + DIV_RND_UP (extra, a->default_size);
+ }
- pool_free (a->pool, node);
+ return PSPPIRE_AXIS_GET_IFACE (a)->unit_at_pixel (a, pixel);
}
+/* Set UNIT to size SIZE */
void
-psppire_axis_resize_unit (PsppireAxis *a, gint size, gint posn)
+psppire_axis_resize (PsppireAxis *a, gint unit, glong size)
{
- struct tower_node *node = tower_get (&a->tower, posn);
-
- tower_resize (&a->tower, node, size);
-}
-
+ g_return_if_fail (PSPPIRE_IS_AXIS (a));
+ g_return_if_fail (PSPPIRE_AXIS_GET_IFACE (a));
-void
-psppire_axis_clear (PsppireAxis *a)
-{
- pool_destroy (a->pool);
- a->pool = pool_create ();
- tower_init (&a->tower);
+ if (PSPPIRE_AXIS_GET_IFACE (a)->resize)
+ PSPPIRE_AXIS_GET_IFACE (a)->resize (a, unit, size);
}