view src/graphics.h.in @ 7365:f5e801eee0d1

[project @ 2008-01-13 06:33:32 by jwe]
author jwe
date Sun, 13 Jan 2008 06:33:32 +0000
parents 0e07f78369d1
children 2a2115742cb5
line wrap: on
line source

/*

Copyright (C) 2007 John W. Eaton

This file is part of Octave.

Octave 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 3 of the License, or (at your
option) any later version.

Octave 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 Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#if !defined (graphics_h)
#define graphics_h 1

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <cctype>

#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <string>

#include "gripes.h"
#include "oct-map.h"
#include "ov.h"

class caseless_str : public std::string
{
public:
  typedef std::string::iterator iterator;
  typedef std::string::const_iterator const_iterator;

  caseless_str (void) : std::string () { }
  caseless_str (const std::string& s) : std::string (s) { }
  caseless_str (const char *s) : std::string (s) { }

  caseless_str (const caseless_str& name) : std::string (name) { }

  caseless_str& operator = (const caseless_str& pname)
  {
    std::string::operator = (pname);
    return *this;
  }

  operator std::string (void) const { return *this; }

  // Case-insensitive comparison.
  bool compare (const std::string& s, size_t limit = NPOS) const
  {
    const_iterator p1 = begin ();
    const_iterator p2 = s.begin ();

    size_t k = 0;

    while (p1 != end () && p2 != s.end () && k++ < limit)
      {
	if (std::tolower (*p1) != std::tolower (*p2))
	  return false;

	*p1++;
	*p2++;
      }

    return (limit == NPOS) ? size () == s.size () : k == limit;
  }
};

// ---------------------------------------------------------------------

class graphics_handle
{
public:
  graphics_handle (void) : val (octave_NaN) { }

  graphics_handle (const octave_value& a);

  graphics_handle (int a) : val (a) { }

  graphics_handle (double a) : val (a) { }

  graphics_handle (const graphics_handle& a) : val (a.val) { }

  graphics_handle& operator = (const graphics_handle& a)
  {
    if (&a != this)
      val = a.val;

    return *this;
  }

  ~graphics_handle (void) { }

  double value (void) const { return val; }

  octave_value as_octave_value (void) const
  {
    return ok () ? octave_value (val) : octave_value (Matrix ());
  }

  graphics_handle operator ++ (void)
  {
    ++val;
    return *this;
  }

  graphics_handle operator ++ (int)
  {
    graphics_handle h = *this;
    ++val;
    return h;
  }

  graphics_handle operator -- (void)
  {
    --val;
    return *this;
  }

  graphics_handle operator -- (int)
  {
    graphics_handle h = *this;
    --val;
    return h;
  }

  bool ok (void) const { return ! xisnan (val); }

private:
  double val;
};

inline bool
operator == (const graphics_handle& a, const graphics_handle& b)
{
  return a.value () == b.value ();
}

inline bool
operator != (const graphics_handle& a, const graphics_handle& b)
{
  return a.value () != b.value ();
}

inline bool
operator < (const graphics_handle& a, const graphics_handle& b)
{
  return a.value () < b.value ();
}

inline bool
operator <= (const graphics_handle& a, const graphics_handle& b)
{
  return a.value () <= b.value ();
}

inline bool
operator >= (const graphics_handle& a, const graphics_handle& b)
{
  return a.value () >= b.value ();
}

inline bool
operator > (const graphics_handle& a, const graphics_handle& b)
{
  return a.value () > b.value ();
}

// ---------------------------------------------------------------------

class property;

class base_property
{
public:
  friend class property;

public:
  base_property (void) : count (0) { }

  base_property (const std::string& s, const graphics_handle& h)
    : count (0), name (s), parent (h), hidden (false) { }

  base_property (const base_property& p)
    : count (0), name (p.name), parent (p.parent), hidden (p.hidden) { }

  virtual ~base_property (void) { }

  bool ok (void) const { return parent.ok (); }

  std::string get_name (void) const { return name; }

  void set_name (const std::string& s) { name = s; }

  graphics_handle get_parent (void) const { return parent; }

  void set_parent (const graphics_handle &h) { parent = h; }

  bool is_hidden (void) const { return hidden; }

  void set_hidden (bool flag) { hidden = flag; }

  virtual void set (const octave_value&)
    { error ("set: invalid property \"%s\"", name.c_str ()); }

  virtual octave_value get (void) const
    {
      error ("get: invalid property \"%s\"", name.c_str ());
      return octave_value ();
    }

  base_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  int count;
  std::string name;
  graphics_handle parent;
  bool hidden;
};

// ---------------------------------------------------------------------

class string_property : public base_property
{
public:
  string_property (const std::string& s, const graphics_handle& h,
                   const std::string& val = "")
    : base_property (s, h), str (val) { }

  string_property (const string_property& p)
    : base_property (p), str (p.str) { }

  void set (const octave_value& val)
    {
      if (val.is_string ())
        str = val.string_value ();
      else
        error ("set: invalid string property value for \"%s\"",
               get_name ().c_str ());
    }

  octave_value get (void) const
    { return octave_value (str); }

  std::string string_value (void) const { return str; }

  string_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  std::string str;
};

// ---------------------------------------------------------------------

class radio_values
{
public:
  OCTINTERP_API radio_values (const std::string& opt_string = std::string ());

  radio_values (const radio_values& a)
    : default_val (a.default_val), possible_vals (a.possible_vals) { }

  radio_values& operator = (const radio_values& a)
  {
    if (&a != this)
      {
	default_val = a.default_val;
	possible_vals = a.possible_vals;
      }

    return *this;
  }

  std::string default_value (void) const { return default_val; }

  bool validate (const std::string& val)
  {
    bool retval = true;

    if (! contains (val))
      {
	error ("invalid value = %s", val.c_str ());
	retval = false;
      }

    return retval;
  }
  
  bool contains (const std::string& val)
  {
    return (possible_vals.find (val) != possible_vals.end ());
  }

private:
  // Might also want to cache
  std::string default_val;
  std::set<caseless_str> possible_vals;
};

class radio_property : public base_property
{
public:
  radio_property (const std::string& nm, const graphics_handle& h,
                  const radio_values& v = radio_values ())
    : base_property (nm, h),
      vals (v), current_val (v.default_value ()) { }

  radio_property (const std::string& nm, const graphics_handle& h,
                  const std::string& v)
    : base_property (nm, h),
      vals (v), current_val (vals.default_value ()) { }

  radio_property (const std::string& nm, const graphics_handle& h,
                  const radio_values& v, const std::string& def)
    : base_property (nm, h),
      vals (v), current_val (def) { }

  radio_property (const radio_property& p)
    : base_property (p), vals (p.vals), current_val (p.current_val) { }

  void set (const octave_value& newval) 
  {
    if (newval.is_string ())
      {
        std::string s = newval.string_value ();
        if (vals.validate (s))
          current_val = s;
        else
          error ("set: invalid value for radio property \"%s\" (value = %s)",
              get_name ().c_str (), s.c_str ());
      }
    else	
      error ("set: invalid value for radio property \"%s\"",
          get_name ().c_str ());
  }

  octave_value get (void) const { return octave_value (current_val); }

  const std::string& current_value (void) const { return current_val; }

  bool is (const caseless_str& v) const
    { return v.compare (current_val); }

  radio_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  radio_values vals;
  std::string current_val;
};

// ---------------------------------------------------------------------

class color_values
{
public:
  color_values (double r = 0, double g = 0, double b = 1)
    : xrgb (1, 3)
  {
    xrgb(0) = r;
    xrgb(1) = g;
    xrgb(2) = b;

    validate ();
  }

  color_values (std::string str)
    : xrgb (1, 3)
  {
    if (! str2rgb (str))
      error ("invalid color specification: %s", str.c_str ());
  }

  color_values (const color_values& c)
    : xrgb (c.xrgb)
  { }

  color_values& operator = (const color_values& c)
  {
    if (&c != this)
      xrgb = c.xrgb;

    return *this;
  }

  Matrix rgb (void) const { return xrgb; }

  operator octave_value (void) const { return xrgb; }

  void validate (void) const
  {
    for (int i = 0; i < 3; i++)
      {
	if (xrgb(i) < 0 ||  xrgb(i) > 1)
	  {
	    error ("invalid RGB color specification");
	    break;
	  }
      }
  }

private:
  Matrix xrgb;

  OCTINTERP_API bool str2rgb (std::string str);
};

class color_property : public base_property
{
public:
  color_property (const color_values& c, const radio_values& v)
    : base_property ("", graphics_handle ()),
      current_type (color_t), color_val (c), radio_val (v),
      current_val (v.default_value ())
  { }

  color_property (const std::string& nm, const graphics_handle& h,
                  const color_values& c = color_values (),
                  const radio_values& v = radio_values ())
    : base_property (nm, h),
      current_type (color_t), color_val (c), radio_val (v),
      current_val (v.default_value ())
  { }

  color_property (const std::string& nm, const graphics_handle& h,
                  const radio_values& v)
    : base_property (nm, h),
      current_type (radio_t), color_val (color_values ()), radio_val (v),
      current_val (v.default_value ())
  { }

  color_property (const std::string& nm, const graphics_handle& h,
                  const std::string& v)
    : base_property (nm, h),
      current_type (radio_t), color_val (color_values ()), radio_val (v),
      current_val (radio_val.default_value ())
  { }
  
  color_property (const std::string& nm, const graphics_handle& h,
                  const color_property& v)
    : base_property (nm, h),
      current_type (v.current_type), color_val (v.color_val),
      radio_val (v.radio_val), current_val (v.current_val)
  { }

  color_property (const color_property& p)
    : base_property (p), current_type (p.current_type),
      color_val (p.color_val), radio_val (p.radio_val),
      current_val (p.current_val) { }

  octave_value get (void) const
  {
    if (current_type == color_t)
      return color_val.rgb ();

    return current_val;
  }

  OCTINTERP_API void set (const octave_value& newval);

  bool is_rgb (void) const { return (current_type == color_t); }

  bool is_radio (void) const { return (current_type == radio_t); }

  bool is (const std::string& v) const
    { return (is_radio () && current_val == v); }

  Matrix rgb (void) const
  {
    if (current_type != color_t)
      error ("color has no rgb value");

    return color_val.rgb ();
  }

  const std::string& current_value (void) const
  {
    if (current_type != radio_t)
      error ("color has no radio value");

    return current_val;
  }

  color_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

  operator octave_value (void) const { return get (); }

private:
  enum current_enum { color_t, radio_t } current_type;
  color_values color_val;
  radio_values radio_val;
  std::string current_val;
};

// ---------------------------------------------------------------------

class double_property : public base_property
{
public:
  double_property (const std::string& nm, const graphics_handle& h,
                   double d = 0)
    : base_property (nm, h),
      current_val (d) { }

  double_property (const double_property& p)
    : base_property (p), current_val (p.current_val) { }

  void set (const octave_value& v)
    {
      if (v.is_scalar_type () && v.is_real_type ())
        current_val = v.double_value ();
      else
        error ("set: invalid value for double property \"%s\"",
               get_name ().c_str ());
    }

  octave_value get (void) const { return octave_value (current_val); }

  double double_value (void) const { return current_val; }

  double_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  double current_val;
};

// ---------------------------------------------------------------------

class array_property : public base_property
{
public:
  array_property (const std::string& nm, const graphics_handle& h,
                  const octave_value& m)
    : base_property (nm, h), data (m) { }

  octave_value get (void) const { return data; }

  void set (const octave_value& v)
    {
      if (validate (v))
        data = v;
      else
        error ("invalid value for array property \"%s\"",
               get_name ().c_str ());
    }

  void add_constraint (const std::string& type)
    { type_constraints.push_back (type); }

  void add_constraint (dim_vector dims)
    { size_constraints.push_back (dims); }

  array_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  OCTINTERP_API bool validate (const octave_value& v);

private:
  octave_value data;
  std::list<std::string> type_constraints;
  std::list<dim_vector> size_constraints;
};

// ---------------------------------------------------------------------

class data_property : public base_property
{
public:
  data_property (void)
    : base_property ("", graphics_handle ()) { }

  data_property (const std::string& nm, const graphics_handle& h,
                 const NDArray& m = NDArray ())
    : base_property (nm, h),
      data (m), xmin (octave_Inf), xmax (-octave_Inf), xminp (octave_Inf)
  {
    get_data_limits ();
  }

  data_property (const std::string& nm, const graphics_handle& h,
                 const Matrix& m)
    : base_property (nm, h),
      data (m), xmin (octave_Inf), xmax (-octave_Inf), xminp (octave_Inf)
  {
    get_data_limits ();
  }

  data_property (const data_property& p)
    : base_property (p), data (p.data),
      xmin (p.xmin), xmax (p.xmax), xminp (p.xminp) { }

  void set (const octave_value& val)
  {
    data = val.array_value ();

    get_data_limits ();
  }

  octave_value get (void) const { return data; }

  NDArray array_value (void) const { return data; }

  Matrix matrix_value (void) const { return data.matrix_value (); }

  double min_val (void) const { return xmin; }
  double max_val (void) const { return xmax; }
  double min_pos (void) const { return xminp; }

  data_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  NDArray data;
  double xmin;
  double xmax;
  double xminp;

  void get_data_limits (void)
  {
    octave_idx_type nel = data.numel ();

    if (nel > 0)
      {
	const double *d = data.data ();

	for (octave_idx_type i = 0; i < nel; i++)
	  {
	    double val = d[i];

	    if (! (xisinf (val) || xisnan (val)))
	      {
		if (val < xmin)
		  xmin = val;

		if (val > xmax)
		  xmax = val;

		if (val > 0 && val < xminp)
		  xminp = val;
	      }
	  }
      }
  }
};

// ---------------------------------------------------------------------

class bool_property : public radio_property
{
public:
  bool_property (const std::string& nm, const graphics_handle& h,
                 bool val)
    : radio_property (nm, h, radio_values (val ? "{on}|off" : "on|{off}"))
    { }

  bool_property (const std::string& nm, const graphics_handle& h,
                 const char* val)
    : radio_property (nm, h, radio_values ("on|off"), val)
    { }

  bool_property (const bool_property& p)
    : radio_property (p) { }

  void set (const octave_value& val)
    {
      if (val.is_bool_scalar ())
        radio_property::set (val.bool_value () ? "on" : "off");
      else
        radio_property::set (val);
    }

  bool is_on (void) const { return is ("on"); }
  
  bool_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }
};

// ---------------------------------------------------------------------

class handle_property : public base_property
{
public:
  handle_property (const std::string& nm, const graphics_handle& h,
                   const graphics_handle& val = graphics_handle ())
    : base_property (nm, h),
      current_val (val) { }

  handle_property (const handle_property& p)
    : base_property (p), current_val (p.current_val) { }

  OCTINTERP_API void set (const octave_value& v);

  octave_value get (void) const { return current_val.as_octave_value (); }

  graphics_handle handle_value (void) const { return current_val; }

  handle_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

  handle_property& operator = (const graphics_handle& h)
    {
      set (octave_value (h.value ()));
      return *this;
    }

private:
  graphics_handle current_val;
};

// ---------------------------------------------------------------------

class any_property : public base_property
{
public:
  any_property (const std::string& nm, const graphics_handle& h,
                  const octave_value& m = Matrix ())
    : base_property (nm, h), data (m) { }

  octave_value get (void) const { return data; }

  void set (const octave_value& v) { data = v; }

  any_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  octave_value data;
};

// ---------------------------------------------------------------------

class callback_property : public base_property
{
public:
  callback_property (const std::string& nm, const graphics_handle& h,
                     const octave_value& m)
    : base_property (nm, h), callback (m) { }

  octave_value get (void) const { return callback; }

  void set (const octave_value& v)
    {
      if (validate (v))
        callback = v;
      else
        error ("invalid value for callback property \"%s\"",
               get_name ().c_str ());
    }

  OCTINTERP_API void execute (void);

  callback_property& operator = (const octave_value& val)
    {
      set (val);
      return *this;
    }

private:
  OCTINTERP_API bool validate (const octave_value& v) const;

private:
  octave_value callback;
};

// ---------------------------------------------------------------------

class property
{
public:
  property (void) : rep (new base_property ("", graphics_handle ()))
    { rep->count++; }

  property (base_property *bp, bool persist = false) : rep (bp)
    { rep->count++; if (persist) rep->count++; }

  property (const property& p)
    {
      rep = p.rep;
      rep->count++;
    }

  ~property (void)
    {
      if (--rep->count <= 0)
        delete rep;
    }

  bool ok (void) const
    { return rep->ok (); }

  std::string get_name (void) const
    { return rep->get_name (); }

  void set_name (const std::string& name)
    { rep->set_name (name); }

  graphics_handle get_parent (void) const
    { return rep->get_parent (); }

  void set_parent (const graphics_handle& h)
    { rep->set_parent (h); }

  bool is_hidden (void) const
    { return rep->is_hidden (); }

  void set_hidden (bool flag)
    { rep->set_hidden (flag); }

  octave_value get (void) const
    { return rep->get (); }

  void set (const octave_value& val)
    { rep->set (val); }

  property& operator = (const octave_value& val)
    {
      *rep = val;
      return *this;
    }

  property& operator = (const property& p)
    {
      if (rep && --rep->count <= 0)
        delete rep;
      
      rep = p.rep;
      rep->count++;

      return *this;
    }

  /*
  const string_property& as_string_property (void) const
    { return *(dynamic_cast<string_property*> (rep)); }

  const radio_property& as_radio_property (void) const
    { return *(dynamic_cast<radio_property*> (rep)); }

  const color_property& as_color_property (void) const
    { return *(dynamic_cast<color_property*> (rep)); }

  const double_property& as_double_property (void) const
    { return *(dynamic_cast<double_property*> (rep)); }

  const data_property& as_data_property (void) const
    { return *(dynamic_cast<data_property*> (rep)); }
  
  const bool_property& as_bool_property (void) const
    { return *(dynamic_cast<bool_property*> (rep)); }
  
  const handle_property& as_handle_property (void) const
    { return *(dynamic_cast<handle_property*> (rep)); }
    */

