/* This is -*- C -*- */
/* $Id: guppi-object-scatter.c,v 1.3 2002/01/08 06:28:53 trow Exp $ */

/*
 * guppi-object-scatter.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 * Copyright (C) 2001 The Free Software Foundation
 *
 * Developed by Jon Trowbridge <trow@gnu.org> and
 * Havoc Pennington <hp@pobox.com>.
 *
 * 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 the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include <guppi-seq-scalar-core.h>
#include <guppi-group-state.h>
#include <guppi-group-view.h>
#include <guppi-group-view-layout.h>
#include "guppi-object-scatter.h"

static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0,
  ARG_X_AXIS_LABEL,
  ARG_Y_AXIS_LABEL,
  ARG_DATA_SIZE,
  ARG_X_DATA,
  ARG_Y_DATA,
  ARG_MARKER,
  ARG_SIZE1,
  ARG_SIZE2,
  ARG_COLOR_RGBA,
  ARG_COLOR_RGB,
  ARG_AXIS_LABEL_FONT,
  ARG_AXIS_MARKER_FONT
};

static gpointer
generic_memdup (gconstpointer p, gsize N)
{
  gpointer cpy = guppi_malloc (N);
  memcpy (cpy, p, N);
  return cpy;
}

#define memdup(ptr, type, N) ((type *)generic_memdup((ptr),(N)*sizeof(type)))

static void
guppi_object_scatter_get_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  switch (arg_id) {

  default:
    break;
  };
}

static void
guppi_object_scatter_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  GuppiObjectScatter *oscat = GUPPI_OBJECT_SCATTER (obj);

  switch (arg_id) {

  case ARG_X_AXIS_LABEL:
    guppi_strdup (oscat->x_axis_label);
    oscat->x_axis_label = guppi_strdup ((gchar *) GTK_VALUE_POINTER (*arg));
    break;

  case ARG_Y_AXIS_LABEL:
    guppi_strdup (oscat->y_axis_label);
    oscat->y_axis_label = guppi_strdup ((gchar *) GTK_VALUE_POINTER (*arg));
    break;

  case ARG_DATA_SIZE:
    oscat->data_size = GTK_VALUE_INT (*arg);
    if (oscat->data_size <= 0)
      g_warning ("illegal data size: %d", oscat->data_size);
    break;

  case ARG_X_DATA:
    guppi_free (oscat->x_data);
    if (oscat->data_size <= 0)
      g_warning ("x_data: illegal data size %d", oscat->data_size);
    else
      oscat->x_data =
	memdup (GTK_VALUE_POINTER (*arg), double, oscat->data_size);
    break;

  case ARG_Y_DATA:
    guppi_free (oscat->y_data);
    if (oscat->data_size <= 0)
      g_warning ("y_data: illegal data size %d", oscat->data_size);
    else
      oscat->y_data =
	memdup (GTK_VALUE_POINTER (*arg), double, oscat->data_size);
    break;

  case ARG_MARKER:
    {
      GuppiMarker m = guppi_str2marker ((gchar *) GTK_VALUE_POINTER (*arg));
      if (m == GUPPI_MARKER_UNKNOWN) {
	g_warning ("Unknown marker \"%s\"",
		   (gchar *) GTK_VALUE_POINTER (*arg));
      } else {
	const GuppiMarkerInfo *info;
	oscat->marker = m;
	info = guppi_marker_info (oscat->marker);
	g_assert (info != NULL);
	oscat->size1 = 1.0;
	oscat->size2 = 1.0;
      }
    }
    break;

  case ARG_SIZE1:
    oscat->size1 = GTK_VALUE_DOUBLE (*arg);
    break;

  case ARG_SIZE2:
    oscat->size2 = GTK_VALUE_DOUBLE (*arg);
    break;

  case ARG_COLOR_RGBA:
    oscat->color = GTK_VALUE_UINT (*arg);
    break;

  case ARG_COLOR_RGB:
    oscat->color = RGB_TO_RGBA (GTK_VALUE_UINT (*arg), 0xff);
    break;

  case ARG_AXIS_LABEL_FONT:
    guppi_refcounting_assign (oscat->axis_label_font,
			      GNOME_FONT (GTK_VALUE_POINTER (*arg)));
    break;

  case ARG_AXIS_MARKER_FONT:
    guppi_refcounting_assign (oscat->axis_marker_font,
			      GNOME_FONT (GTK_VALUE_POINTER (*arg)));
    break;

  default:
    g_assert_not_reached ();
    break;
  }

}

static void
guppi_object_scatter_finalize (GtkObject *obj)
{
  GuppiObjectScatter *oscat = GUPPI_OBJECT_SCATTER (obj);

  guppi_free (oscat->x_axis_label);
  guppi_free (oscat->y_axis_label);
  oscat->x_axis_label = NULL;
  oscat->y_axis_label = NULL;

  guppi_free (oscat->x_data);
  oscat->x_data = NULL;

  guppi_free (oscat->y_data);
  oscat->y_data = NULL;

  guppi_unref0 (oscat->axis_label_font);
  guppi_unref0 (oscat->axis_marker_font);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

/***************************************************************************/

