/* This is -*- C -*- */
/* $Id: guppi-curve-calc.c,v 1.1 2002/01/08 06:28:59 trow Exp $ */
 
/*
 * calc.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-curve-calc.h"

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

#include <guppi-useful.h>
#include <guppi-memory.h>
#include <guppi-data-plug-in.h>

static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0,
  ARG_T0,
  ARG_T1,
  ARG_X_FUNC_C,
  ARG_Y_FUNC_C,
  ARG_XY_FUNC_C,
  ARG_X_USER_DATA,
  ARG_Y_USER_DATA,
  ARG_X_FUNC,
  ARG_Y_FUNC
};

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

  default:
    break;
  };
}

static void
guppi_curve_calc_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  GuppiCurveCalc *func = GUPPI_CURVE_CALC (obj);
  double (*fn1) (double, gpointer);
  void (*fn2) (double, double *, double *, gpointer, gpointer);
  GuppiFnWrapper *fw;

  switch (arg_id) {

  case ARG_T0:
    if (func->t0 != GTK_VALUE_DOUBLE (*arg)) {
      func->t0 = GTK_VALUE_DOUBLE (*arg);
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_T1:
    if (func->t1 != GTK_VALUE_DOUBLE (*arg)) {
      func->t1 = GTK_VALUE_DOUBLE (*arg);
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;


  case ARG_X_FUNC_C:
    fn1 = (double (*)(double, gpointer)) GTK_VALUE_POINTER (*arg);
    if (fn1 != func->x_func) {
      func->x_func = fn1;
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_Y_FUNC_C:
    fn1 = (double (*)(double, gpointer)) GTK_VALUE_POINTER (*arg);
    if (fn1 != func->y_func) {
      func->y_func = fn1;
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_XY_FUNC_C:
    fn2 =
      (void (*)(double, double *, double *, gpointer, gpointer))
      GTK_VALUE_POINTER (*arg);
    if (fn2 != func->xy_func) {
      func->xy_func = fn2;
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_X_USER_DATA:
    if (GTK_VALUE_POINTER (*arg) != func->x_user_data) {
      func->x_user_data = GTK_VALUE_POINTER (*arg);
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_Y_USER_DATA:
    if (GTK_VALUE_POINTER (*arg) != func->y_user_data) {
      func->y_user_data = GTK_VALUE_POINTER (*arg);
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_X_FUNC:
    fw = GUPPI_FN_WRAPPER (GTK_VALUE_POINTER (*arg));
    if (fw != func->x_fn_wrapper) {
      guppi_refcounting_assign (func->x_fn_wrapper, fw);
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;

  case ARG_Y_FUNC:
    fw = GUPPI_FN_WRAPPER (GTK_VALUE_POINTER (*arg));
    if (fw != func->y_fn_wrapper) {
      guppi_refcounting_assign (func->y_fn_wrapper, fw);
      guppi_data_changed (GUPPI_DATA (obj));
    }
    break;


  default:
    break;
  };
}

static void
guppi_curve_calc_finalize (GtkObject *obj)
{
  GuppiCurveCalc *calc = GUPPI_CURVE_CALC (obj);
  
  guppi_unref0 (calc->x_fn_wrapper);
  guppi_unref0 (calc->y_fn_wrapper);

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

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

static void
v_curve_bounds (GuppiCurve *curve, double *a, double *b)
{
  GuppiCurveCalc *cfi = GUPPI_CURVE_CALC (curve);

  if (a)
    *a = cfi->t0;

  if (b)
    *b = cfi->t1;
}

static void
v_curve_get (GuppiCurve *curve, double t, double *x, double *y)
{
  GuppiCurveCalc *cfi = GUPPI_CURVE_CALC (curve);

  if (cfi->xy_func) {
    cfi->xy_func (t, x, y, cfi->x_user_data, cfi->y_user_data);
    return;
  }

  if (x) {
    if (cfi->x_fn_wrapper)
      *x = guppi_fn_wrapper_eval_d__d (cfi->x_fn_wrapper, t);
    else if (cfi->x_func)
      *x = cfi->x_func (t, cfi->x_user_data);
    else
      *x = t;			/* default is identity function */
  }

  if (y) {
    if (cfi->y_fn_wrapper)
      *y = guppi_fn_wrapper_eval_d__d (cfi->y_fn_wrapper, t);
    else if (cfi->y_func)
      *y = cfi->y_func (t, cfi->y_user_data);
    else
      *y = t;			/* default is identity function */
  }
}