private:
  base_property *rep;
};

// ---------------------------------------------------------------------

class property_list
{
public:
  typedef std::map<std::string, octave_value> pval_map_type;
  typedef std::map<std::string, pval_map_type> plist_map_type;
  
  typedef pval_map_type::iterator pval_map_iterator;
  typedef pval_map_type::const_iterator pval_map_const_iterator;

  typedef plist_map_type::iterator plist_map_iterator;
  typedef plist_map_type::const_iterator plist_map_const_iterator;

  property_list (const plist_map_type& m = plist_map_type ())
    : plist_map (m) { }

  ~property_list (void) { }

  void set (const caseless_str& name, const octave_value& val);

  octave_value lookup (const caseless_str& name) const;

  plist_map_iterator begin (void) { return plist_map.begin (); }
  plist_map_const_iterator begin (void) const { return plist_map.begin (); }

  plist_map_iterator end (void) { return plist_map.end (); }
  plist_map_const_iterator end (void) const { return plist_map.end (); }

  plist_map_iterator find (const std::string& go_name)
  {
    return plist_map.find (go_name);
  }

  plist_map_const_iterator find (const std::string& go_name) const
  {
    return plist_map.find (go_name);
  }

  Octave_map as_struct (const std::string& prefix_arg) const;

private:
  plist_map_type plist_map;
};