static gpointer
build (GuppiObject *obj, double hsize, double vsize)
{
  GuppiObjectScatter *oscat;

  GuppiElementState *grp_state;
  GuppiGroupView *grp_view;

  GnomeFont *axis_label_font;
  GnomeFont *axis_marker_font;

  GuppiSeqScalar *x_data;
  GuppiSeqScalar *y_data;

  GuppiElementState *scatter_state = NULL;
  GuppiElementState *frame_state = NULL;
  GuppiElementState *x_axis_state = NULL;
  GuppiElementState *y_axis_state = NULL;

  GuppiElementView *scatter_view = NULL;
  GuppiElementView *frame_view = NULL;
  GuppiElementView *x_axis_view = NULL;
  GuppiElementView *y_axis_view = NULL;

  gint i;

  const double outer_margin = 3.6;
  const double inner_gap = 3.6;

  g_return_val_if_fail (obj != NULL && GUPPI_IS_OBJECT_SCATTER (obj), NULL);
  oscat = GUPPI_OBJECT_SCATTER (obj);

  grp_state = guppi_group_state_new ();
  grp_view = GUPPI_GROUP_VIEW (guppi_element_state_make_view (grp_state));
  guppi_unref0 (grp_state);

  axis_label_font = oscat->axis_label_font;
  if (axis_label_font == NULL)
    axis_label_font = guppi_default_font_medium ();

  axis_marker_font = oscat->axis_label_font;
  if (axis_marker_font == NULL)
    axis_marker_font = guppi_default_font_medium ();

  if (oscat->x_data == NULL) {
    g_warning ("No x-data specified.");
    return NULL;
  }
  if (oscat->y_data == NULL) {
    g_warning ("No y-data specified.");
    return NULL;
  }

  /* Build up our data objects */
  x_data = GUPPI_SEQ_SCALAR (guppi_seq_scalar_core_new ());
  y_data = GUPPI_SEQ_SCALAR (guppi_seq_scalar_core_new ());
  for (i = 0; i < oscat->data_size; ++i) {
    guppi_seq_scalar_append (x_data, oscat->x_data[i]);
    guppi_seq_scalar_append (y_data, oscat->y_data[i]);
  }

  /* Build state objects */

  x_axis_state = guppi_element_state_new ("axis",
					  "position", GUPPI_SOUTH,
					  "legend", oscat->x_axis_label,
					  "legend_font", axis_label_font,
					  "major_label_font",
					  axis_marker_font, NULL);

  y_axis_state = guppi_element_state_new ("axis",
					  "position", GUPPI_WEST,
					  "legend", oscat->y_axis_label,
					  "legend_font", axis_label_font,
					  "major_label_font", axis_marker_font,
					  NULL);

  scatter_state = guppi_element_state_new ("scatter",
					   "x_data", x_data,
					   "y_data", y_data,
					   "color", oscat->color,
					   "marker", oscat->marker,
					   "size1", oscat->size1,
					   "size2", oscat->size2,
					   NULL);
  
  frame_state = guppi_element_state_new ("frame", NULL);



  /* Build view objects */

  x_axis_view = guppi_element_state_make_view (x_axis_state);
  y_axis_view = guppi_element_state_make_view (y_axis_state);
  scatter_view = guppi_element_state_make_view (scatter_state);
  frame_view = guppi_element_state_make_view (frame_state);

  /* Define our marker types */

  guppi_element_view_set_axis_marker_type (GUPPI_ELEMENT_VIEW (scatter_view), GUPPI_X_AXIS, GUPPI_AXIS_SCALAR);
  guppi_element_view_set_axis_marker_type (GUPPI_ELEMENT_VIEW (scatter_view), GUPPI_Y_AXIS, GUPPI_AXIS_SCALAR);

  /* Define connections */

  guppi_element_view_connect_axis_markers (scatter_view, GUPPI_X_AXIS, frame_view, GUPPI_X_AXIS);
  guppi_element_view_connect_axis_markers (scatter_view, GUPPI_Y_AXIS, frame_view, GUPPI_Y_AXIS);
  guppi_element_view_connect_axis_markers (scatter_view, GUPPI_X_AXIS, x_axis_view, GUPPI_X_AXIS);
  guppi_element_view_connect_axis_markers (scatter_view, GUPPI_Y_AXIS, y_axis_view, GUPPI_Y_AXIS);

  /* Do layout */

  guppi_group_view_layout_flush_top (grp_view, frame_view, outer_margin);

  guppi_group_view_layout_flush_right (grp_view, frame_view, outer_margin);

  guppi_group_view_layout_horizontally_aligned (grp_view, y_axis_view, frame_view, inner_gap);
  guppi_group_view_layout_flush_left (grp_view, y_axis_view, outer_margin);

  guppi_group_view_layout_vertically_aligned (grp_view, frame_view, x_axis_view, inner_gap);
  guppi_group_view_layout_flush_bottom (grp_view, x_axis_view, outer_margin);

  guppi_group_view_layout_same_place (grp_view, frame_view, scatter_view);

  guppi_element_view_set_preferred_view (scatter_view, GUPPI_X_AXIS);
  guppi_element_view_set_preferred_view (scatter_view, GUPPI_Y_AXIS);


  /* Clean up */

  guppi_unref0 (x_data);
  guppi_unref0 (y_data);
  guppi_unref0 (scatter_state);
  guppi_unref0 (frame_state);
  guppi_unref0 (x_axis_state);
  guppi_unref0 (y_axis_state);

  return GUPPI_ELEMENT_VIEW (grp_view);
}