static gboolean
v_curve_clamp (GuppiCurve *curve, double *t0, double *t1,
	       double x0, double y0, double x1, double y1)
{
  GuppiCurveCalc *cfi = GUPPI_CURVE_CALC (curve);

  if (cfi->x_fn_wrapper == NULL && cfi->x_func == NULL) {
    if (t0) *t0 = x0 - (x1-x0)/20;
    if (t1) *t1 = x1 + (x1-x0)/20;
    return TRUE;
  }
  return FALSE;
}

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

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

static void
guppi_curve_calc_class_init (GuppiCurveCalcClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiCurveClass *curve_class = GUPPI_CURVE_CLASS (klass);
  GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_CURVE);

  object_class->get_arg = guppi_curve_calc_get_arg;
  object_class->set_arg = guppi_curve_calc_set_arg;
  object_class->finalize = guppi_curve_calc_finalize;

  data_class->is_leaf_type = TRUE;

  curve_class->bounds = v_curve_bounds;
  curve_class->get = v_curve_get;
  curve_class->clamp = v_curve_clamp;

  add_arg ("t0", GTK_TYPE_DOUBLE, ARG_T0);
  add_arg ("t1", GTK_TYPE_DOUBLE, ARG_T1);
  add_arg ("x_function_C", GTK_TYPE_POINTER, ARG_X_FUNC_C);
  add_arg ("y_function_C", GTK_TYPE_POINTER, ARG_Y_FUNC_C);
  add_arg ("xy_function_C", GTK_TYPE_POINTER, ARG_XY_FUNC_C);
  add_arg ("x_user_data", GTK_TYPE_POINTER, ARG_X_USER_DATA);
  add_arg ("y_user_data", GTK_TYPE_POINTER, ARG_X_USER_DATA);
  add_arg ("x_function", GTK_TYPE_POINTER, ARG_X_FUNC);
  add_arg ("y_function", GTK_TYPE_POINTER, ARG_Y_FUNC);
}

static void
guppi_curve_calc_init (GuppiCurveCalc *obj)
{
  obj->t0 = 0;
  obj->t1 = 1;
}

GtkType guppi_curve_calc_get_type (void)
{
  static GtkType guppi_curve_calc_type = 0;
  if (!guppi_curve_calc_type) {
    static const GtkTypeInfo guppi_curve_calc_info = {
      "GuppiCurveCalc",
      sizeof (GuppiCurveCalc),
      sizeof (GuppiCurveCalcClass),
      (GtkClassInitFunc) guppi_curve_calc_class_init,
      (GtkObjectInitFunc) guppi_curve_calc_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_curve_calc_type =
      gtk_type_unique (GUPPI_TYPE_CURVE, &guppi_curve_calc_info);
  }
  return guppi_curve_calc_type;
}

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

#if 0
GuppiData *
guppi_curve_new_calc_parametric (double t0, double t1,
				 GuppiFnWrapper *x_fn, GuppiFnWrapper *y_fn)
{
  g_return_val_if_fail (x_fn != NULL && GUPPI_IS_FN_WRAPPER (x_fn), NULL);
  g_return_val_if_fail (y_fn != NULL && GUPPI_IS_FN_WRAPPER (y_fn), NULL);

  return guppi_data_new_by_type (GUPPI_TYPE_CURVE,
				 GUPPI_TYPE_CURVE_CALC,
				 "t0", MIN (t0, t1),
				 "t1", MAX (t0, t1),
				 "x_function", x_fn,
				 "y_function", y_fn, NULL);
}

GuppiData *
guppi_curve_new_calc_function (double t0, double t1, GuppiFnWrapper *fn)
{
  g_return_val_if_fail (fn != NULL && GUPPI_IS_FN_WRAPPER (fn), NULL);

  return guppi_data_new_by_type (GUPPI_TYPE_CURVE,
				 GUPPI_TYPE_CURVE_CALC,
				 "t0", MIN (t0, t1),
				 "t1", MAX (t0, t1), "y_function", fn, NULL);
}
#endif

/* $Id: guppi-curve-calc.c,v 1.1 2002/01/08 06:28:59 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1