// ---------------------------------------------------------------------

class base_graphics_object;

class OCTINTERP_API base_properties
{
public:
  base_properties (const std::string& ty = "unknown",
                   const graphics_handle& mh = graphics_handle (),
                   const graphics_handle& p = graphics_handle ())
    : tag ("tag", mh),
      type ("type", mh, ty),
      __modified__ ("__modified__", mh, true),
      __myhandle__ (mh),
      parent ("parent", mh, p), children ()
    { }

  virtual ~base_properties (void) { }

  virtual std::string graphics_object_name (void) const { return "unknonwn"; }

  void mark_modified (void);

  void override_defaults (base_graphics_object& obj);

  // Look through DEFAULTS for properties with given CLASS_NAME, and
  // apply them to the current object with set (virtual method).

  void set_from_list (base_graphics_object& obj, property_list& defaults);

  void insert_property (const std::string& name, property p)
    {
      p.set_name (name);
      p.set_parent (__myhandle__);
      all_props[name] = p;
    }

  virtual void set (const caseless_str&, const octave_value&);

  virtual octave_value get (const caseless_str&) const;

  virtual octave_value get (void) const;

  property get_property (const caseless_str&) const;

  std::string get_tag (void) const { return tag.string_value (); }

  graphics_handle get_parent (void) const { return parent.handle_value (); }