/***************************************************************************/

#define add_arg(str, t, symb) \
gtk_object_add_arg_type("GuppiObjectScatter::" str, t, GTK_ARG_WRITABLE, symb)

static void
guppi_object_scatter_class_init (GuppiObjectScatterClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiObjectClass *gobj_class = GUPPI_OBJECT_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_OBJECT);

  object_class->get_arg = guppi_object_scatter_get_arg;
  object_class->set_arg = guppi_object_scatter_set_arg;
  object_class->finalize = guppi_object_scatter_finalize;

  gobj_class->build = build;

  add_arg ("x_axis_label", GTK_TYPE_POINTER, ARG_X_AXIS_LABEL);
  add_arg ("y_axis_label", GTK_TYPE_POINTER, ARG_Y_AXIS_LABEL);
  add_arg ("data_size", GTK_TYPE_INT, ARG_DATA_SIZE);
  add_arg ("x_data", GTK_TYPE_POINTER, ARG_X_DATA);
  add_arg ("y_data", GTK_TYPE_POINTER, ARG_Y_DATA);
  add_arg ("marker", GTK_TYPE_POINTER, ARG_MARKER);
  add_arg ("size1", GTK_TYPE_DOUBLE, ARG_SIZE1);
  add_arg ("size2", GTK_TYPE_DOUBLE, ARG_SIZE2);
  add_arg ("color_rgba", GTK_TYPE_UINT, ARG_COLOR_RGBA);
  add_arg ("color_rgb", GTK_TYPE_UINT, ARG_COLOR_RGB);
  add_arg ("axis_label_font", GTK_TYPE_POINTER, ARG_AXIS_LABEL_FONT);
  add_arg ("axis_marker_font", GTK_TYPE_POINTER, ARG_AXIS_MARKER_FONT);

}

static void
guppi_object_scatter_init (GuppiObjectScatter *obj)
{
  /* Set some not-totally-unreasonable defaults */

  obj->color = RGBA_RED;

  obj->marker = GUPPI_MARKER_CIRCLE;
  obj->size1 = 1.0;
  obj->size2 = 1.0;
}

GtkType guppi_object_scatter_get_type (void)
{
  static GtkType guppi_object_scatter_type = 0;
  if (!guppi_object_scatter_type) {
    static const GtkTypeInfo guppi_object_scatter_info = {
      "GuppiObjectScatter",
      sizeof (GuppiObjectScatter),
      sizeof (GuppiObjectScatterClass),
      (GtkClassInitFunc) guppi_object_scatter_class_init,
      (GtkObjectInitFunc) guppi_object_scatter_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_object_scatter_type =
      gtk_type_unique (GUPPI_TYPE_OBJECT, &guppi_object_scatter_info);
  }
  return guppi_object_scatter_type;
}

GtkObject *
guppi_object_scatter_new (void)
{
  return GTK_OBJECT (guppi_type_new (guppi_object_scatter_get_type ()));
}



/* $Id: guppi-object-scatter.c,v 1.3 2002/01/08 06:28:53 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1