  std::string get_type (void) const { return type.string_value (); }

  bool is_modified (void) const { return __modified__.is_on (); }
 
  graphics_handle get___myhandle__ (void) const { return __myhandle__; }
 
  void remove_child (const graphics_handle& h);

  void adopt (const graphics_handle& h)
  {
    octave_idx_type n = children.numel ();
    children.resize (1, n+1);
    children(n) = h.value ();
  }

  void set_tag (const octave_value& val) { tag = val; }

  void set_parent (const octave_value& val);

  void reparent (const graphics_handle& new_parent) { parent = new_parent; }

  // Update data limits for AXIS_TYPE (xdata, ydata, etc.) in the parent
  // axes object.

  void update_axis_limits (const std::string& axis_type) const;

  virtual void delete_children (void);

  Matrix get_children (void) const { return children; }

  // FIXME -- these functions should be generated automatically by the
  // genprops.awk script.
  //
  // EMIT_BASE_PROPERTIES_GET_FUNCTIONS
  virtual data_property get_xdata_property (void) const
  {
    error ("get: invalid property \"xdata\"");
    return data_property ();
  }

  virtual data_property get_ydata_property (void) const
  {
    error ("get: invalid property \"ydata\"");
    return data_property ();
  }

  virtual data_property get_zdata_property (void) const
  {
    error ("get: invalid property \"zdata\"");
    return data_property ();
  }

  virtual data_property get_ldata_property (void) const
  {
    error ("get: invalid property \"ldata\"");
    return data_property ();
  }

  virtual data_property get_udata_property (void) const
  {
    error ("get: invalid property \"udata\"");
    return data_property ();
  }

  virtual data_property get_xldata_property (void) const
  {
    error ("get: invalid property \"xldata\"");
    return data_property ();
  }

  virtual data_property get_xudata_property (void) const
  {
    error ("get: invalid property \"xudata\"");
    return data_property ();
  }

  virtual data_property get_cdata_property (void) const
  {
    error ("get: invalid property \"cdata\"");
    return data_property ();
  }

protected:
  string_property tag;
  string_property type;
  bool_property __modified__;
  graphics_handle __myhandle__;
  handle_property parent;
  // FIXME: use a property class for children
  Matrix children;

protected:
  std::map<caseless_str, property> all_props;

protected:
  void insert_static_property (const std::string& name, base_property& p)
    { insert_property (name, property (&p, true)); }
  
  virtual void init (void) { }
};

class OCTINTERP_API base_graphics_object
{
public:
  friend class graphics_object;

  base_graphics_object (void) : count (1) { }

  base_graphics_object (const base_graphics_object&) { }

  virtual ~base_graphics_object (void) { }

  virtual void mark_modified (void)
  {
    error ("base_graphics_object::mark_modified: invalid graphics object");
  }

  virtual void override_defaults (base_graphics_object&)
  {
    error ("base_graphics_object::override_defaults: invalid graphics object");
  }

  virtual void set_from_list (property_list&)
  {
    error ("base_graphics_object::set_from_list: invalid graphics object");
  }

  virtual void set (const caseless_str&, const octave_value&)
  {
    error ("base_graphics_object::set: invalid graphics object");
  }

  virtual void set_defaults (const std::string&)
  {
    error ("base_graphics_object::set_defaults: invalid graphics object");
  }

  virtual octave_value get (void) const
  {
    error ("base_graphics_object::get: invalid graphics object");
    return octave_value ();
  }

  virtual octave_value get (const caseless_str&) const
  {
    error ("base_graphics_object::get: invalid graphics object");
    return octave_value ();
  }

  virtual octave_value get_default (const caseless_str&) const;

  virtual octave_value get_factory_default (const caseless_str&) const;

  virtual octave_value get_defaults (void) const
  {
    error ("base_graphics_object::get_defaults: invalid graphics object");
    return octave_value ();
  }

  virtual octave_value get_factory_defaults (void) const
  {
    error ("base_graphics_object::get_factory_defaults: invalid graphics object");
    return octave_value ();
  }

  virtual graphics_handle get_parent (void) const
  {
    error ("base_graphics_object::get_parent: invalid graphics object");
    return graphics_handle ();
  }

  virtual void remove_child (const graphics_handle&)
  {
    error ("base_graphics_object::remove_child: invalid graphics object");
  }

  virtual void adopt (const graphics_handle&)
  {
    error ("base_graphics_object::adopt: invalid graphics object");
  }

  virtual void reparent (const graphics_handle&)
  {
    error ("base_graphics_object::reparent: invalid graphics object");
  }

  virtual void defaults (void) const
  {
    error ("base_graphics_object::default: invalid graphics object");
  }

  virtual base_properties& get_properties (void)
  {
    static base_properties properties;
    error ("base_graphics_object::get_properties: invalid graphics object");
    return properties;
  }

  virtual const base_properties& get_properties (void) const
  {
    static base_properties properties;
    error ("base_graphics_object::get_properties: invalid graphics object");
    return properties;
  }

  virtual void update_axis_limits (const std::string&)
  {
    error ("base_graphics_object::update_axis_limits: invalid graphics object");
  }

  virtual bool valid_object (void) const { return false; }

  virtual std::string type (void) const { return "unknown"; }

  bool isa (const std::string& go_name) const
  {
    return type () == go_name;
  }

protected:
  // A reference count.
  int count;
};

class OCTINTERP_API graphics_object
{
public:
  graphics_object (void) : rep (new base_graphics_object ()) { }

  graphics_object (base_graphics_object *new_rep)
    : rep (new_rep) { }

  graphics_object (const graphics_object& obj)
  {
    rep = obj.rep;
    rep->count++;
  }

  graphics_object& operator = (const graphics_object& obj)
  {
    if (rep != obj.rep)
      {
	if (--rep->count == 0)
	  delete rep;

	rep = obj.rep;
	rep->count++;
      }

    return *this;
  }

  ~graphics_object (void)
  {
    if (--rep->count == 0)
      delete rep;
  }

  void mark_modified (void) { rep->mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    rep->override_defaults (obj);
  }

  void set_from_list (property_list& plist) { rep->set_from_list (plist); }

  void set (const caseless_str& name, const octave_value& val)
  {
    rep->set (name, val);
  }

  void set (const octave_value_list& args);

  void set_defaults (const std::string& mode) { rep->set_defaults (mode); }

  octave_value get (void) const { return rep->get (); }

  octave_value get (const caseless_str& name) const
  {
    return name.compare ("default")
      ? get_defaults ()
      : (name.compare ("factory")
	 ? get_factory_defaults () : rep->get (name));
  }

  octave_value get_default (const caseless_str& name) const
  {
    return rep->get_default (name);
  }

  octave_value get_factory_default (const caseless_str& name) const
  {
    return rep->get_factory_default (name);
  }

  octave_value get_defaults (void) const { return rep->get_defaults (); }

  octave_value get_factory_defaults (void) const
  {
    return rep->get_factory_defaults ();
  }

  graphics_handle get_parent (void) const { return rep->get_parent (); }

  void remove_child (const graphics_handle& h) { rep->remove_child (h); }

  void adopt (const graphics_handle& h) { rep->adopt (h); }

  void reparent (const graphics_handle& h) { rep->reparent (h); }

  void defaults (void) const { rep->defaults (); }

  bool isa (const std::string& go_name) const { return rep->isa (go_name); }

  base_properties& get_properties (void) { return rep->get_properties (); }

  const base_properties& get_properties (void) const
  {
    return rep->get_properties ();
  }

  void update_axis_limits (const std::string& axis_type)
  {
    rep->update_axis_limits (axis_type);
  }

  bool valid_object (void) const { return rep->valid_object (); }

  operator bool (void) const { return rep->valid_object (); }

  // FIXME -- these functions should be generated automatically by the
  // genprops.awk script.
  //
  // EMIT_GRAPHICS_OBJECT_GET_FUNCTIONS
  data_property get_xdata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_xdata_property ();
  }

  data_property get_ydata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_ydata_property ();
  }

  data_property get_zdata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_zdata_property ();
  }

  data_property get_ldata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_ldata_property ();
  }

  data_property get_udata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_udata_property ();
  }

  data_property get_xldata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_xldata_property ();
  }

  data_property get_xudata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_xudata_property ();
  }

  data_property get_cdata_property (void) const
  {
    const base_properties& props = get_properties ();
    return props.get_cdata_property ();
  }

private:
  base_graphics_object *rep;
};

// ---------------------------------------------------------------------

class OCTINTERP_API root_figure : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(root_figure)
      handle_property currentfigure S , graphics_handle ()
      bool_property visible , "on"
    END_PROPERTIES
  };

private:
  properties xproperties;

public:

  root_figure (void) : xproperties (0, graphics_handle ()), default_properties () { }

  ~root_figure (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { }

  void override_defaults (base_graphics_object& obj)
  {
    // Now override with our defaults.  If the default_properties
    // list includes the properties for all defaults (line,
    // surface, etc.) then we don't have to know the type of OBJ
    // here, we just call its set function and let it decide which
    // properties from the list to use.
    obj.set_from_list (default_properties);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& value)
  {
    if (name.compare ("default", 7))
      // strip "default", pass rest to function that will
      // parse the remainder and add the element to the
      // default_properties map.
      default_properties.set (name.substr (7), value);
    else
      xproperties.set (name, value);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    octave_value retval;

    if (name.compare ("default", 7))
      return get_default (name.substr (7));
    else if (name.compare ("factory", 7))
      return get_factory_default (name.substr (7));
    else
      retval = xproperties.get (name);

    return retval;
  }

  octave_value get_default (const caseless_str& name) const
  {
    octave_value retval = default_properties.lookup (name);

    if (retval.is_undefined ())
      error ("get: invalid default property `%s'", name.c_str ());

    return retval;
  }

  octave_value get_factory_default (const caseless_str& name) const
  {
    octave_value retval = factory_properties.lookup (name);

    if (retval.is_undefined ())
      error ("get: invalid factory default property `%s'", name.c_str ());

    return retval;
  }

  octave_value get_defaults (void) const
  {
    return default_properties.as_struct ("default");
  }

  octave_value get_factory_defaults (void) const
  {
    return factory_properties.as_struct ("factory");
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& np) { xproperties.reparent (np); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const
  {
    gripe_not_implemented ("root_figure::defaults");
  }

  bool valid_object (void) const { return true; }

private:
  property_list default_properties;

  static property_list factory_properties;

  static property_list::plist_map_type init_factory_properties (void);
};

// ---------------------------------------------------------------------

class OCTINTERP_API figure : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    void close (void);

    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(figure)
      any_property __plot_stream__ , Matrix ()
      bool_property __enhanced__ , "on"
      radio_property nextplot , "add|replace_children|{replace}"
      callback_property closerequestfcn , "closereq"
      handle_property currentaxes S , graphics_handle ()
      array_property colormap , jet_colormap ()
      bool_property visible S , "on"
      radio_property paperorientation , "{portrait}|landscape"
      color_property color , color_values (1, 1, 1)
    END_PROPERTIES
    
  protected:
    void init (void)
      {
        colormap.add_constraint (dim_vector (-1, 3));
      }

  };

private:
  properties xproperties;

public:
  figure (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p), default_properties ()
  {
    xproperties.override_defaults (*this);
  }

  ~figure (void)
  {
    xproperties.delete_children ();
    xproperties.close ();
  }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (root figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);

    // Now override with our defaults.  If the default_properties
    // list includes the properties for all defaults (line,
    // surface, etc.) then we don't have to know the type of OBJ
    // here, we just call its set function and let it decide which
    // properties from the list to use.
    obj.set_from_list (default_properties);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& value)
  {
    if (name.compare ("default", 7))
      // strip "default", pass rest to function that will
      // parse the remainder and add the element to the
      // default_properties map.
      default_properties.set (name.substr (7), value);
    else
      xproperties.set (name, value);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    octave_value retval;

    if (name.compare ("default", 7))
      retval = get_default (name.substr (7));
    else
      retval = xproperties.get (name);

    return retval;
  }

  octave_value get_default (const caseless_str& name) const;

  octave_value get_defaults (void) const
  {
    return default_properties.as_struct ("default");
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& np) { xproperties.reparent (np); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("figure::defaults"); }

  bool valid_object (void) const { return true; }

private:
  property_list default_properties;
};

// ---------------------------------------------------------------------

class OCTINTERP_API axes : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    void set_defaults (base_graphics_object& obj, const std::string& mode);

    void remove_child (const graphics_handle& h);

    void delete_children (void);

    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(axes)
      array_property position , Matrix ()
      mutable handle_property title GSO , graphics_handle ()
      bool_property box , "on"
      bool_property key , "off"
      bool_property keybox , "off"
      double_property keypos , 1
      array_property colororder , default_colororder ()
      array_property dataaspectratio m , Matrix (1, 3, 1.0)
      radio_property dataaspectratiomode , "{auto}|manual"
      radio_property layer a , "{bottom}|top"
      array_property xlim m , default_lim ()
      array_property ylim m , default_lim ()
      array_property zlim m , default_lim ()
      array_property clim m , default_lim ()
      radio_property xlimmode al , "{auto}|manual"
      radio_property ylimmode al , "{auto}|manual"
      radio_property zlimmode al , "{auto}|manual"
      radio_property climmode al , "{auto}|manual"
      mutable handle_property xlabel GSO , graphics_handle ()
      mutable handle_property ylabel GSO , graphics_handle ()
      mutable handle_property zlabel GSO , graphics_handle ()
      bool_property xgrid , "off"
      bool_property ygrid , "off"
      bool_property zgrid , "off"
      bool_property xminorgrid , "off"
      bool_property yminorgrid , "off"
      bool_property zminorgrid , "off"
      array_property xtick m , Matrix ()
      array_property ytick m , Matrix ()
      array_property ztick m , Matrix ()
      radio_property xtickmode , "{auto}|manual"
      radio_property ytickmode , "{auto}|manual"
      radio_property ztickmode , "{auto}|manual"
      any_property xticklabel m , ""
      any_property yticklabel m , ""
      any_property zticklabel m , ""
      radio_property xticklabelmode , "{auto}|manual"
      radio_property yticklabelmode , "{auto}|manual"
      radio_property zticklabelmode , "{auto}|manual"
      color_property color a , color_property (color_values (1, 1, 1), radio_values ("none"))
      color_property xcolor , color_values (0, 0, 0)
      color_property ycolor , color_values (0, 0, 0)
      color_property zcolor , color_values (0, 0, 0)
      radio_property xscale al , "{linear}|log"
      radio_property yscale al , "{linear}|log"
      radio_property zscale al , "{linear}|log"
      radio_property xdir , "{normal}|reverse"
      radio_property ydir , "{normal}|reverse"
      radio_property zdir , "{normal}|reverse"
      radio_property yaxislocation , "{left}|right|zero"
      radio_property xaxislocation , "{bottom}|top|zero"
      array_property view , Matrix ()
      bool_property visible , "on"
      radio_property nextplot , "add|replace_children|{replace}"
      array_property outerposition , Matrix ()
      radio_property activepositionproperty a , "{outerposition}|position"
      radio_property __colorbar__ a , "{none}|north|south|east|west|northoutside|southoutside|eastoutside|westoutside"
   END_PROPERTIES

  protected:
    void init (void)
      {
        position.add_constraint (dim_vector (1, 4));
		position.add_constraint (dim_vector (0, 0));
        outerposition.add_constraint (dim_vector (1, 4));
        colororder.add_constraint (dim_vector (-1, 3));
        dataaspectratio.add_constraint (dim_vector (1, 3));
        xlim.add_constraint (dim_vector (1, 2));
        ylim.add_constraint (dim_vector (1, 2));
        zlim.add_constraint (dim_vector (1, 2));
        clim.add_constraint (dim_vector (1, 2));
        xtick.add_constraint (dim_vector (1, -1));
        ytick.add_constraint (dim_vector (1, -1));
        ztick.add_constraint (dim_vector (1, -1));
        Matrix vw (1, 2, 0);
        vw(1) = 90;
        view = vw;
        view.add_constraint (dim_vector (1, 2));
      }
  };

private:
  properties xproperties;

public:
  axes (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p), default_properties ()
  {
    xproperties.override_defaults (*this);
  }

  ~axes (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);

    // Now override with our defaults.  If the default_properties
    // list includes the properties for all defaults (line,
    // surface, etc.) then we don't have to know the type of OBJ
    // here, we just call its set function and let it decide which
    // properties from the list to use.
    obj.set_from_list (default_properties);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& value)
  {
    if (name.compare ("default", 7))
      // strip "default", pass rest to function that will
      // parse the remainder and add the element to the
      // default_properties map.
      default_properties.set (name.substr (7), value);
    else
      xproperties.set (name, value);
  }

  void set_defaults (const std::string& mode)
  {
    xproperties.set_defaults (*this, mode);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    octave_value retval;

    // FIXME -- finish this.
    if (name.compare ("default", 7))
      retval = get_default (name.substr (7));
    else
      retval = xproperties.get (name);

    return retval;
  }

  octave_value get_default (const caseless_str& name) const;

  octave_value get_defaults (void) const
  {
    return default_properties.as_struct ("default");
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& np) { xproperties.reparent (np); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("axes::defaults"); }

  void update_axis_limits (const std::string& axis_type);

  bool valid_object (void) const { return true; }

private:
  property_list default_properties;
};

// ---------------------------------------------------------------------

class OCTINTERP_API line : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(line)
      data_property xdata l , default_data ()
      data_property ydata l , default_data ()
      data_property zdata l , Matrix ()
      data_property ldata l , Matrix ()
      data_property udata l , Matrix ()
      data_property xldata l , Matrix ()
      data_property xudata l , Matrix ()
      color_property color , color_values (0, 0, 0)
      radio_property linestyle , "{-}|--|:|-.|none"
      double_property linewidth , 0.5
      radio_property marker , "{none}|s|o|x|+|.|*|<|>|v|^|d|p|h"
      color_property markeredgecolor , "{auto}|none"
      color_property markerfacecolor , "auto|{none}"
      double_property markersize , 6
      string_property keylabel , ""
      radio_property interpreter a , "{tex}|none|latex"
    END_PROPERTIES
  };

private:
  properties xproperties;

public:
  line (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p)
  {
    xproperties.override_defaults (*this);
  }

  ~line (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& val)
  {
    xproperties.set (name, val);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    return xproperties.get (name);
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& h) { xproperties.reparent (h); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("line::defaults"); }

  bool valid_object (void) const { return true; }
};

// ---------------------------------------------------------------------

class OCTINTERP_API text : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(text)
      string_property string , ""
      radio_property units , "{data}|pixels|normalized|inches|centimeters|points"
      array_property position , Matrix (1, 3, 0.0)
      double_property rotation , 0
      radio_property horizontalalignment , "{left}|center|right"
      color_property color , color_values (0, 0, 0)
      string_property fontname , "Helvetica"
      double_property fontsize , 10
      radio_property fontangle a , "{normal}|italic|oblique"
      radio_property fontweight a , "light|{normal}|demi|bold"
      radio_property interpreter a , "{tex}|none|latex"
    END_PROPERTIES

  protected:
    void init (void)
      {
        position.add_constraint (dim_vector (1, 3));
      }
  };

private:
  properties xproperties;

public:
  text (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p)
  {
    xproperties.override_defaults (*this);
  }

  ~text (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& val)
  {
    xproperties.set (name, val);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    return xproperties.get (name);
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& h) { xproperties.reparent (h); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("text::defaults"); }

  bool valid_object (void) const { return true; }
};

// ---------------------------------------------------------------------

class OCTINTERP_API image : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(image)
      data_property xdata l , Matrix ()
      data_property ydata l , Matrix ()
      data_property cdata l , Matrix ()
    END_PROPERTIES

  protected:
    void init (void)
      {
      }
  };

private:
  properties xproperties;

public:
  image (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p)
  {
    xproperties.override_defaults (*this);
  }

  ~image (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& val)
  {
    xproperties.set (name, val);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    return xproperties.get (name);
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& h) { xproperties.reparent (h); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("image::defaults"); }

  bool valid_object (void) const { return true; }
};

// ---------------------------------------------------------------------

class OCTINTERP_API patch : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(patch)
      data_property xdata l , Matrix ()
      data_property ydata l , Matrix ()
      data_property zdata l , Matrix ()
      data_property cdata l , Matrix ()
      array_property faces , Matrix ()
      array_property vertices , Matrix ()
      color_property facecolor a , "{flat}|none|interp"
      double_property facealpha , 1.0
      color_property edgecolor a , color_property (color_values (0, 0, 0), radio_values ("flat|none|interp"))
      radio_property linestyle , "{-}|--|:|-.|none"
      double_property linewidth , 0.5
      radio_property marker , "{none}|s|o|x|+|.|*|<|>|v|^|d|p|h"
      color_property markeredgecolor , "{auto}|none"
      color_property markerfacecolor , "auto|{none}"
      double_property markersize , 6
      string_property keylabel , ""
      radio_property interpreter a , "{tex}|none|latex"
    END_PROPERTIES

  protected:
    void init (void)
      {
        vertices.add_constraint (dim_vector (-1, 2));
        vertices.add_constraint (dim_vector (-1, 3));
      }
  };

private:
  properties xproperties;

public:
  patch (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p)
  {
    xproperties.override_defaults (*this);
  }

  ~patch (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& val)
  {
    xproperties.set (name, val);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    return xproperties.get (name);
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& h) { xproperties.reparent (h); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("patch::defaults"); }

  bool valid_object (void) const { return true; }
};

// ---------------------------------------------------------------------

class OCTINTERP_API surface : public base_graphics_object
{
public:
  class properties : public base_properties
  {
  public:
    // See the genprops.awk script for an explanation of the
    // properties declarations.

    BEGIN_PROPERTIES(surface)
      data_property xdata l , Matrix ()
      data_property ydata l , Matrix ()
      data_property zdata l , Matrix ()
      data_property cdata l , Matrix ()
      color_property facecolor a , "{flat}|none|interp"
      double_property facealpha , 1.0
      color_property edgecolor a , color_property (color_values (0, 0, 0), radio_values ("flat|none|interp"))
      radio_property linestyle , "{-}|--|:|-.|none"
      double_property linewidth , 0.5
      radio_property marker , "{none}|s|o|x|+|.|*|<|>|v|^|d|p|h"
      color_property markeredgecolor , "{auto}|none"
      color_property markerfacecolor , "auto|{none}"
      double_property markersize , 6
      string_property keylabel , ""
      radio_property interpreter a , "{tex}|none|latex"
    END_PROPERTIES

  protected:
    void init (void)
      {
      }
  };

private:
  properties xproperties;

public:
  surface (const graphics_handle& mh, const graphics_handle& p)
    : base_graphics_object (), xproperties (mh, p)
  {
    xproperties.override_defaults (*this);
  }

  ~surface (void) { xproperties.delete_children (); }

  std::string type (void) const { return xproperties.graphics_object_name (); }

  void mark_modified (void) { xproperties.mark_modified (); }

  void override_defaults (base_graphics_object& obj)
  {
    // Allow parent (figure) to override first (properties knows how
    // to find the parent object).
    xproperties.override_defaults (obj);
  }

  void set_from_list (property_list& plist)
  {
    xproperties.set_from_list (*this, plist);
  }

  void set (const caseless_str& name, const octave_value& val)
  {
    xproperties.set (name, val);
  }

  octave_value get (void) const
  {
    return xproperties.get ();
  }

  octave_value get (const caseless_str& name) const
  {
    return xproperties.get (name);
  }

  graphics_handle get_parent (void) const { return xproperties.get_parent (); }

  void remove_child (const graphics_handle& h) { xproperties.remove_child (h); }

  void adopt (const graphics_handle& h) { xproperties.adopt (h); }

  void reparent (const graphics_handle& h) { xproperties.reparent (h); }

  base_properties& get_properties (void) { return xproperties; }

  const base_properties& get_properties (void) const { return xproperties; }

  void defaults (void) const { gripe_not_implemented ("surface::defaults"); }

  bool valid_object (void) const { return true; }
};

octave_value
get_property_from_handle (double handle, const std::string &property,
			  const std::string &func);
bool
set_property_in_handle (double handle, const std::string &property,
			const octave_value &arg, const std::string &func);

// ---------------------------------------------------------------------

class OCTINTERP_API gh_manager
{
protected:

  gh_manager (void);

public:

  static bool instance_ok (void)
  {
    bool retval = true;

    if (! instance)
      instance = new gh_manager ();

    if (! instance)
      {
	::error ("unable to create gh_manager!");

	retval = false;
      }

    return retval;
  }

  static void free (const graphics_handle& h)
  {
    if (instance_ok ())
      instance->do_free (h);
  }

  static graphics_handle lookup (double val)
  {
    return instance_ok () ? instance->do_lookup (val) : graphics_handle ();
  }

  static graphics_object get_object (const graphics_handle& h)
  {
    return instance_ok () ? instance->do_get_object (h) : graphics_object ();
  }

  static graphics_handle
  make_graphics_handle (const std::string& go_name,
			const graphics_handle& parent)
  {
    return instance_ok ()
      ? instance->do_make_graphics_handle (go_name, parent)
      : graphics_handle ();
  }

  static graphics_handle make_figure_handle (double val)
  {
    return instance_ok ()
      ? instance->do_make_figure_handle (val) : graphics_handle ();
  }

  static void push_figure (const graphics_handle& h)
  {
    if (instance_ok ())
      instance->do_push_figure (h);
  }

  static void pop_figure (const graphics_handle& h)
  {
    if (instance_ok ())
      instance->do_pop_figure (h);
  }

  static graphics_handle current_figure (void)
  {
    return instance_ok ()
      ? instance->do_current_figure () : graphics_handle ();
  }

  static Matrix handle_list (void)
  {
    return instance_ok () ? instance->do_handle_list () : Matrix ();
  }

  static Matrix figure_handle_list (void)
  {
    return instance_ok () ? instance->do_figure_handle_list () : Matrix ();
  }

private:

  static gh_manager *instance;

  typedef std::map<graphics_handle, graphics_object>::iterator iterator;
  typedef std::map<graphics_handle, graphics_object>::const_iterator const_iterator;

  typedef std::set<graphics_handle>::iterator free_list_iterator;
  typedef std::set<graphics_handle>::const_iterator const_free_list_iterator;

  typedef std::list<graphics_handle>::iterator figure_list_iterator;
  typedef std::list<graphics_handle>::const_iterator const_figure_list_iterator;

  // A map of handles to graphics objects.
  std::map<graphics_handle, graphics_object> handle_map;

  // The available graphics handles.
  std::set<graphics_handle> handle_free_list;

  // The next handle available if handle_free_list is empty.
  double next_handle;

  // The allocated figure handles.  Top of the stack is most recently
  // created.
  std::list<graphics_handle> figure_list;

  graphics_handle get_handle (const std::string& go_name);

  void do_free (const graphics_handle& h);

  graphics_handle do_lookup (double val)
  {
    iterator p = (xisnan (val) ? handle_map.end () : handle_map.find (val));

    return (p != handle_map.end ()) ? p->first : graphics_handle ();
  }

  graphics_object do_get_object (const graphics_handle& h)
  {
    iterator p = handle_map.find (h);

    return (p != handle_map.end ()) ? p->second : graphics_object ();
  }

  graphics_handle do_make_graphics_handle (const std::string& go_name,
					   const graphics_handle& p);

  graphics_handle do_make_figure_handle (double val);

  Matrix do_handle_list (void)
  {
    Matrix retval (1, handle_map.size ());
    octave_idx_type i = 0;
    for (const_iterator p = handle_map.begin (); p != handle_map.end (); p++)
      {
	graphics_handle h = p->first;
	retval(i++) = h.value ();
      }
    return retval;
  }

  Matrix do_figure_handle_list (void)
  {
    Matrix retval (1, figure_list.size ());
    octave_idx_type i = 0;
    for (const_figure_list_iterator p = figure_list.begin ();
	 p != figure_list.end ();
	 p++)
      {
	graphics_handle h = *p;
	retval(i++) = h.value ();
      }
    return retval;
  }

  void do_push_figure (const graphics_handle& h);

  void do_pop_figure (const graphics_handle& h);

  graphics_handle do_current_figure (void) const
  {
    return figure_list.empty () ? graphics_handle () : figure_list.front ();
  }
};


// This function is NOT equivalent to the scripting language function gcf.
OCTINTERP_API graphics_handle gcf (void);

// This function is NOT equivalent to the scripting language function gca.
OCTINTERP_API graphics_handle gca (void);

#endif

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/