src/graphics.cc
author John W. Eaton <jwe@octave.org>
Thu Jul 16 11:56:44 2009 -0400 (2009-07-16)
changeset 9384 44300eb51817
parent 9318 282968d49949
child 9416 7ed8182b783d
permissions -rw-r--r--
graphics.cc (get_array_limits): require min_pos value to be greater than zero
jwe@6406
     1
/*
jwe@6406
     2
jwe@8920
     3
Copyright (C) 2007, 2008, 2009 John W. Eaton
jwe@6406
     4
jwe@6406
     5
This file is part of Octave.
jwe@6406
     6
jwe@6406
     7
Octave is free software; you can redistribute it and/or modify it
jwe@6406
     8
under the terms of the GNU General Public License as published by the
jwe@7016
     9
Free Software Foundation; either version 3 of the License, or (at your
jwe@7016
    10
option) any later version.
jwe@6406
    11
jwe@6406
    12
Octave is distributed in the hope that it will be useful, but WITHOUT
jwe@6406
    13
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jwe@6406
    14
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jwe@6406
    15
for more details.
jwe@6406
    16
jwe@6406
    17
You should have received a copy of the GNU General Public License
jwe@7016
    18
along with Octave; see the file COPYING.  If not, see
jwe@7016
    19
<http://www.gnu.org/licenses/>.
jwe@6406
    20
jwe@6406
    21
*/
jwe@6406
    22
jwe@6406
    23
#ifdef HAVE_CONFIG_H
jwe@6406
    24
#include <config.h>
jwe@6406
    25
#endif
jwe@6406
    26
jwe@6406
    27
#include <cctype>
jwe@7222
    28
#include <cfloat>
jwe@7286
    29
#include <cstdlib>
jwe@6406
    30
jwe@6406
    31
#include <algorithm>
jwe@6406
    32
#include <list>
jwe@6406
    33
#include <map>
jwe@6406
    34
#include <set>
jwe@6406
    35
#include <string>
jwe@8059
    36
#include <sstream>
jwe@6406
    37
jwe@7409
    38
#include "file-ops.h"
jwe@7409
    39
#include "file-stat.h"
jwe@7409
    40
jwe@7936
    41
#include "cmd-edit.h"
jwe@6705
    42
#include "defun.h"
jwe@8560
    43
#include "display.h"
jwe@6705
    44
#include "error.h"
dbateman@6595
    45
#include "graphics.h"
jwe@7409
    46
#include "input.h"
jwe@6705
    47
#include "ov.h"
jwe@6705
    48
#include "oct-obj.h"
jwe@6705
    49
#include "oct-map.h"
jwe@6705
    50
#include "ov-fcn-handle.h"
jwe@6705
    51
#include "parse.h"
jwe@7409
    52
#include "toplev.h"
jwe@7222
    53
#include "unwind-prot.h"
dbateman@6595
    54
michael@9238
    55
// forward declaration
michael@9238
    56
static octave_value xget (const graphics_handle& h, const caseless_str& name);
michael@9238
    57
jwe@6406
    58
static void
jwe@6406
    59
gripe_set_invalid (const std::string& pname)
jwe@6406
    60
{
jwe@6406
    61
  error ("set: invalid value for %s property", pname.c_str ());
jwe@6406
    62
}
jwe@6406
    63
jwe@7363
    64
static Matrix
jwe@7363
    65
jet_colormap (void)
jwe@7363
    66
{
jwe@7363
    67
  Matrix cmap (64, 3, 0.0);
jwe@7363
    68
jwe@7363
    69
  for (octave_idx_type i = 0; i < 64; i++)
jwe@7363
    70
    {
jwe@7363
    71
      // This is the jet colormap.  It would be nice to be able
jwe@7363
    72
      // to feval the jet function but since there is a static
jwe@7363
    73
      // property object that includes a colormap_property
jwe@7363
    74
      // object, we need to initialize this before main is even
jwe@7363
    75
      // called, so calling an interpreted function is not
jwe@7363
    76
      // possible.
jwe@7363
    77
jwe@7363
    78
      double x = i / 63.0;
jwe@7363
    79
jwe@7363
    80
      if (x >= 3.0/8.0 && x < 5.0/8.0)
jwe@7363
    81
        cmap(i,0) = 4.0 * x - 3.0/2.0;
jwe@7363
    82
      else if (x >= 5.0/8.0 && x < 7.0/8.0)
jwe@7363
    83
        cmap(i,0) = 1.0;
jwe@7363
    84
      else if (x >= 7.0/8.0)
jwe@7363
    85
        cmap(i,0) = -4.0 * x + 9.0/2.0;
jwe@7363
    86
jwe@7363
    87
      if (x >= 1.0/8.0 && x < 3.0/8.0)
jwe@7363
    88
        cmap(i,1) = 4.0 * x - 1.0/2.0;
jwe@7363
    89
      else if (x >= 3.0/8.0 && x < 5.0/8.0)
jwe@7363
    90
        cmap(i,1) = 1.0;
jwe@7363
    91
      else if (x >= 5.0/8.0 && x < 7.0/8.0)
jwe@7363
    92
        cmap(i,1) = -4.0 * x + 7.0/2.0;
jwe@7363
    93
jwe@7363
    94
      if (x < 1.0/8.0)
jwe@7363
    95
        cmap(i,2) = 4.0 * x + 1.0/2.0;
jwe@7363
    96
      else if (x >= 1.0/8.0 && x < 3.0/8.0)
jwe@7363
    97
        cmap(i,2) = 1.0;
jwe@7363
    98
      else if (x >= 3.0/8.0 && x < 5.0/8.0)
jwe@7363
    99
        cmap(i,2) = -4.0 * x + 5.0/2.0;
jwe@7363
   100
    }
jwe@7363
   101
jwe@7363
   102
  return cmap;
jwe@7363
   103
}
jwe@7363
   104
jwe@8560
   105
static double
jwe@8560
   106
default_screendepth (void)
jwe@8560
   107
{
jwe@8560
   108
  return display_info::depth ();
jwe@8560
   109
}
jwe@8560
   110
jwe@8560
   111
static Matrix
jwe@8560
   112
default_screensize (void)
jwe@8560
   113
{
jwe@8560
   114
  Matrix retval (1, 4, 1.0);
jwe@8560
   115
jwe@8560
   116
  retval(2) = display_info::width ();
jwe@8560
   117
  retval(3) = display_info::height ();
jwe@8560
   118
jwe@8560
   119
  return retval;
jwe@8560
   120
}
jwe@8560
   121
jwe@8560
   122
static double
jwe@8560
   123
default_screenpixelsperinch (void)
jwe@8560
   124
{
jwe@8560
   125
  return (display_info::x_dpi () + display_info::y_dpi ()) / 2;
jwe@8560
   126
}
jwe@8560
   127
jwe@7363
   128
static Matrix
jwe@7363
   129
default_colororder (void)
jwe@7363
   130
{
jwe@7363
   131
  Matrix retval (7, 3, 0.0);
jwe@7363
   132
jwe@7363
   133
  retval(0,2) = 1.0;
jwe@7363
   134
jwe@7363
   135
  retval(1,1) = 0.5;
jwe@7363
   136
jwe@7363
   137
  retval(2,0) = 1.0;
jwe@7363
   138
jwe@7363
   139
  retval(3,1) = 0.75;
jwe@7363
   140
  retval(3,2) = 0.75;
jwe@7363
   141
jwe@7363
   142
  retval(4,0) = 0.75;
jwe@7363
   143
  retval(4,2) = 0.75;
jwe@7363
   144
jwe@7363
   145
  retval(5,0) = 0.75;
jwe@7363
   146
  retval(5,1) = 0.75;
jwe@7363
   147
jwe@7363
   148
  retval(6,0) = 0.25;
jwe@7363
   149
  retval(6,1) = 0.25;
jwe@7363
   150
  retval(6,2) = 0.25;
jwe@7363
   151
jwe@7363
   152
  return retval;
jwe@7363
   153
}
jwe@7363
   154
jwe@7363
   155
static Matrix
jwe@7363
   156
default_lim (void)
jwe@7363
   157
{
jwe@7363
   158
  Matrix m (1, 2, 0);
jwe@7363
   159
  m(1) = 1;
jwe@7363
   160
  return m;
jwe@7363
   161
}
jwe@7363
   162
jwe@7363
   163
static Matrix
jwe@7363
   164
default_data (void)
jwe@7363
   165
{
jwe@7363
   166
  Matrix retval (1, 2);
jwe@7363
   167
jwe@7363
   168
  retval(0) = 0;
jwe@7363
   169
  retval(1) = 1;
jwe@7363
   170
jwe@7363
   171
  return retval;
jwe@7363
   172
}
jwe@7363
   173
jwe@7427
   174
static Matrix
jwe@7427
   175
default_axes_position (void)
jwe@7427
   176
{
jwe@7427
   177
  Matrix m (1, 4, 0.0);
jwe@7427
   178
  m(0) = 0.13;
jwe@7427
   179
  m(1) = 0.11;
jwe@7427
   180
  m(2) = 0.775;
jwe@7427
   181
  m(3) = 0.815;
jwe@7427
   182
  return m;
jwe@7427
   183
}
jwe@7427
   184
jwe@7427
   185
static Matrix
jwe@7427
   186
default_axes_outerposition (void)
jwe@7427
   187
{
jwe@7427
   188
  Matrix m (1, 4, 0.0);
jwe@7427
   189
  m(2) = m(3) = 1.0;
jwe@7427
   190
  return m;
jwe@7427
   191
}
jwe@7427
   192
jwe@7445
   193
static Matrix
bpabbott@8599
   194
default_axes_tick (void)
bpabbott@8599
   195
{
bpabbott@8599
   196
  Matrix m (1, 6, 0.0);
bpabbott@8599
   197
  m(0) = 0.0;
bpabbott@8599
   198
  m(1) = 0.2;
bpabbott@8599
   199
  m(2) = 0.4;
bpabbott@8599
   200
  m(3) = 0.6;
bpabbott@8599
   201
  m(4) = 0.8;
bpabbott@8599
   202
  m(5) = 1.0;
bpabbott@8599
   203
  return m;
bpabbott@8599
   204
}
bpabbott@8599
   205
bpabbott@8599
   206
static Matrix
bpabbott@8740
   207
default_axes_ticklength (void)
bpabbott@8740
   208
{
bpabbott@8740
   209
  Matrix m (1, 2, 0.01);
bpabbott@8740
   210
  m(1) = 0.025;
bpabbott@8740
   211
  return m;
bpabbott@8740
   212
}
bpabbott@8740
   213
bpabbott@8740
   214
static Matrix
jwe@7445
   215
default_figure_position (void)
jwe@7445
   216
{
jwe@7445
   217
  Matrix m (1, 4, 0.0);
jwe@7445
   218
  m(0) = 300;
jwe@7445
   219
  m(1) = 200;
jwe@7445
   220
  m(2) = 560;
jwe@7445
   221
  m(3) = 420;
jwe@7445
   222
  return m;
jwe@7445
   223
}
jwe@7445
   224
jwe@7427
   225
static Matrix
bpabbott@8599
   226
default_figure_papersize (void)
bpabbott@8599
   227
{
bpabbott@8599
   228
  Matrix m (1, 2, 0.0);
bpabbott@8599
   229
  m(0) = 8.5;
bpabbott@8961
   230
  m(1) = 11.0;
bpabbott@8599
   231
  return m;
bpabbott@8599
   232
}
bpabbott@8599
   233
bpabbott@8599
   234
static Matrix
bpabbott@8599
   235
default_figure_paperposition (void)
bpabbott@8599
   236
{
bpabbott@8599
   237
  Matrix m (1, 4, 0.0);
bpabbott@8599
   238
  m(0) = 0.25;
bpabbott@8599
   239
  m(1) = 2.50;
bpabbott@8599
   240
  m(2) = 8.00;
bpabbott@8599
   241
  m(3) = 6.00;
bpabbott@8599
   242
  return m;
bpabbott@8599
   243
}
bpabbott@8599
   244
bpabbott@8599
   245
static Matrix
jwe@7427
   246
convert_position (const Matrix& pos, const caseless_str& from_units,
jwe@7427
   247
		  const caseless_str& to_units,
michael@9238
   248
		  const Matrix& parent_dim = Matrix (1, 2, 0.0))
jwe@7427
   249
{
jwe@7427
   250
  Matrix retval (1, 4);
jwe@7427
   251
  double res = 0;
jwe@7427
   252
jwe@7427
   253
  if (from_units.compare ("pixels"))
jwe@7427
   254
    retval = pos;
jwe@7427
   255
  else if (from_units.compare ("normalized"))
jwe@7427
   256
    {
jwe@7427
   257
      retval(0) = pos(0) * parent_dim(0) + 1;
jwe@7427
   258
      retval(1) = pos(1) * parent_dim(1) + 1;
jwe@7427
   259
      retval(2) = pos(2) * parent_dim(0);
jwe@7427
   260
      retval(3) = pos(3) * parent_dim(1);
jwe@7427
   261
    }
jwe@7427
   262
  else if (from_units.compare ("characters"))
jwe@7427
   263
    {
michael@9238
   264
      if (res <= 0)
michael@9238
   265
	res = xget (0, "screenpixelsperinch").double_value ();
bpabbott@8599
   266
bpabbott@8599
   267
      double f = 0.0;
bpabbott@8599
   268
bpabbott@8599
   269
      // FIXME -- this assumes the system font is Helvetica 10pt 
bpabbott@8599
   270
      //          (for which "x" requires 6x12 pixels at 74.951 pixels/inch)
bpabbott@8599
   271
      f = 12.0 * res / 74.951;
bpabbott@8599
   272
bpabbott@8599
   273
      if (f > 0)
bpabbott@8599
   274
	{
bpabbott@8599
   275
	  retval(0) = 0.5 * pos(0) * f;
bpabbott@8599
   276
	  retval(1) = pos(1) * f;
bpabbott@8599
   277
	  retval(2) = 0.5 * pos(2) * f;
bpabbott@8599
   278
	  retval(3) = pos(3) * f;
bpabbott@8599
   279
	}
jwe@7427
   280
    }
jwe@7427
   281
  else
jwe@7427
   282
    {
michael@9238
   283
      if (res <= 0)
michael@9238
   284
	res = xget (0, "screenpixelsperinch").double_value ();
jwe@7427
   285
jwe@7427
   286
      double f = 0.0;
jwe@7427
   287
jwe@7427
   288
      if (from_units.compare ("points"))
jwe@7427
   289
	f = res / 72.0;
jwe@7427
   290
      else if (from_units.compare ("inches"))
jwe@7427
   291
	f = res;
jwe@7427
   292
      else if (from_units.compare ("centimeters"))
jwe@7427
   293
	f = res / 2.54;
jwe@7427
   294
jwe@7427
   295
      if (f > 0)
jwe@7427
   296
	{
jwe@7427
   297
	  retval(0) = pos(0) * f + 1;
jwe@7427
   298
	  retval(1) = pos(1) * f + 1;
jwe@7427
   299
	  retval(2) = pos(2) * f;
jwe@7427
   300
	  retval(3) = pos(3) * f;
jwe@7427
   301
	}
jwe@7427
   302
    }
jwe@7427
   303
jwe@7427
   304
  if (! to_units.compare ("pixels"))
jwe@7427
   305
    {
jwe@7427
   306
      if (to_units.compare ("normalized"))
jwe@7427
   307
	{
jwe@7427
   308
	  retval(0) = (retval(0) - 1) / parent_dim(0);
jwe@7427
   309
	  retval(1) = (retval(1) - 1) / parent_dim(1);
jwe@7427
   310
	  retval(2) /= parent_dim(0);
jwe@7427
   311
	  retval(3) /= parent_dim(1);
jwe@7427
   312
	}
jwe@7427
   313
      else if (to_units.compare ("characters"))
jwe@7427
   314
	{
michael@9238
   315
	  if (res <= 0)
michael@9238
   316
	    res = xget (0, "screenpixelsperinch").double_value ();
bpabbott@8599
   317
bpabbott@8599
   318
	  double f = 0.0;
bpabbott@8599
   319
bpabbott@8599
   320
	  f = 12.0 * res / 74.951;
bpabbott@8599
   321
bpabbott@8599
   322
	  if (f > 0)
bpabbott@8599
   323
	    {
bpabbott@8599
   324
	      retval(0) = 2 * retval(0) / f;
bpabbott@8599
   325
	      retval(1) = retval(1) / f;
bpabbott@8599
   326
	      retval(2) = 2 * retval(2) / f;
bpabbott@8599
   327
	      retval(3) = retval(3) / f;
bpabbott@8599
   328
	    }
jwe@7427
   329
	}
jwe@7427
   330
      else
jwe@7427
   331
	{
jwe@7427
   332
	  if (res <= 0)
michael@9238
   333
	    res = xget (0, "screenpixelsperinch").double_value ();
jwe@7427
   334
jwe@7427
   335
	  double f = 0.0;
jwe@7427
   336
jwe@7427
   337
	  if (to_units.compare ("points"))
jwe@7427
   338
	    f = res / 72.0;
jwe@7427
   339
	  else if (to_units.compare ("inches"))
jwe@7427
   340
	    f = res;
jwe@7427
   341
	  else if (to_units.compare ("centimeters"))
jwe@7427
   342
	    f = res / 2.54;
jwe@7427
   343
jwe@7427
   344
	  if (f > 0)
jwe@7427
   345
	    {
jwe@7427
   346
	      retval(0) = (retval(0) - 1) / f;
jwe@7427
   347
	      retval(1) = (retval(1) - 1) / f;
jwe@7427
   348
	      retval(2) /= f;
jwe@7427
   349
	      retval(3) /= f;
jwe@7427
   350
	    }
jwe@7427
   351
	}
jwe@7427
   352
    }
jwe@7427
   353
jwe@7427
   354
  return retval;
jwe@7427
   355
}
jwe@7427
   356
michael@7829
   357
static graphics_object
jwe@7878
   358
xget_ancestor (const graphics_object& go_arg, const std::string& type)
michael@7829
   359
{
jwe@7878
   360
  graphics_object go = go_arg;
jwe@7878
   361
michael@7829
   362
  do
michael@7829
   363
    {
michael@7829
   364
      if (go.valid_object ())
michael@7829
   365
	{
michael@7829
   366
	  if (go.isa (type))
michael@7829
   367
	    return go;
michael@7829
   368
	  else
michael@7829
   369
	    go = gh_manager::get_object (go.get_parent ());
michael@7829
   370
	}
michael@7829
   371
      else
michael@7829
   372
	return graphics_object ();
jwe@7869
   373
    }
jwe@7869
   374
 while (true);
michael@7829
   375
}
michael@7829
   376
michael@7829
   377
static octave_value
michael@7829
   378
convert_cdata (const base_properties& props, const octave_value& cdata,
michael@7829
   379
	       bool is_scaled, int cdim)
michael@7829
   380
{
michael@7829
   381
  dim_vector dv (cdata.dims ());
michael@7829
   382
michael@7829
   383
  if (dv.length () == cdim && dv(cdim-1) == 3)
michael@7829
   384
    return cdata;
michael@7829
   385
michael@7829
   386
  Matrix cmap (1, 3, 0.0);
michael@7829
   387
  Matrix clim (1, 2, 0.0);
michael@7829
   388
michael@7829
   389
  graphics_object go = gh_manager::get_object (props.get___myhandle__ ());
michael@7829
   390
  graphics_object fig = xget_ancestor (go, "figure");
michael@7829
   391
michael@7829
   392
  if (fig.valid_object ())
michael@7829
   393
    {
michael@7829
   394
      Matrix _cmap = fig.get (caseless_str ("colormap")).matrix_value ();
michael@7829
   395
michael@7829
   396
      if (! error_state)
michael@7829
   397
	cmap = _cmap;
michael@7829
   398
    }
michael@7829
   399
michael@7829
   400
  if (is_scaled)
michael@7829
   401
    {
michael@7829
   402
      graphics_object ax = xget_ancestor (go, "axes");
michael@7829
   403
michael@7829
   404
      if (ax.valid_object ())
michael@7829
   405
	{
michael@7829
   406
	  Matrix _clim = ax.get (caseless_str ("clim")).matrix_value ();
michael@7829
   407
michael@7829
   408
	  if (! error_state)
michael@7829
   409
	    clim = _clim;
michael@7829
   410
	}
michael@7829
   411
    }
michael@7829
   412
michael@7829
   413
  dv.resize (cdim);
michael@7829
   414
  dv(cdim-1) = 3;
michael@7829
   415
michael@7829
   416
  NDArray a (dv);
michael@7829
   417
dbateman@8075
   418
  octave_idx_type lda = a.numel () / static_cast<octave_idx_type> (3);
dbateman@8075
   419
  octave_idx_type nc = cmap.rows ();
michael@7829
   420
michael@7829
   421
  double *av = a.fortran_vec ();
michael@7829
   422
  const double *cmapv = cmap.data ();
michael@7829
   423
  const double *cv = 0;
michael@7829
   424
  const octave_uint8 *icv = 0;
michael@7829
   425
michael@7829
   426
  if (cdata.is_integer_type ())
michael@7829
   427
    icv = cdata.uint8_array_value ().data ();
michael@7829
   428
  else
michael@7829
   429
    cv = cdata.array_value ().data ();
michael@7829
   430
dbateman@8075
   431
  for (octave_idx_type i = 0; i < lda; i++)
michael@7829
   432
    {
michael@7829
   433
      double x = (cv ? cv[i] : double (icv[i]));
michael@7829
   434
michael@7829
   435
      if (is_scaled)
michael@7829
   436
	x = xround ((nc - 1) * (x - clim(0)) / (clim(1) - clim(0)));
michael@7829
   437
      else
michael@7829
   438
	x = xround (x - 1);
michael@7829
   439
michael@7829
   440
      if (x < 0)
michael@7829
   441
	x = 0;
michael@7829
   442
      else if (x >= nc)
michael@7829
   443
	x = (nc - 1);
michael@7829
   444
dbateman@8075
   445
      octave_idx_type idx = static_cast<octave_idx_type> (x);
michael@7829
   446
michael@7829
   447
      av[i]       = cmapv[idx];
michael@7829
   448
      av[i+lda]   = cmapv[idx+nc];
michael@7829
   449
      av[i+2*lda] = cmapv[idx+2*nc];
michael@7829
   450
    }
michael@7829
   451
michael@7829
   452
  return octave_value (a);
michael@7829
   453
}
michael@7829
   454
michael@7836
   455
template<class T>
michael@7836
   456
static void
michael@7836
   457
get_array_limits (const Array<T>& m, double& emin, double& emax,
michael@7836
   458
		  double& eminp)
michael@7836
   459
{
michael@7836
   460
  const T *data = m.data ();
dbateman@8075
   461
  octave_idx_type n = m.numel ();
dbateman@8075
   462
dbateman@8075
   463
  for (octave_idx_type i = 0; i < n; i++)
michael@7836
   464
    {
michael@7836
   465
      double e = double (data[i]);
michael@7836
   466
michael@7836
   467
      if (! (xisinf (e) || xisnan (e)))
michael@7836
   468
	{
michael@7836
   469
	  if (e < emin)
michael@7836
   470
	    emin = e;
michael@7836
   471
michael@7836
   472
	  if (e > emax)
michael@7836
   473
	    emax = e;
michael@7836
   474
jwe@9384
   475
	  if (e > 0 && e < eminp)
michael@7836
   476
	    eminp = e;
michael@7836
   477
	}
michael@7836
   478
    }
michael@7836
   479
}
michael@7836
   480
michael@7864
   481
static bool
michael@7864
   482
lookup_object_name (const caseless_str& name, caseless_str& go_name,
michael@7864
   483
		    caseless_str& rest)
michael@7864
   484
{
michael@7864
   485
  int len = name.length ();
michael@7864
   486
  int offset = 0;
michael@7864
   487
  bool result = false;
michael@7864
   488
michael@7864
   489
  if (len >= 4)
michael@7864
   490
    {
michael@7864
   491
      caseless_str pfx = name.substr (0, 4);
michael@7864
   492
michael@7864
   493
      if (pfx.compare ("axes") || pfx.compare ("line")
michael@7864
   494
	  || pfx.compare ("text"))
michael@7864
   495
	offset = 4;
michael@7864
   496
      else if (len >= 5)
michael@7864
   497
	{
michael@7864
   498
	  pfx = name.substr (0, 5);
michael@7864
   499
michael@7864
   500
	  if (pfx.compare ("image") || pfx.compare ("patch"))
michael@7864
   501
	    offset = 5;
michael@7864
   502
	  else if (len >= 6)
michael@7864
   503
	    {
michael@7864
   504
	      pfx = name.substr (0, 6);
michael@7864
   505
michael@7864
   506
	      if (pfx.compare ("figure"))
michael@7864
   507
		offset = 6;
michael@7864
   508
	      else if (len >= 7)
michael@7864
   509
		{
michael@7864
   510
		  pfx = name.substr (0, 7);
michael@7864
   511
michael@7865
   512
		  if (pfx.compare ("surface") || pfx.compare ("hggroup"))
michael@7864
   513
		    offset = 7;
michael@7864
   514
		}
michael@7864
   515
	    }
michael@7864
   516
	}
michael@7864
   517
michael@7864
   518
      if (offset > 0)
michael@7864
   519
	{
michael@7864
   520
	  go_name = pfx;
michael@7864
   521
	  rest = name.substr (offset);
michael@7864
   522
	  result = true;
michael@7864
   523
	}
michael@7864
   524
    }
michael@7864
   525
michael@7864
   526
  return result;
michael@7864
   527
}
michael@7864
   528
michael@7864
   529
static base_graphics_object*
michael@7864
   530
make_graphics_object_from_type (const caseless_str& type,
michael@7864
   531
				const graphics_handle& h = graphics_handle (),
michael@7864
   532
				const graphics_handle& p = graphics_handle ())
michael@7864
   533
{
michael@7864
   534
  base_graphics_object *go = 0;
michael@7864
   535
michael@7864
   536
  if (type.compare ("figure"))
michael@7864
   537
    go = new figure (h, p);
michael@7864
   538
  else if (type.compare ("axes"))
michael@7864
   539
    go = new axes (h, p);
michael@7864
   540
  else if (type.compare ("line"))
michael@7864
   541
    go = new line (h, p);
michael@7864
   542
  else if (type.compare ("text"))
michael@7864
   543
    go = new text (h, p);
michael@7864
   544
  else if (type.compare ("image"))
michael@7864
   545
    go = new image (h, p);
michael@7864
   546
  else if (type.compare ("patch"))
michael@7864
   547
    go = new patch (h, p);
michael@7864
   548
  else if (type.compare ("surface"))
michael@7864
   549
    go = new surface (h, p);
michael@7865
   550
  else if (type.compare ("hggroup"))
michael@7865
   551
    go = new hggroup (h, p);
michael@7864
   552
michael@7864
   553
  return go;
michael@7864
   554
}
michael@7864
   555
jwe@6406
   556
// ---------------------------------------------------------------------
jwe@6406
   557
Michael@8063
   558
bool
jwe@8058
   559
base_property::set (const octave_value& v, bool do_run )
jwe@8058
   560
{
Michael@8063
   561
  if (do_set (v))
jwe@8058
   562
    {
Michael@8063
   563
Michael@8063
   564
      // notify backend
Michael@8063
   565
      if (id >= 0)
jwe@8059
   566
	{
Michael@8063
   567
	  graphics_object go = gh_manager::get_object (parent);
Michael@8063
   568
	  if (go)
Michael@8063
   569
	    {
Michael@8063
   570
	      graphics_backend backend = go.get_backend();
Michael@8063
   571
	      if (backend)
Michael@8063
   572
		backend.property_changed (go, id);
Michael@8063
   573
	    }
jwe@8059
   574
	}
Michael@8063
   575
Michael@8063
   576
      // run listeners
Michael@8063
   577
      if (do_run && ! error_state)
Michael@8063
   578
	run_listeners (POSTSET);
Michael@8063
   579
Michael@8063
   580
      return true;
jwe@8058
   581
    }
Michael@8063
   582
Michael@8063
   583
  return false;
jwe@8058
   584
}
jwe@8058
   585
jwe@8058
   586
jwe@8058
   587
void
michael@7849
   588
base_property::run_listeners (listener_mode mode)
michael@7849
   589
{
michael@7849
   590
  const octave_value_list& l = listeners[mode];
michael@7849
   591
michael@7849
   592
  for (int i = 0; i < l.length (); i++)
michael@7849
   593
    {
jwe@7936
   594
      gh_manager::execute_callback (parent, l(i), octave_value ());
michael@7849
   595
michael@7849
   596
      if (error_state)
michael@7849
   597
	break;
michael@7849
   598
    }
michael@7849
   599
}
michael@7849
   600
jwe@6705
   601
radio_values::radio_values (const std::string& opt_string)
jwe@6406
   602
{
jwe@6705
   603
  size_t beg = 0;
jwe@6705
   604
  size_t len = opt_string.length ();
jwe@6705
   605
  bool done = len == 0;
jwe@6681
   606
jwe@6705
   607
  while (! done)
jwe@6705
   608
    {
jwe@6705
   609
      size_t end = opt_string.find ('|', beg);
jwe@6681
   610
jwe@6705
   611
      if (end == std::string::npos)
jwe@6705
   612
	{
jwe@6705
   613
	  end = len;
jwe@6705
   614
	  done = true;
jwe@6705
   615
	}
jwe@6681
   616
jwe@6705
   617
      std::string t = opt_string.substr (beg, end-beg);
jwe@6681
   618
jwe@6705
   619
      // Might want more error checking here...
jwe@6705
   620
      if (t[0] == '{')
jwe@6705
   621
	{
jwe@6705
   622
	  t = t.substr (1, t.length () - 2);
jwe@6681
   623
	  default_val = t;
jwe@6705
   624
	}
jwe@6705
   625
      else if (beg == 0) // ensure default value
jwe@6705
   626
	default_val = t;
jwe@6681
   627
jwe@6705
   628
      possible_vals.insert (t);
jwe@6681
   629
jwe@6705
   630
      beg = end + 1;
jwe@6705
   631
    }
jwe@6705
   632
}
jwe@6681
   633
jwe@6705
   634
bool
jwe@6761
   635
color_values::str2rgb (std::string str)
jwe@6705
   636
{
jwe@6705
   637
  double tmp_rgb[3] = {0, 0, 0};
jwe@6705
   638
  bool retval = true;
jwe@6761
   639
  unsigned int len = str.length();
jwe@6681
   640
dbateman@6925
   641
  std::transform (str.begin (), str.end (), str.begin (), tolower);
dbateman@6925
   642
jwe@6761
   643
  if (str.compare(0, len, "blue", 0, len) == 0)
jwe@6761
   644
    tmp_rgb[2] = 1;
jwe@7869
   645
  else if (str.compare(0, len, "black", 0, len) == 0
jwe@7869
   646
	   || str.compare(0, len, "k", 0, len) == 0)
jwe@6761
   647
    tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 0;
jwe@6761
   648
  else if (str.compare(0, len, "red", 0, len) == 0)
jwe@6761
   649
    tmp_rgb[0] = 1;
jwe@6761
   650
  else if (str.compare(0, len, "green", 0, len) == 0)
jwe@6761
   651
    tmp_rgb[1] = 1;
jwe@6761
   652
  else if (str.compare(0, len, "yellow", 0, len) == 0)
jwe@6761
   653
    tmp_rgb[0] = tmp_rgb[1] = 1;
jwe@6761
   654
  else if (str.compare(0, len, "magenta", 0, len) == 0)
jwe@6761
   655
    tmp_rgb[0] = tmp_rgb[2] = 1;
jwe@6761
   656
  else if (str.compare(0, len, "cyan", 0, len) == 0)
jwe@6761
   657
    tmp_rgb[1] = tmp_rgb[2] = 1;
jwe@7869
   658
  else if (str.compare(0, len, "white", 0, len) == 0
jwe@7869
   659
	   || str.compare(0, len, "w", 0, len) == 0)
jwe@6761
   660
    tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 1;
jwe@6761
   661
  else	
jwe@6761
   662
    retval = false;
jwe@6681
   663
jwe@6705
   664
  if (retval)
jwe@6705
   665
    {
jwe@6705
   666
      for (int i = 0; i < 3; i++)
jwe@7363
   667
	xrgb(i) = tmp_rgb[i];
jwe@6705
   668
    }
jwe@6705
   669
jwe@6705
   670
  return retval;
jwe@6705
   671
}
jwe@6705
   672
Michael@8063
   673
bool
michael@7849
   674
color_property::do_set (const octave_value& val)
jwe@6790
   675
{
jwe@6790
   676
  if (val.is_string ())
jwe@6790
   677
    {
jwe@6790
   678
      std::string s = val.string_value ();
jwe@6790
   679
jwe@6790
   680
      if (! s.empty ())
jwe@6790
   681
	{
jwe@6898
   682
	  if (radio_val.contains (s))
jwe@6790
   683
	    {
Michael@8063
   684
	      if (current_type != radio_t || current_val != s)
Michael@8063
   685
		{
Michael@8063
   686
		  current_val = s;
Michael@8063
   687
		  current_type = radio_t;
Michael@8063
   688
		  return true;
Michael@8063
   689
		}
jwe@6790
   690
	    }
jwe@6790
   691
          else
jwe@6790
   692
	    {
jwe@6790
   693
	      color_values col (s);
jwe@6790
   694
	      if (! error_state)
jwe@6790
   695
		{
Michael@8063
   696
		  if (current_type != color_t || col != color_val)
Michael@8063
   697
		    {
Michael@8063
   698
		      color_val = col;
Michael@8063
   699
		      current_type = color_t;
Michael@8063
   700
		      return true;
Michael@8063
   701
		    }
jwe@6790
   702
		}
jwe@6790
   703
	      else
jwe@7363
   704
		error ("invalid value for color property \"%s\" (value = %s)",
Michael@8063
   705
		       get_name ().c_str (), s.c_str ());
jwe@6790
   706
	    }	
jwe@6790
   707
	}
jwe@6790
   708
      else
jwe@7363
   709
	error ("invalid value for color property \"%s\"",
jwe@7363
   710
           get_name ().c_str ());
jwe@6790
   711
    }
highegg@9313
   712
  else if (val.is_numeric_type ())
jwe@6790
   713
    {
jwe@6790
   714
      Matrix m = val.matrix_value ();
jwe@6790
   715
jwe@6790
   716
      if (m.numel () == 3)
jwe@6790
   717
	{
jwe@6790
   718
	  color_values col (m (0), m (1), m(2));
jwe@6790
   719
	  if (! error_state)
jwe@6790
   720
	    {
Michael@8063
   721
	      if (current_type != color_t || col != color_val)
Michael@8063
   722
		{
Michael@8063
   723
		  color_val = col;
Michael@8063
   724
		  current_type = color_t;
Michael@8063
   725
		  return true;
Michael@8063
   726
		}
jwe@6790
   727
	    }
jwe@6790
   728
	}
jwe@6790
   729
      else
jwe@7363
   730
	error ("invalid value for color property \"%s\"",
jwe@7363
   731
           get_name ().c_str ());
jwe@6790
   732
    }
jwe@6790
   733
  else 
jwe@7363
   734
    error ("invalid value for color property \"%s\"",
jwe@7363
   735
           get_name ().c_str ());
Michael@8063
   736
Michael@8063
   737
  return false;
jwe@6790
   738
}
jwe@6790
   739
Michael@8063
   740
bool
michael@7849
   741
double_radio_property::do_set (const octave_value& val)
michael@7844
   742
{
michael@7844
   743
  if (val.is_string ())
michael@7844
   744
    {
michael@7844
   745
      std::string s = val.string_value ();
michael@7844
   746
michael@7844
   747
      if (! s.empty () && radio_val.contains (s))
michael@7844
   748
	{
Michael@8063
   749
	  if (current_type != radio_t || s != current_val)
Michael@8063
   750
	    {
Michael@8063
   751
	      current_val = s;
Michael@8063
   752
	      current_type = radio_t;
Michael@8063
   753
	      return true;
Michael@8063
   754
	    }
michael@7844
   755
	}
michael@7844
   756
      else
michael@7844
   757
	error ("invalid value for double_radio property \"%s\"",
michael@7844
   758
	       get_name ().c_str ());
michael@7844
   759
    }
michael@7844
   760
  else if (val.is_scalar_type () && val.is_real_type ())
michael@7844
   761
    {
Michael@8063
   762
      double new_dval = val.double_value ();
Michael@8063
   763
Michael@8063
   764
      if (current_type != double_t || new_dval != dval)
Michael@8063
   765
	{
Michael@8063
   766
	  dval = new_dval;
Michael@8063
   767
	  current_type = double_t;
Michael@8063
   768
	  return true;
Michael@8063
   769
	}
michael@7844
   770
    }
michael@7844
   771
  else 
michael@7844
   772
    error ("invalid value for double_radio property \"%s\"",
michael@7844
   773
	   get_name ().c_str ());
Michael@8063
   774
Michael@8063
   775
  return false;
michael@7844
   776
}
michael@7844
   777
jwe@7363
   778
bool
jwe@7363
   779
array_property::validate (const octave_value& v)
jwe@7363
   780
{
jwe@7364
   781
  bool xok = false;
jwe@7363
   782
jwe@8333
   783
  // FIXME -- should we always support []?
jwe@9181
   784
  if (v.is_empty () && v.is_numeric_type ())
jwe@7363
   785
    return true;
jwe@7363
   786
jwe@7363
   787
  // check value type
jwe@7363
   788
  if (type_constraints.size () > 0)
jwe@7363
   789
    {
jwe@7363
   790
      for (std::list<std::string>::const_iterator it = type_constraints.begin ();
jwe@7364
   791
           ! xok && it != type_constraints.end (); ++it)
michael@7836
   792
        if ((*it) == v.class_name ())
jwe@7364
   793
          xok = true;
jwe@7363
   794
    }
jwe@7363
   795
  else
jwe@9181
   796
    xok = v.is_numeric_type ();
jwe@7363
   797
jwe@7364
   798
  if (xok)
jwe@7363
   799
    {
jwe@7363
   800
      dim_vector vdims = v.dims ();
jwe@7363
   801
      int vlen = vdims.length ();
jwe@7363
   802
jwe@7364
   803
      xok = false;
jwe@7363
   804
jwe@7363
   805
      // check value size
jwe@7363
   806
      if (size_constraints.size () > 0)
jwe@7363
   807
        for (std::list<dim_vector>::const_iterator it = size_constraints.begin ();
jwe@7364
   808
             ! xok && it != size_constraints.end (); ++it)
jwe@7363
   809
          {
jwe@7363
   810
            dim_vector itdims = (*it);
jwe@7363
   811
jwe@7363
   812
            if (itdims.length () == vlen)
jwe@7363
   813
              {
jwe@7364
   814
                xok = true;
jwe@7363
   815
jwe@7364
   816
                for (int i = 0; xok && i < vlen; i++)
jwe@7363
   817
                  if (itdims(i) >= 0 && itdims(i) != vdims(i))
jwe@7364
   818
                    xok = false;
jwe@7363
   819
              }
jwe@7363
   820
          }
jwe@7363
   821
      else
jwe@7363
   822
        return true;
jwe@7363
   823
    }
jwe@7363
   824
jwe@7364
   825
  return xok;
jwe@7363
   826
}
jwe@7363
   827
Michael@8063
   828
bool
Michael@8063
   829
array_property::is_equal (const octave_value& v) const
Michael@8063
   830
{
Michael@8063
   831
  if (data.type_name () == v.type_name ())
Michael@8063
   832
    {
Michael@8063
   833
      if (data.dims () == v.dims ())
Michael@8063
   834
	{
dbateman@8075
   835
dbateman@8075
   836
#define CHECK_ARRAY_EQUAL(T,F,A) \
Michael@8063
   837
	    { \
dbateman@8075
   838
	      if (data.numel () == 1) \
dbateman@8075
   839
		return data.F ## scalar_value () == \
dbateman@8075
   840
		  v.F ## scalar_value (); \
dbateman@8075
   841
	      else  \
dbateman@8075
   842
		{ \
dbateman@8075
   843
                  /* Keep copy of array_value to allow sparse/bool arrays */ \
dbateman@8075
   844
		  /* that are converted, to not be deallocated early */ \
dbateman@8075
   845
		  const A m1 = data.F ## array_value (); \
dbateman@8075
   846
		  const T* d1 = m1.data (); \
dbateman@8075
   847
		  const A m2 = v.F ## array_value (); \
dbateman@8075
   848
		  const T* d2 = m2.data ();\
dbateman@8075
   849
		  \
dbateman@8075
   850
		  bool flag = true; \
dbateman@8075
   851
		  \
dbateman@8075
   852
		  for (int i = 0; flag && i < data.numel (); i++) \
dbateman@8075
   853
		    if (d1[i] != d2[i]) \
dbateman@8075
   854
		      flag = false; \
dbateman@8075
   855
		  \
dbateman@8075
   856
		  return flag; \
dbateman@8075
   857
		} \
Michael@8063
   858
	    }
Michael@8063
   859
dbateman@8075
   860
	  if (data.is_double_type() || data.is_bool_type ())
dbateman@8075
   861
	    CHECK_ARRAY_EQUAL (double, , NDArray)
Michael@8063
   862
	  else if (data.is_single_type ())
dbateman@8075
   863
	    CHECK_ARRAY_EQUAL (float, float_, FloatNDArray)
Michael@8063
   864
	  else if (data.is_int8_type ())
dbateman@8075
   865
	    CHECK_ARRAY_EQUAL (octave_int8, int8_, int8NDArray)
Michael@8063
   866
	  else if (data.is_int16_type ())
dbateman@8075
   867
	    CHECK_ARRAY_EQUAL (octave_int16, int16_, int16NDArray)
Michael@8063
   868
	  else if (data.is_int32_type ())
dbateman@8075
   869
	    CHECK_ARRAY_EQUAL (octave_int32, int32_, int32NDArray)
Michael@8063
   870
	  else if (data.is_int64_type ())
dbateman@8075
   871
	    CHECK_ARRAY_EQUAL (octave_int64, int64_, int64NDArray)
Michael@8063
   872
	  else if (data.is_uint8_type ())
dbateman@8075
   873
	    CHECK_ARRAY_EQUAL (octave_uint8, uint8_, uint8NDArray)
Michael@8063
   874
	  else if (data.is_uint16_type ())
dbateman@8075
   875
	    CHECK_ARRAY_EQUAL (octave_uint16, uint16_, uint16NDArray)
Michael@8063
   876
	  else if (data.is_uint32_type ())
dbateman@8075
   877
	    CHECK_ARRAY_EQUAL (octave_uint32, uint32_, uint32NDArray)
Michael@8063
   878
	  else if (data.is_uint64_type ())
dbateman@8075
   879
	    CHECK_ARRAY_EQUAL (octave_uint64, uint64_, uint64NDArray)
Michael@8063
   880
	}
Michael@8063
   881
    }
Michael@8063
   882
Michael@8063
   883
  return false;
Michael@8063
   884
}
Michael@8063
   885
jwe@7363
   886
void
michael@7836
   887
array_property::get_data_limits (void)
michael@7836
   888
{
michael@7836
   889
  xmin = xminp = octave_Inf;
michael@7836
   890
  xmax = -octave_Inf;
michael@7836
   891
michael@7836
   892
  if (! data.is_empty ())
michael@7836
   893
    {
michael@7836
   894
      if (data.is_integer_type ())
michael@7836
   895
	{
michael@7836
   896
	  if (data.is_int8_type ())
michael@7836
   897
	    get_array_limits (data.int8_array_value (), xmin, xmax, xminp);
michael@7836
   898
	  else if (data.is_uint8_type ())
michael@7836
   899
	    get_array_limits (data.uint8_array_value (), xmin, xmax, xminp);
michael@7836
   900
	  else if (data.is_int16_type ())
michael@7836
   901
	    get_array_limits (data.int16_array_value (), xmin, xmax, xminp);
michael@7836
   902
	  else if (data.is_uint16_type ())
michael@7836
   903
	    get_array_limits (data.uint16_array_value (), xmin, xmax, xminp);
michael@7836
   904
	  else if (data.is_int32_type ())
michael@7836
   905
	    get_array_limits (data.int32_array_value (), xmin, xmax, xminp);
michael@7836
   906
	  else if (data.is_uint32_type ())
michael@7836
   907
	    get_array_limits (data.uint32_array_value (), xmin, xmax, xminp);
michael@7836
   908
	  else if (data.is_int64_type ())
michael@7836
   909
	    get_array_limits (data.int64_array_value (), xmin, xmax, xminp);
michael@7836
   910
	  else if (data.is_uint64_type ())
michael@7836
   911
	    get_array_limits (data.uint64_array_value (), xmin, xmax, xminp);
michael@7836
   912
	}
michael@7836
   913
      else
michael@7836
   914
	get_array_limits (data.array_value (), xmin, xmax, xminp);
michael@7836
   915
    }
michael@7836
   916
}
michael@7836
   917
Michael@8063
   918
bool
michael@7849
   919
handle_property::do_set (const octave_value& v)
jwe@7363
   920
{
jwe@7363
   921
  double dv = v.double_value ();
jwe@7363
   922
jwe@7363
   923
  if (! error_state)
jwe@7363
   924
    {
jwe@7363
   925
      graphics_handle gh = gh_manager::lookup (dv);
jwe@7363
   926
jwe@7363
   927
      if (xisnan (gh.value ()) || gh.ok ())
Michael@8063
   928
	{
Michael@8063
   929
	  if (current_val != gh)
Michael@8063
   930
	    {
Michael@8063
   931
	      current_val = gh;
Michael@8063
   932
	      return true;
Michael@8063
   933
	    }
Michael@8063
   934
	}
jwe@7363
   935
      else
jwe@7363
   936
        error ("set: invalid graphics handle (= %g) for property \"%s\"",
jwe@7869
   937
	       dv, get_name ().c_str ());
jwe@7363
   938
    }
jwe@7363
   939
  else
jwe@7363
   940
    error ("set: invalid graphics handle for property \"%s\"",
jwe@7869
   941
	   get_name ().c_str ());
Michael@8063
   942
Michael@8063
   943
  return false;
jwe@7363
   944
}
jwe@7363
   945
jwe@7363
   946
bool
jwe@7367
   947
callback_property::validate (const octave_value& v) const
jwe@7363
   948
{
jwe@7367
   949
  // case 1: function handle
jwe@7367
   950
  // case 2: cell array with first element being a function handle
jwe@7367
   951
  // case 3: string corresponding to known function name
jwe@7367
   952
  // case 4: evaluatable string
jwe@7367
   953
  // case 5: empty matrix
jwe@7367
   954
jwe@7367
   955
  if (v.is_function_handle ())
jwe@7367
   956
    return true;
jwe@7367
   957
  else if (v.is_string ())
jwe@7367
   958
    // complete validation will be done at execution-time
jwe@7367
   959
    return true;
jwe@7367
   960
  else if (v.is_cell () && v.length () > 0
jwe@7367
   961
           && (v.rows() == 1 || v.columns () == 1)
jwe@7367
   962
           && v.cell_value ()(0).is_function_handle ())
jwe@7367
   963
    return true;
jwe@7367
   964
  else if (v.is_empty ())
jwe@7367
   965
    return true;
jwe@7367
   966
jwe@7367
   967
  return false;
jwe@7363
   968
}
jwe@7363
   969
jwe@7363
   970
void
jwe@7367
   971
callback_property::execute (const octave_value& data) const
jwe@7363
   972
{
jwe@7367
   973
  if (callback.is_defined () && ! callback.is_empty ())
jwe@7936
   974
    gh_manager::execute_callback (get_parent (), callback, data);
michael@7824
   975
}
michael@7824
   976
michael@7864
   977
// Used to cache dummy graphics objects from which dynamic
michael@7864
   978
// properties can be cloned.
michael@7864
   979
static std::map<caseless_str, graphics_object> dprop_obj_map;
michael@7864
   980
michael@7864
   981
property
michael@7864
   982
property::create (const std::string& name, const graphics_handle& h,
michael@7864
   983
		  const caseless_str& type, const octave_value_list& args)
michael@7864
   984
{
michael@7864
   985
  property retval;
michael@7864
   986
michael@7864
   987
  if (type.compare ("string"))
michael@7864
   988
    {
michael@7864
   989
      std::string val = (args.length () > 0 ? args(0).string_value () : "");
michael@7864
   990
michael@7864
   991
      if (! error_state)
michael@7864
   992
	retval = property (new string_property (name, h, val));
michael@7864
   993
    }
michael@7864
   994
  else if (type.compare ("any"))
michael@7864
   995
    {
michael@7864
   996
      octave_value val =
michael@7864
   997
	  (args.length () > 0 ? args(0) : octave_value (Matrix ()));
michael@7864
   998
michael@7864
   999
      retval = property (new any_property (name, h, val));
michael@7864
  1000
    }
michael@7864
  1001
  else if (type.compare ("radio"))
michael@7864
  1002
    {
michael@7864
  1003
      if (args.length () > 0)
michael@7864
  1004
	{
michael@7864
  1005
	  std::string vals = args(0).string_value ();
michael@7864
  1006
michael@7864
  1007
	  if (! error_state)
michael@7864
  1008
	    {
michael@7864
  1009
	      retval = property (new radio_property (name, h, vals));
michael@7864
  1010
michael@7864
  1011
	      if (args.length () > 1)
michael@7864
  1012
		retval.set (args(1));
michael@7864
  1013
	    }
michael@7864
  1014
	  else
michael@7864
  1015
	    error ("addproperty: invalid argument for radio property, expected a string value");
michael@7864
  1016
	}
michael@7864
  1017
      else
michael@7864
  1018
	error ("addproperty: missing possible values for radio property");
michael@7864
  1019
    }
michael@7864
  1020
  else if (type.compare ("double"))
michael@7864
  1021
    {
michael@7864
  1022
      double d = (args.length () > 0 ? args(0).double_value () : 0);
michael@7864
  1023
michael@7864
  1024
      if (! error_state)
michael@7864
  1025
	retval = property (new double_property (name, h, d));
michael@7864
  1026
    }
michael@7864
  1027
  else if (type.compare ("handle"))
michael@7864
  1028
    {
michael@7864
  1029
      double hh = (args.length () > 0 ? args(0).double_value () : octave_NaN);
michael@7864
  1030
michael@7864
  1031
      if (! error_state)
michael@7864
  1032
	{
michael@7864
  1033
	  graphics_handle gh (hh);
michael@7864
  1034
michael@7864
  1035
	  retval = property (new handle_property (name, h, gh));
michael@7864
  1036
	}
michael@7864
  1037
    }
michael@7864
  1038
  else if (type.compare ("boolean"))
michael@7864
  1039
    {
michael@7864
  1040
      retval = property (new bool_property (name, h, false));
michael@7864
  1041
michael@7864
  1042
      if (args.length () > 0)
michael@7864
  1043
	retval.set (args(0));
michael@7864
  1044
    }
michael@7864
  1045
  else if (type.compare ("data"))
michael@7864
  1046
    {
michael@7864
  1047
      retval = property (new array_property (name, h, Matrix ()));
michael@7864
  1048
michael@7864
  1049
      if (args.length () > 0)
michael@7864
  1050
	{
michael@7864
  1051
	  retval.set (args(0));
michael@7864
  1052
jwe@8333
  1053
	  // FIXME -- additional argument could define constraints,
jwe@8333
  1054
	  // but is this really useful?
michael@7864
  1055
	}
michael@7864
  1056
    }
michael@7864
  1057
  else if (type.compare ("color"))
michael@7864
  1058
    {
michael@7864
  1059
      color_values cv (0, 0, 0);
michael@7864
  1060
      radio_values rv;
michael@7864
  1061
michael@7864
  1062
      if (args.length () > 1)
michael@7864
  1063
	rv = radio_values (args(1).string_value ());
michael@7864
  1064
michael@7864
  1065
      if (! error_state)
michael@7864
  1066
	{
michael@7864
  1067
	  retval = property (new color_property (name, h, cv, rv));
michael@7864
  1068
michael@7864
  1069
	  if (! error_state)
michael@7864
  1070
	    {
jwe@7869
  1071
	      if (args.length () > 0 && ! args(0).is_empty ())
michael@7864
  1072
		retval.set (args(0));
michael@7864
  1073
	      else
michael@7864
  1074
		retval.set (rv.default_value ());
michael@7864
  1075
	    }
michael@7864
  1076
	}
michael@7864
  1077
    }
michael@7864
  1078
  else
michael@7864
  1079
    {
michael@7864
  1080
      caseless_str go_name, go_rest;
michael@7864
  1081
michael@7864
  1082
      if (lookup_object_name (type, go_name, go_rest))
michael@7864
  1083
	{
michael@7864
  1084
	  graphics_object go;
michael@7864
  1085
michael@7864
  1086
	  std::map<caseless_str, graphics_object>::const_iterator it =
michael@7864
  1087
	      dprop_obj_map.find (go_name);
michael@7864
  1088
michael@7864
  1089
	  if (it == dprop_obj_map.end ())
michael@7864
  1090
	    {
michael@7864
  1091
	      base_graphics_object *bgo =
michael@7864
  1092
		  make_graphics_object_from_type (go_name);
michael@7864
  1093
michael@7864
  1094
	      if (bgo)
michael@7864
  1095
		{
michael@7864
  1096
		  go = graphics_object (bgo);
michael@7864
  1097
michael@7864
  1098
		  dprop_obj_map[go_name] = go;
michael@7864
  1099
		}
michael@7864
  1100
	    }
michael@7864
  1101
	  else
michael@7864
  1102
	    go = it->second;
michael@7864
  1103
michael@7864
  1104
	  if (go.valid_object ())
michael@7864
  1105
	    {
michael@7864
  1106
	      property prop = go.get_properties ().get_property (go_rest);
michael@7864
  1107
michael@7864
  1108
	      if (! error_state)
michael@7864
  1109
		{
michael@7864
  1110
		  retval = prop.clone ();
michael@7864
  1111
michael@7864
  1112
		  retval.set_parent (h);
michael@7864
  1113
		  retval.set_name (name);
michael@7864
  1114
michael@7864
  1115
		  if (args.length () > 0)
michael@7864
  1116
		    retval.set (args(0));
michael@7864
  1117
		}
michael@7864
  1118
	    }
michael@7864
  1119
	  else
michael@7864
  1120
	    error ("addproperty: invalid object type (= %s)",
michael@7864
  1121
		   go_name.c_str ());
michael@7864
  1122
	}
michael@7864
  1123
      else
michael@7864
  1124
	error ("addproperty: unsupported type for dynamic property (= %s)",
michael@7864
  1125
	       type.c_str ());
michael@7864
  1126
    }
michael@7864
  1127
  
michael@7864
  1128
  return retval;
michael@7864
  1129
}
michael@7864
  1130
jwe@7363
  1131
// ---------------------------------------------------------------------
jwe@6681
  1132
jwe@6705
  1133
void
dbateman@7189
  1134
property_list::set (const caseless_str& name, const octave_value& val)
jwe@6705
  1135
{
jwe@6705
  1136
  size_t offset = 0;
jwe@6681
  1137
jwe@6705
  1138
  size_t len = name.length ();
jwe@6681
  1139
jwe@6705
  1140
  if (len > 4)
jwe@6705
  1141
    {
dbateman@7189
  1142
      caseless_str pfx = name.substr (0, 4);
jwe@6681
  1143
jwe@6705
  1144
      if (pfx.compare ("axes") || pfx.compare ("line")
jwe@6705
  1145
	  || pfx.compare ("text"))
jwe@6705
  1146
	offset = 4;
jwe@6705
  1147
      else if (len > 5)
jwe@6705
  1148
	{
jwe@6705
  1149
	  pfx = name.substr (0, 5);
jwe@6681
  1150
jwe@6807
  1151
	  if (pfx.compare ("image") || pfx.compare ("patch"))
jwe@6705
  1152
	    offset = 5;
jwe@6705
  1153
	  else if (len > 6)
jwe@6705
  1154
	    {
jwe@6705
  1155
	      pfx = name.substr (0, 6);
jwe@6705
  1156
jwe@6705
  1157
	      if (pfx.compare ("figure"))
jwe@6705
  1158
		offset = 6;
jwe@6705
  1159
	      else if (len > 7)
jwe@6705
  1160
		{
jwe@6705
  1161
		  pfx = name.substr (0, 7);
jwe@6705
  1162
michael@7865
  1163
		  if (pfx.compare ("surface") || pfx.compare ("hggroup"))
jwe@6705
  1164
		    offset = 7;
jwe@6705
  1165
		}
jwe@6705
  1166
	    }
jwe@6705
  1167
	}
jwe@6705
  1168
jwe@6705
  1169
      if (offset > 0)
jwe@6705
  1170
	{
jwe@6705
  1171
	  // FIXME -- should we validate property names and values here?
jwe@6705
  1172
jwe@6705
  1173
	  std::string pname = name.substr (offset);
jwe@6705
  1174
jwe@6705
  1175
	  std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
jwe@6705
  1176
	  std::transform (pname.begin (), pname.end (), pname.begin (), tolower);
jwe@6705
  1177
jwe@9185
  1178
	  bool has_property = false;
jwe@9185
  1179
	  if (pfx == "axes")
jwe@9185
  1180
	    has_property = axes::properties::has_property (pname);
jwe@9185
  1181
	  else if (pfx == "line")
jwe@9185
  1182
	    has_property = line::properties::has_property (pname);
jwe@9185
  1183
	  else if (pfx == "text")
jwe@9185
  1184
	    has_property = text::properties::has_property (pname);
jwe@9185
  1185
	  else if (pfx == "image")
jwe@9185
  1186
	    has_property = image::properties::has_property (pname);
jwe@9185
  1187
	  else if (pfx == "patch")
jwe@9185
  1188
	    has_property = patch::properties::has_property (pname);
jwe@9185
  1189
	  else if (pfx == "figure")
jwe@9185
  1190
	    has_property = figure::properties::has_property (pname);
jwe@9185
  1191
	  else if (pfx == "surface")
jwe@9185
  1192
	    has_property = surface::properties::has_property (pname);
jwe@9185
  1193
	  else if (pfx == "hggroup")
jwe@9185
  1194
	    has_property = hggroup::properties::has_property (pname);
jwe@9185
  1195
jwe@9185
  1196
	  if (has_property)
jwe@6705
  1197
	    {
jwe@9185
  1198
	      bool remove = false;
jwe@9185
  1199
	      if (val.is_string ())
jwe@9185
  1200
		{
jwe@9185
  1201
		  caseless_str tval = val.string_value ();
jwe@9185
  1202
jwe@9185
  1203
		  remove = tval.compare ("remove");
jwe@9185
  1204
		}
jwe@9185
  1205
jwe@9185
  1206
	      pval_map_type& pval_map = plist_map[pfx];
jwe@9185
  1207
jwe@9185
  1208
	      if (remove)
jwe@9185
  1209
		{
jwe@9185
  1210
		  pval_map_iterator p = pval_map.find (pname);
jwe@9185
  1211
jwe@9185
  1212
		  if (p != pval_map.end ())
jwe@9185
  1213
		    pval_map.erase (p);
jwe@9185
  1214
		}
jwe@9185
  1215
	      else
jwe@9185
  1216
		pval_map[pname] = val;
jwe@6705
  1217
	    }
jwe@6705
  1218
	  else
jwe@9185
  1219
	    error ("invalid %s property `%s'", pfx.c_str (), pname.c_str ());
jwe@6705
  1220
	}
jwe@6705
  1221
    }
jwe@6705
  1222
jwe@9185
  1223
  if (! error_state && offset == 0)
jwe@6705
  1224
    error ("invalid default property specification");
jwe@6705
  1225
}
jwe@6705
  1226
jwe@6705
  1227
octave_value
dbateman@7189
  1228
property_list::lookup (const caseless_str& name) const
jwe@6681
  1229
{
jwe@6705
  1230
  octave_value retval;
jwe@6563
  1231
jwe@6705
  1232
  size_t offset = 0;
jwe@6406
  1233
jwe@6705
  1234
  size_t len = name.length ();
jwe@6563
  1235
jwe@6705
  1236
  if (len > 4)
jwe@6705
  1237
    {
dbateman@7189
  1238
      caseless_str pfx = name.substr (0, 4);
jwe@6681
  1239
jwe@6705
  1240
      if (pfx.compare ("axes") || pfx.compare ("line")
jwe@6705
  1241
	  || pfx.compare ("text"))
jwe@6705
  1242
	offset = 4;
jwe@6705
  1243
      else if (len > 5)
jwe@6705
  1244
	{
jwe@6705
  1245
	  pfx = name.substr (0, 5);
jwe@6681
  1246
jwe@6807
  1247
	  if (pfx.compare ("image") || pfx.compare ("patch"))
jwe@6705
  1248
	    offset = 5;
jwe@6705
  1249
	  else if (len > 6)
jwe@6705
  1250
	    {
jwe@6705
  1251
	      pfx = name.substr (0, 6);
jwe@6681
  1252
jwe@6705
  1253
	      if (pfx.compare ("figure"))
jwe@6705
  1254
		offset = 6;
jwe@6705
  1255
	      else if (len > 7)
jwe@6705
  1256
		{
jwe@6705
  1257
		  pfx = name.substr (0, 7);
jwe@6406
  1258
michael@7865
  1259
		  if (pfx.compare ("surface") || pfx.compare ("hggroup"))
jwe@6705
  1260
		    offset = 7;
jwe@6705
  1261
		}
jwe@6705
  1262
	    }
jwe@6705
  1263
	}
jwe@6681
  1264
jwe@6705
  1265
      if (offset > 0)
jwe@6705
  1266
	{
jwe@6705
  1267
	  std::string pname = name.substr (offset);
jwe@6406
  1268
jwe@6705
  1269
	  std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
jwe@6705
  1270
	  std::transform (pname.begin (), pname.end (), pname.begin (), tolower);
jwe@6568
  1271
jwe@6705
  1272
	  plist_map_const_iterator p = find (pfx);
jwe@6563
  1273
jwe@6705
  1274
	  if (p != end ())
jwe@6705
  1275
	    {
jwe@6705
  1276
	      const pval_map_type& pval_map = p->second;
jwe@6563
  1277
jwe@6705
  1278
	      pval_map_const_iterator q = pval_map.find (pname);
jwe@6563
  1279
jwe@6705
  1280
	      if (q != pval_map.end ())
jwe@6705
  1281
		retval = q->second;
jwe@6705
  1282
	    }
jwe@6705
  1283
	}
jwe@6705
  1284
    }
jwe@6563
  1285
jwe@6705
  1286
  return retval;
jwe@6705
  1287
}
jwe@6563
  1288
jwe@6705
  1289
Octave_map
jwe@6705
  1290
property_list::as_struct (const std::string& prefix_arg) const
jwe@6705
  1291
{
jwe@6705
  1292
  Octave_map m;
jwe@6563
  1293
jwe@6705
  1294
  for (plist_map_const_iterator p = begin (); p != end (); p++)
jwe@6705
  1295
    {
jwe@6705
  1296
      std::string prefix = prefix_arg + p->first;
jwe@6563
  1297
jwe@6705
  1298
      const pval_map_type pval_map = p->second;
jwe@6563
  1299
jwe@6705
  1300
      for (pval_map_const_iterator q = pval_map.begin ();
jwe@6705
  1301
	   q != pval_map.end ();
jwe@6705
  1302
	   q++)
jwe@6705
  1303
	m.assign (prefix + q->first, q->second);
jwe@6705
  1304
    }
jwe@6563
  1305
jwe@6705
  1306
  return m;    
jwe@6705
  1307
}
jwe@6681
  1308
jwe@6874
  1309
graphics_handle::graphics_handle (const octave_value& a)
jwe@6874
  1310
  : val (octave_NaN)
jwe@6874
  1311
{
jwe@6874
  1312
  if (a.is_empty ())
jwe@6874
  1313
    /* do nothing */;
jwe@6874
  1314
  else
jwe@6874
  1315
    {
jwe@6874
  1316
      double tval = a.double_value ();
jwe@6874
  1317
jwe@6874
  1318
      if (! error_state)
jwe@6874
  1319
	val = tval;
jwe@6874
  1320
      else
jwe@6874
  1321
	error ("invalid graphics handle");
jwe@6874
  1322
    }
jwe@6874
  1323
}
jwe@6874
  1324
jwe@6705
  1325
void
jwe@6705
  1326
graphics_object::set (const octave_value_list& args)
jwe@6705
  1327
{
jwe@6705
  1328
  int nargin = args.length ();
jwe@6406
  1329
jwe@6705
  1330
  if (nargin == 0)
jwe@6705
  1331
    rep->defaults ();
jwe@6705
  1332
  else if (nargin % 2 == 0)
jwe@6705
  1333
    {
jwe@6705
  1334
      for (int i = 0; i < nargin; i += 2)
jwe@6705
  1335
	{
dbateman@7189
  1336
	  caseless_str name = args(i).string_value ();
jwe@6681
  1337
jwe@6705
  1338
	  if (! error_state)
jwe@6705
  1339
	    {
jwe@6705
  1340
	      octave_value val = args(i+1);
jwe@6705
  1341
jwe@6705
  1342
	      if (val.is_string ())
jwe@6705
  1343
		{
dbateman@7189
  1344
		  caseless_str tval = val.string_value ();
jwe@6705
  1345
jwe@6705
  1346
		  if (tval.compare ("default"))
jwe@6705
  1347
		    val = get_default (name);
jwe@6705
  1348
		  else if (tval.compare ("factory"))
jwe@6705
  1349
		    val = get_factory_default (name);
jwe@6705
  1350
		}
jwe@6705
  1351
jwe@6705
  1352
	      if (error_state)
jwe@6705
  1353
		break;
jwe@6705
  1354
jwe@6705
  1355
	      rep->set (name, val);
jwe@6705
  1356
	    }
jwe@6705
  1357
	  else
jwe@6705
  1358
	    error ("set: expecting argument %d to be a property name", i);
jwe@6705
  1359
	}
jwe@6705
  1360
    }
jwe@6705
  1361
  else
jwe@6705
  1362
    error ("set: invalid number of arguments");
jwe@6705
  1363
}
jwe@6705
  1364
jwe@8234
  1365
static double
jwe@8234
  1366
make_handle_fraction (void)
jwe@8234
  1367
{
jwe@8234
  1368
  static double maxrand = RAND_MAX + 2.0;
jwe@8234
  1369
jwe@8234
  1370
  return (rand () + 1.0) / maxrand;
jwe@8234
  1371
}
jwe@6705
  1372
jwe@6705
  1373
graphics_handle
jwe@6705
  1374
gh_manager::get_handle (const std::string& go_name)
jwe@6681
  1375
{
jwe@6705
  1376
  graphics_handle retval;
jwe@6681
  1377
jwe@6705
  1378
  if (go_name == "figure")
jwe@6705
  1379
    {
jwe@8234
  1380
      // Figure handles are positive integers corresponding to the
jwe@8234
  1381
      // figure number.
jwe@8234
  1382
jwe@6705
  1383
      // We always want the lowest unused figure number.
jwe@6681
  1384
jwe@6705
  1385
      retval = 1;
jwe@6681
  1386
jwe@6705
  1387
      while (handle_map.find (retval) != handle_map.end ())
jwe@6705
  1388
	retval++;
jwe@6705
  1389
    }
jwe@6705
  1390
  else
jwe@6705
  1391
    {
jwe@8234
  1392
      // Other graphics handles are negative integers plus some random
jwe@8234
  1393
      // fractional part.  To avoid running out of integers, we
jwe@8234
  1394
      // recycle the integer part but tack on a new random part each
jwe@8234
  1395
      // time.
jwe@8234
  1396
jwe@6705
  1397
      free_list_iterator p = handle_free_list.begin ();
jwe@6681
  1398
jwe@6705
  1399
      if (p != handle_free_list.end ())
jwe@6705
  1400
	{
jwe@6705
  1401
	  retval = *p;
jwe@6705
  1402
	  handle_free_list.erase (p);
jwe@6705
  1403
	}
jwe@6705
  1404
      else
jwe@7286
  1405
	{
jwe@7286
  1406
	  retval = graphics_handle (next_handle);
jwe@7286
  1407
jwe@8234
  1408
	  next_handle = ceil (next_handle) - 1.0 - make_handle_fraction ();
jwe@7286
  1409
	}
jwe@6705
  1410
    }
jwe@6681
  1411
jwe@6705
  1412
  return retval;
jwe@6705
  1413
}
jwe@6681
  1414
jwe@6705
  1415
void
jwe@6705
  1416
gh_manager::do_free (const graphics_handle& h)
jwe@6705
  1417
{
jwe@7056
  1418
  if (h.ok ())
jwe@6705
  1419
    {
jwe@6874
  1420
      if (h.value () != 0)
jwe@6705
  1421
	{
jwe@6874
  1422
	  iterator p = handle_map.find (h);
jwe@6874
  1423
jwe@6874
  1424
	  if (p != handle_map.end ())
jwe@6874
  1425
	    {
jwe@8208
  1426
	      base_properties& bp = p->second.get_properties ();
jwe@8208
  1427
	      
jwe@8208
  1428
	      bp.set_beingdeleted (true);
jwe@8208
  1429
jwe@8208
  1430
	      bp.delete_children ();
jwe@8208
  1431
jwe@8208
  1432
	      octave_value val = bp.get_deletefcn ();
jwe@8208
  1433
jwe@8208
  1434
	      bp.execute_deletefcn ();
jwe@7367
  1435
jwe@8058
  1436
	      // notify backend
jwe@8058
  1437
	      graphics_backend backend = p->second.get_backend ();
jwe@8058
  1438
	      if (backend)
jwe@8059
  1439
                backend.object_destroyed (p->second);
jwe@8208
  1440
jwe@8208
  1441
	      // Note: this will be valid only for first explicitly 
jwe@8208
  1442
	      // deleted object.  All its children will then have an
jwe@8208
  1443
	      // unknown backend.
jwe@8208
  1444
jwe@8234
  1445
	      // Graphics handles for non-figure objects are negative
jwe@8234
  1446
	      // integers plus some random fractional part.  To avoid
jwe@8234
  1447
	      // running out of integers, we recycle the integer part
jwe@8234
  1448
	      // but tack on a new random part each time.
jwe@8234
  1449
jwe@6874
  1450
	      handle_map.erase (p);
jwe@6874
  1451
jwe@6874
  1452
	      if (h.value () < 0)
jwe@8234
  1453
		handle_free_list.insert (ceil (h.value ()) - make_handle_fraction ());
jwe@6874
  1454
	    }
jwe@6874
  1455
	  else
jwe@6874
  1456
	    error ("graphics_handle::free: invalid object %g", h.value ());
jwe@6705
  1457
	}
jwe@6705
  1458
      else
jwe@6874
  1459
	error ("graphics_handle::free: can't delete root figure");
jwe@6705
  1460
    }
jwe@6705
  1461
}
jwe@6681
  1462
jwe@6406
  1463
gh_manager *gh_manager::instance = 0;
jwe@6406
  1464
jwe@6406
  1465
static void
dbateman@7189
  1466
xset (const graphics_handle& h, const caseless_str& name,
jwe@6406
  1467
      const octave_value& val)
jwe@6406
  1468
{
jwe@6406
  1469
  graphics_object obj = gh_manager::get_object (h);
jwe@6406
  1470
  obj.set (name, val);
jwe@6406
  1471
}
jwe@6406
  1472
jwe@6406
  1473
static void
jwe@6406
  1474
xset (const graphics_handle& h, const octave_value_list& args)
jwe@6406
  1475
{
jwe@6406
  1476
  if (args.length () > 0)
jwe@6406
  1477
    {
jwe@6406
  1478
      graphics_object obj = gh_manager::get_object (h);
jwe@6406
  1479
      obj.set (args);
jwe@6406
  1480
    }
jwe@6406
  1481
}
jwe@6406
  1482
jwe@6406
  1483
jwe@6406
  1484
static octave_value
dbateman@7189
  1485
xget (const graphics_handle& h, const caseless_str& name)
jwe@6406
  1486
{
jwe@6406
  1487
  graphics_object obj = gh_manager::get_object (h);
jwe@6406
  1488
  return obj.get (name);
jwe@6406
  1489
}
jwe@6406
  1490
jwe@6406
  1491
static graphics_handle
jwe@6406
  1492
reparent (const octave_value& ov, const std::string& who,
jwe@6406
  1493
	  const std::string& property, const graphics_handle& new_parent,
jwe@6406
  1494
	  bool adopt = true)
jwe@6406
  1495
{
jwe@6406
  1496
  graphics_handle h = octave_NaN;
jwe@6406
  1497
jwe@6406
  1498
  double val = ov.double_value ();
jwe@6406
  1499
jwe@6406
  1500
  if (! error_state)
jwe@6406
  1501
    {
jwe@6406
  1502
      h = gh_manager::lookup (val);
jwe@6406
  1503
jwe@7056
  1504
      if (h.ok ())
jwe@6406
  1505
	{
jwe@6406
  1506
	  graphics_object obj = gh_manager::get_object (h);
jwe@6406
  1507
	  
jwe@6406
  1508
	  graphics_handle parent_h = obj.get_parent ();
jwe@6406
  1509
jwe@6406
  1510
	  graphics_object parent_obj = gh_manager::get_object (parent_h);
jwe@6406
  1511
jwe@6406
  1512
	  parent_obj.remove_child (h);
jwe@6406
  1513
jwe@6406
  1514
	  if (adopt)
jwe@6874
  1515
	    obj.set ("parent", new_parent.value ());
jwe@6406
  1516
	  else
jwe@6406
  1517
	    obj.reparent (new_parent);
jwe@6406
  1518
	}
jwe@6406
  1519
      else
jwe@6406
  1520
	error ("%s: invalid graphics handle (= %g) for %s",
jwe@6406
  1521
	       who.c_str (), val, property.c_str ());
jwe@6406
  1522
    }
jwe@6406
  1523
  else
jwe@6406
  1524
    error ("%s: expecting %s to be a graphics handle",
jwe@6406
  1525
	   who.c_str (), property.c_str ());
jwe@6406
  1526
jwe@6406
  1527
  return h;
jwe@6406
  1528
}
jwe@6406
  1529
jwe@6406
  1530
// This function is NOT equivalent to the scripting language function gcf.
jwe@6406
  1531
graphics_handle
jwe@6406
  1532
gcf (void)
jwe@6406
  1533
{
jwe@6406
  1534
  octave_value val = xget (0, "currentfigure");
jwe@6406
  1535
jwe@6406
  1536
  return val.is_empty () ? octave_NaN : val.double_value ();
jwe@6406
  1537
}
jwe@6406
  1538
jwe@6406
  1539
// This function is NOT equivalent to the scripting language function gca.
jwe@6406
  1540
graphics_handle
jwe@6406
  1541
gca (void)
jwe@6406
  1542
{
jwe@6406
  1543
  octave_value val = xget (gcf (), "currentaxes");
jwe@6406
  1544
jwe@6406
  1545
  return val.is_empty () ? octave_NaN : val.double_value ();
jwe@6406
  1546
}
jwe@6406
  1547
jwe@6406
  1548
static void
jwe@6406
  1549
adopt (const graphics_handle& p, const graphics_handle& h)
jwe@6406
  1550
{
jwe@6406
  1551
  graphics_object parent_obj = gh_manager::get_object (p);
jwe@6406
  1552
jwe@6406
  1553
  parent_obj.adopt (h);
jwe@6406
  1554
}
jwe@6406
  1555
jwe@6406
  1556
static bool
jwe@7056
  1557
is_handle (const graphics_handle& h)
jwe@7056
  1558
{
jwe@7056
  1559
  return h.ok ();
jwe@7056
  1560
}
jwe@7056
  1561
jwe@7056
  1562
static bool
jwe@6406
  1563
is_handle (double val)
jwe@6406
  1564
{
jwe@6874
  1565
  graphics_handle h = gh_manager::lookup (val);
jwe@6874
  1566
jwe@6874
  1567
  return h.ok ();
jwe@6406
  1568
}
jwe@6406
  1569
dbateman@8183
  1570
static octave_value
jwe@6406
  1571
is_handle (const octave_value& val)
jwe@6406
  1572
{
dbateman@8183
  1573
  octave_value retval = false;
dbateman@8183
  1574
dbateman@8183
  1575
  if (val.is_real_scalar () && is_handle (val.double_value ()))
dbateman@8183
  1576
    retval = true;
dbateman@8183
  1577
  else if (val.is_real_matrix ())
dbateman@8183
  1578
    {
dbateman@8183
  1579
      if (val.is_string ())
dbateman@8183
  1580
	retval = boolNDArray (val.dims (), false);
dbateman@8183
  1581
      else
dbateman@8183
  1582
	{
dbateman@8183
  1583
	  const NDArray handles = val.array_value ();
dbateman@8183
  1584
dbateman@8183
  1585
	  if (! error_state)
dbateman@8183
  1586
	    {
dbateman@8183
  1587
	      boolNDArray result (handles.dims ());
dbateman@8183
  1588
dbateman@8183
  1589
	      for (octave_idx_type i = 0; i < handles.numel (); i++)
dbateman@8183
  1590
		result.xelem (i) = is_handle (handles (i));
dbateman@8183
  1591
dbateman@8183
  1592
	      retval = result;
dbateman@8183
  1593
	    }
dbateman@8183
  1594
	}
dbateman@8183
  1595
    }
dbateman@8183
  1596
dbateman@8183
  1597
  return retval;
jwe@6406
  1598
}
jwe@6406
  1599
jwe@6406
  1600
static bool
jwe@6406
  1601
is_figure (double val)
jwe@6406
  1602
{
jwe@6406
  1603
  graphics_object obj = gh_manager::get_object (val);
jwe@6406
  1604
jwe@6406
  1605
  return obj && obj.isa ("figure");
jwe@6406
  1606
}
jwe@6406
  1607
jwe@7370
  1608
static void
jwe@7370
  1609
xcreatefcn (const graphics_handle& h)
jwe@7370
  1610
{
jwe@7370
  1611
  graphics_object obj = gh_manager::get_object (h);
jwe@7370
  1612
  obj.get_properties ().execute_createfcn  ();
jwe@7370
  1613
}
jwe@7370
  1614
jwe@6406
  1615
// ---------------------------------------------------------------------
jwe@6406
  1616
jwe@8059
  1617
void
jwe@8059
  1618
base_graphics_backend::property_changed (const graphics_handle& h, int id)
jwe@8059
  1619
{
jwe@8059
  1620
  graphics_object go = gh_manager::get_object (h);
jwe@8059
  1621
jwe@8059
  1622
  property_changed (go, id);
jwe@8059
  1623
}
jwe@8059
  1624
jwe@8059
  1625
void
jwe@8059
  1626
base_graphics_backend::object_created (const graphics_handle& h)
jwe@8059
  1627
{
jwe@8059
  1628
  graphics_object go = gh_manager::get_object (h);
jwe@8059
  1629
jwe@8059
  1630
  object_created (go);
jwe@8059
  1631
}
jwe@8059
  1632
jwe@8059
  1633
void
jwe@8059
  1634
base_graphics_backend::object_destroyed (const graphics_handle& h)
jwe@8059
  1635
{
jwe@8059
  1636
  graphics_object go = gh_manager::get_object (h);
jwe@8059
  1637
jwe@8059
  1638
  object_destroyed (go);
jwe@8059
  1639
}
jwe@8059
  1640
// ---------------------------------------------------------------------
jwe@8059
  1641
jwe@6406
  1642
static Matrix
jwe@6406
  1643
maybe_set_children (const Matrix& kids, const octave_value& val)
jwe@6406
  1644
{
jwe@6406
  1645
  const Matrix new_kids = val.matrix_value ();
jwe@6406
  1646
jwe@6406
  1647
  bool ok = true;
jwe@6406
  1648
jwe@6406
  1649
  if (! error_state)
jwe@6406
  1650
    {
jwe@6406
  1651
      if (kids.numel () == new_kids.numel ())
jwe@6406
  1652
	{
jwe@6406
  1653
	  Matrix t1 = kids;
jwe@6406
  1654
	  Matrix t2 = new_kids;
jwe@6406
  1655
highegg@8503
  1656
	  t1.sort ();
highegg@8503
  1657
	  t2.sort ();
jwe@6406
  1658
jwe@6406
  1659
	  if (t1 != t2)
jwe@6406
  1660
	    ok = false;
jwe@8209
  1661
	}
jwe@8209
  1662
      else
jwe@6406
  1663
	ok = false;
jwe@6406
  1664
jwe@6406
  1665
      if (! ok)
jwe@6406
  1666
	error ("set: new children must be a permutation of existing children");
jwe@6406
  1667
    }
jwe@6406
  1668
  else
jwe@6406
  1669
    {
jwe@6406
  1670
      ok = false;
jwe@6406
  1671
      error ("set: expecting children to be array of graphics handles");
jwe@6406
  1672
    }
jwe@6406
  1673
jwe@6406
  1674
  return ok ? new_kids : kids;
jwe@6406
  1675
}
jwe@6406
  1676
jwe@6705
  1677
void
jwe@6705
  1678
base_properties::set_from_list (base_graphics_object& obj,
jwe@6705
  1679
				property_list& defaults)
jwe@6406
  1680
{
jwe@6705
  1681
  std::string go_name = graphics_object_name ();
jwe@6406
  1682
jwe@6705
  1683
  property_list::plist_map_const_iterator p = defaults.find (go_name);
jwe@6406
  1684
jwe@6705
  1685
  if (p != defaults.end ())
jwe@6705
  1686
    {
jwe@6705
  1687
      const property_list::pval_map_type pval_map = p->second;
jwe@6406
  1688
jwe@6705
  1689
      for (property_list::pval_map_const_iterator q = pval_map.begin ();
jwe@6705
  1690
	   q != pval_map.end ();
jwe@6705
  1691
	   q++)
jwe@6705
  1692
	{
jwe@6705
  1693
	  std::string pname = q->first;
jwe@6432
  1694
jwe@6705
  1695
	  obj.set (pname, q->second);
jwe@6406
  1696
jwe@6705
  1697
	  if (error_state)
jwe@6705
  1698
	    {
jwe@6705
  1699
	      error ("error setting default property %s", pname.c_str ());
jwe@6705
  1700
	      break;
jwe@6705
  1701
	    }
jwe@6705
  1702
	}
jwe@6705
  1703
    }
jwe@6705
  1704
}
jwe@6406
  1705
jwe@7363
  1706
octave_value
jwe@8061
  1707
base_properties::get_dynamic (const caseless_str& name) const
jwe@7363
  1708
{
jwe@7363
  1709
  octave_value retval;
jwe@7363
  1710
Michael@8090
  1711
  std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.find (name);
jwe@8061
  1712
jwe@8061
  1713
  if (it != all_props.end ())
jwe@8061
  1714
    retval = it->second.get ();
jwe@7363
  1715
  else
jwe@8061
  1716
    error ("get: unknown property \"%s\"", name.c_str ());
jwe@7363
  1717
jwe@7363
  1718
  return retval;
jwe@7363
  1719
}
jwe@7363
  1720
jwe@7363
  1721
octave_value
jwe@8061
  1722
base_properties::get_dynamic (bool all) const
jwe@7363
  1723
{
jwe@7363
  1724
  Octave_map m;
jwe@7363
  1725
Michael@8090
  1726
  for (std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.begin ();
jwe@7363
  1727
       it != all_props.end (); ++it)
jwe@7379
  1728
    if (all || ! it->second.is_hidden ())
jwe@7379
  1729
      m.assign (it->second.get_name (), it->second.get ());
jwe@7363
  1730
jwe@7363
  1731
  return m;
jwe@7363
  1732
}
jwe@7363
  1733
jwe@9185
  1734
std::map<std::string, std::set<std::string> > base_properties::all_dynamic_properties;
jwe@9185
  1735
jwe@9185
  1736
bool
jwe@9185
  1737
base_properties::has_dynamic_property (const std::string& pname,
jwe@9185
  1738
				       const std::string& cname)
jwe@9185
  1739
{
jwe@9185
  1740
  // FIXME -- we need to maintain a static map of class names to sets
jwe@9185
  1741
  // of dynamic property names, then look up the set for the given
jwe@9185
  1742
  // cname, then see if the set contains the given pname.  Doing that
jwe@9185
  1743
  // implies changes to set_dynamic, I think.  Where is set_dynamic
jwe@9185
  1744
  // ever used?
jwe@9185
  1745
jwe@9185
  1746
  std::set<std::string>& dynprops = all_dynamic_properties[cname];
jwe@9185
  1747
jwe@9185
  1748
  return dynprops.find (pname) != dynprops.end ();
jwe@9185
  1749
}
jwe@9185
  1750
jwe@7363
  1751
void
jwe@9185
  1752
base_properties::set_dynamic (const caseless_str& pname,
jwe@9185
  1753
			      const std::string& cname,
jwe@9185
  1754
			      const octave_value& val)
jwe@9185
  1755
{
jwe@9185
  1756
  std::map<caseless_str, property, cmp_caseless_str>::iterator it = all_props.find (pname);
jwe@8061
  1757
jwe@8061
  1758
  if (it != all_props.end ())
jwe@8061
  1759
    it->second.set (val);
jwe@7363
  1760
  else
jwe@9185
  1761
    error ("set: unknown property \"%s\"", pname.c_str ());
jwe@8061
  1762
jwe@8061
  1763
  if (! error_state)
jwe@9185
  1764
    {
jwe@9185
  1765
      all_dynamic_properties[cname].insert (pname);
jwe@9185
  1766
jwe@9185
  1767
      mark_modified ();
jwe@9185
  1768
    }
jwe@7363
  1769
}
jwe@7363
  1770
jwe@7363
  1771
property
jwe@8061
  1772
base_properties::get_property_dynamic (const caseless_str& name)
jwe@7363
  1773
{
Michael@8090
  1774
  std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.find (name);
jwe@8061
  1775
jwe@8061
  1776
  if (it == all_props.end ())
jwe@8061
  1777
    {
jwe@8061
  1778
      error ("get_property: unknown property \"%s\"", name.c_str ());
jwe@8061
  1779
      return property ();
jwe@8061
  1780
    }
jwe@7363
  1781
  else
jwe@8061
  1782
    return it->second;
jwe@7363
  1783
}
jwe@7363
  1784
michael@7864
  1785
bool
michael@7864
  1786
base_properties::has_property (const caseless_str& name)
michael@7864
  1787
{
michael@7864
  1788
  property p;
michael@7864
  1789
michael@7864
  1790
  unwind_protect::begin_frame("base_properties::has_property");
michael@7864
  1791
michael@7864
  1792
  unwind_protect_bool (discard_error_messages);
michael@7864
  1793
  unwind_protect_int (error_state);
michael@7864
  1794
michael@7864
  1795
  discard_error_messages = true;
michael@7864
  1796
michael@7864
  1797
  p = get_property (name);
michael@7864
  1798
michael@7864
  1799
  unwind_protect::run_frame ("base_properties::has_property");
michael@7864
  1800
michael@7864
  1801
  return (p.ok ());
michael@7864
  1802
}
michael@7864
  1803
jwe@6705
  1804
void
jwe@6705
  1805
base_properties::remove_child (const graphics_handle& h)
jwe@6406
  1806
{
jwe@6705
  1807
  octave_idx_type k = -1;
jwe@6705
  1808
  octave_idx_type n = children.numel ();
jwe@6705
  1809
  for (octave_idx_type i = 0; i < n; i++)
jwe@6406
  1810
    {
jwe@6874
  1811
      if (h.value () == children(i))
jwe@6406
  1812
	{
jwe@6705
  1813
	  k = i;
jwe@6705
  1814
	  break;
jwe@6406
  1815
	}
jwe@6406
  1816
    }
jwe@6406
  1817
jwe@6705
  1818
  if (k >= 0)
jwe@6406
  1819
    {
jwe@8233
  1820
      Matrix new_kids (n-1, 1);
jwe@6705
  1821
      octave_idx_type j = 0;
jwe@6705
  1822
      for (octave_idx_type i = 0; i < n; i++)
jwe@6705
  1823
	{
jwe@6705
  1824
	  if (i != k)
jwe@6705
  1825
	    new_kids(j++) = children(i);
jwe@6705
  1826
	}
jwe@6705
  1827
      children = new_kids;
jwe@7378
  1828
      mark_modified ();
jwe@6705
  1829
    }
jwe@6705
  1830
}
jwe@6406
  1831
jwe@6836
  1832
void
jwe@6836
  1833
base_properties::set_parent (const octave_value& val)
jwe@6705
  1834
{
jwe@6705
  1835
  double tmp = val.double_value ();
jwe@6406
  1836
jwe@6705
  1837
  graphics_handle new_parent = octave_NaN;
jwe@6705
  1838
jwe@6705
  1839
  if (! error_state)
jwe@6705
  1840
    {
jwe@6705
  1841
      new_parent = gh_manager::lookup (tmp);
jwe@6705
  1842
jwe@7056
  1843
      if (new_parent.ok ())
jwe@6705
  1844
	{
jwe@7363
  1845
	  graphics_object parent_obj = gh_manager::get_object (get_parent ());
jwe@6705
  1846
jwe@6705
  1847
	  parent_obj.remove_child (__myhandle__);
jwe@6705
  1848
jwe@7363
  1849
	  parent = new_parent.as_octave_value ();
jwe@6705
  1850
jwe@7363
  1851
	  ::adopt (parent.handle_value (), __myhandle__);
jwe@6705
  1852
	}
jwe@6705
  1853
      else
jwe@6705
  1854
	error ("set: invalid graphics handle (= %g) for parent", tmp);
jwe@6406
  1855
    }
jwe@6705
  1856
  else
jwe@6705
  1857
    error ("set: expecting parent to be a graphics handle");
jwe@6705
  1858
}
jwe@6406
  1859
jwe@6705
  1860
void
jwe@8061
  1861
base_properties::set_children (const octave_value& val)
jwe@8061
  1862
{
jwe@8061
  1863
  children = maybe_set_children (children, val);
jwe@8061
  1864
}
jwe@8061
  1865
jwe@8061
  1866
void
jwe@6836
  1867
base_properties::mark_modified (void)
jwe@6836
  1868
{
jwe@7363
  1869
  __modified__ = "on";
jwe@7363
  1870
  graphics_object parent_obj = gh_manager::get_object (get_parent ());
jwe@7379
  1871
  if (parent_obj)
jwe@7379
  1872
    parent_obj.mark_modified ();
jwe@6836
  1873
}
jwe@6836
  1874
jwe@6836
  1875
void
jwe@6836
  1876
base_properties::override_defaults (base_graphics_object& obj)
jwe@6836
  1877
{
jwe@7363
  1878
  graphics_object parent_obj = gh_manager::get_object (get_parent ());
michael@7864
  1879
michael@7864
  1880
  if (parent_obj)
michael@7864
  1881
    parent_obj.override_defaults (obj);
jwe@6836
  1882
}
jwe@6836
  1883
jwe@6836
  1884
void
jwe@7214
  1885
base_properties::update_axis_limits (const std::string& axis_type) const
jwe@7214
  1886
{
michael@7862
  1887
  graphics_object obj = gh_manager::get_object (__myhandle__);
michael@7862
  1888
michael@7862
  1889
  if (obj)
jwe@7214
  1890
    obj.update_axis_limits (axis_type);
jwe@7214
  1891
}
jwe@7214
  1892
jwe@7214
  1893
void
jwe@6836
  1894
base_properties::delete_children (void)
jwe@6836
  1895
{
jwe@6836
  1896
  octave_idx_type n = children.numel ();
jwe@6836
  1897
jwe@8208
  1898
  // A callback function might have already deleted the child,
jwe@8208
  1899
  // so check before deleting
jwe@6836
  1900
  for (octave_idx_type i = 0; i < n; i++)
jwe@8208
  1901
    {
jwe@8208
  1902
      graphics_object go = gh_manager::get_object (children(i));
jwe@8208
  1903
jwe@8208
  1904
      if (go.valid_object ())
jwe@8208
  1905
	gh_manager::free (children(i));
jwe@8208
  1906
    }
jwe@6836
  1907
}
jwe@6836
  1908
jwe@7419
  1909
graphics_backend
jwe@7419
  1910
base_properties::get_backend (void) const
jwe@7419
  1911
{
jwe@7419
  1912
  graphics_object go = gh_manager::get_object (get_parent ());
jwe@7419
  1913
jwe@7419
  1914
  if (go)
jwe@7419
  1915
    return go.get_backend ();
jwe@7419
  1916
  else
jwe@7419
  1917
    return graphics_backend ();
jwe@7419
  1918
}
jwe@7419
  1919
michael@7828
  1920
void
michael@7828
  1921
base_properties::update_boundingbox (void)
michael@7828
  1922
{
michael@7828
  1923
  Matrix kids = get_children ();
michael@7828
  1924
michael@7828
  1925
  for (int i = 0; i < kids.numel (); i++)
michael@7828
  1926
    {
michael@7828
  1927
      graphics_object go = gh_manager::get_object (kids(i));
michael@7828
  1928
michael@7828
  1929
      if (go.valid_object ())
michael@7828
  1930
	go.get_properties ().update_boundingbox ();
michael@7828
  1931
    }
michael@7828
  1932
}
michael@7828
  1933
michael@7849
  1934
void
michael@7849
  1935
base_properties::add_listener (const caseless_str& nm, const octave_value& v,
michael@7849
  1936
			       listener_mode mode)
michael@7849
  1937
{
michael@7849
  1938
  property p = get_property (nm);
michael@7849
  1939
michael@7849
  1940
  if (! error_state && p.ok ())
michael@7849
  1941
    p.add_listener (v, mode);
michael@7849
  1942
}
michael@7849
  1943
dbateman@8299
  1944
void
dbateman@8299
  1945
base_properties::delete_listener (const caseless_str& nm, 
dbateman@8299
  1946
				  const octave_value& v, listener_mode mode)
dbateman@8299
  1947
{
dbateman@8299
  1948
  property p = get_property (nm);
dbateman@8299
  1949
dbateman@8299
  1950
  if (! error_state && p.ok ())
dbateman@8299
  1951
    p.delete_listener (v, mode);
dbateman@8299
  1952
}
dbateman@8299
  1953
jwe@7363
  1954
// ---------------------------------------------------------------------
jwe@7363
  1955
jwe@7408
  1956
class gnuplot_backend : public base_graphics_backend
jwe@7408
  1957
{
jwe@7408
  1958
public:
jwe@7408
  1959
  gnuplot_backend (void)
jwe@7408
  1960
      : base_graphics_backend ("gnuplot") { }
jwe@7408
  1961
jwe@7408
  1962
  ~gnuplot_backend (void) { }
jwe@7408
  1963
jwe@7408
  1964
  bool is_valid (void) const { return true; }
jwe@8059
  1965
jwe@8059
  1966
  void object_destroyed (const graphics_object& go)
jwe@8059
  1967
    {
jwe@8059
  1968
      if (go.isa ("figure"))
jwe@8059
  1969
	{
jwe@8059
  1970
	  const figure::properties& props =
jwe@8059
  1971
	      dynamic_cast<const figure::properties&> (go.get_properties ());
jwe@8059
  1972
jwe@8059
  1973
	  send_quit (props.get___plot_stream__ ());
jwe@8059
  1974
	}
jwe@8059
  1975
    }
jwe@8059
  1976
jwe@8059
  1977
  void property_changed (const graphics_object& go, int id)
jwe@8059
  1978
    {
jwe@8059
  1979
      if (go.isa ("figure"))
jwe@8059
  1980
	{
jwe@8059
  1981
	  graphics_object obj (go);
jwe@8059
  1982
jwe@8059
  1983
	  figure::properties& props =
jwe@8059
  1984
	      dynamic_cast<figure::properties&> (obj.get_properties ());
jwe@8059
  1985
jwe@8059
  1986
	  switch (id)
jwe@8059
  1987
	    {
jwe@8059
  1988
	    case base_properties::VISIBLE:
jwe@8059
  1989
	      if (! props.is_visible ())
jwe@8059
  1990
		{
jwe@8059
  1991
		  send_quit (props.get___plot_stream__ ());
jwe@8059
  1992
		  props.set___plot_stream__ (Matrix ());
jwe@8059
  1993
		  props.set___enhanced__ (false);
jwe@8059
  1994
		}
jwe@8059
  1995
	      break;
jwe@8059
  1996
	    }
jwe@8059
  1997
	}
jwe@8059
  1998
    }
jwe@8059
  1999
jwe@8059
  2000
  void redraw_figure (const graphics_object& go) const
jwe@8059
  2001
    {
jwe@8059
  2002
      octave_value_list args;
jwe@8059
  2003
      args(0) = go.get_handle ().as_octave_value ();
jwe@8059
  2004
      feval ("gnuplot_drawnow", args);
jwe@8059
  2005
    }
jwe@8059
  2006
jwe@8059
  2007
  void print_figure (const graphics_object& go, const std::string& term,
jwe@8059
  2008
		     const std::string& file, bool mono,
jwe@8059
  2009
		     const std::string& debug_file) const
jwe@8059
  2010
    {
jwe@8059
  2011
      octave_value_list args;
jwe@8059
  2012
      if (! debug_file.empty ())
jwe@8059
  2013
	args(4) = debug_file;
jwe@8059
  2014
      args(3) = mono;
jwe@8059
  2015
      args(2) = file;
jwe@8059
  2016
      args(1) = term;
jwe@8059
  2017
      args(0) = go.get_handle ().as_octave_value ();
jwe@8059
  2018
      feval ("gnuplot_drawnow", args);
jwe@8059
  2019
    }
jwe@8059
  2020
jwe@8059
  2021
  Matrix get_canvas_size (const graphics_handle&) const
jwe@8059
  2022
    {
jwe@8059
  2023
      Matrix sz (1, 2, 0.0);
jwe@8059
  2024
      return sz;
jwe@8059
  2025
    }
jwe@8059
  2026
jwe@8059
  2027
  double get_screen_resolution (void) const
jwe@8059
  2028
    { return 72.0; }
jwe@8059
  2029
jwe@8059
  2030
  Matrix get_screen_size (void) const
jwe@8059
  2031
    { return Matrix (1, 2, 0.0); }
jwe@8059
  2032
jwe@8059
  2033
private:
jwe@8059
  2034
  void send_quit (const octave_value& pstream) const
jwe@7408
  2035
    {
jwe@7408
  2036
      if (! pstream.is_empty())
jwe@7408
  2037
	{
jwe@7408
  2038
	  octave_value_list args;
dbateman@7680
  2039
	  Matrix fids = pstream.matrix_value ();
dbateman@7680
  2040
dbateman@7680
  2041
	  if (! error_state)
dbateman@7680
  2042
	    {
dbateman@7680
  2043
	      args(1) = "\nquit;\n";
dbateman@7680
  2044
	      args(0) = octave_value (fids (0));
dbateman@7680
  2045
	      feval ("fputs", args);
dbateman@7680
  2046
	      args.resize (1);
dbateman@7680
  2047
	      feval ("fflush", args);
dbateman@7680
  2048
	      feval ("pclose", args);
dbateman@7680
  2049
	      if (fids.numel () > 1)
dbateman@7680
  2050
		{
dbateman@7680
  2051
		  args(0) = octave_value (fids (1));
dbateman@7680
  2052
		  feval ("pclose", args);
dbateman@7680
  2053
		}
dbateman@7680
  2054
	    }
jwe@7408
  2055
	}
jwe@7408
  2056
    }
jwe@7408
  2057
};
jwe@7408
  2058
jwe@7408
  2059
graphics_backend
jwe@7408
  2060
graphics_backend::default_backend (void)
jwe@7408
  2061
{
jwe@7408
  2062
  if (available_backends.size () == 0)
jwe@7408
  2063
    register_backend (new gnuplot_backend ());
jwe@7408
  2064
jwe@7408
  2065
  return available_backends["gnuplot"];
jwe@7408
  2066
}
jwe@7408
  2067
jwe@7408
  2068
std::map<std::string, graphics_backend> graphics_backend::available_backends;
jwe@7408
  2069
jwe@7408
  2070
// ---------------------------------------------------------------------
jwe@7408
  2071
michael@7862
  2072
void
michael@7862
  2073
base_graphics_object::update_axis_limits (const std::string& axis_type)
michael@7862
  2074
{
michael@7862
  2075
  if (valid_object ())
michael@7862
  2076
    {
michael@7862
  2077
      graphics_object parent_obj = gh_manager::get_object (get_parent ());
michael@7862
  2078
michael@7862
  2079
      if (parent_obj)
michael@7862
  2080
	parent_obj.update_axis_limits (axis_type);
michael@7862
  2081
    }
michael@7862
  2082
  else
michael@7862
  2083
    error ("base_graphics_object::update_axis_limits: invalid graphics object");
michael@7862
  2084
}
michael@7862
  2085
dbateman@8299
  2086
void
dbateman@8299
  2087
base_graphics_object::remove_all_listeners (void)
dbateman@8299
  2088
{
dbateman@8299
  2089
  Octave_map m = get (true).map_value ();
dbateman@8299
  2090
dbateman@8299
  2091
  for (Octave_map::const_iterator pa = m.begin (); pa != m.end (); pa++)
dbateman@8299
  2092
    {
dbateman@8299
  2093
      if (get_properties().has_property (pa->first))
dbateman@8299
  2094
	{
dbateman@8299
  2095
	  property p = get_properties ().get_property (pa->first);
dbateman@8299
  2096
dbateman@8299
  2097
	  if (! error_state && p.ok ())
dbateman@8299
  2098
	    p.delete_listener ();
dbateman@8299
  2099
	}
dbateman@8299
  2100
    }
dbateman@8299
  2101
}
dbateman@8299
  2102
michael@7862
  2103
// ---------------------------------------------------------------------
michael@7862
  2104
jwe@7363
  2105
#include "graphics-props.cc"
jwe@7363
  2106
jwe@7363
  2107
// ---------------------------------------------------------------------
jwe@7363
  2108
jwe@6836
  2109
void
jwe@7363
  2110
root_figure::properties::set_currentfigure (const octave_value& v)
jwe@6874
  2111
{
jwe@7378
  2112
  graphics_handle val (v);
jwe@7363
  2113
jwe@6874
  2114
  if (error_state)
jwe@6874
  2115
    return;
jwe@6874
  2116
jwe@7059
  2117
  if (xisnan (val.value ()) || is_handle (val))
jwe@6874
  2118
    {
jwe@6874
  2119
      currentfigure = val;
jwe@6874
  2120
jwe@7363
  2121
      gh_manager::push_figure (val);
jwe@6874
  2122
    }
jwe@6874
  2123
  else
jwe@6874
  2124
    gripe_set_invalid ("currentfigure");
jwe@6874
  2125
}
jwe@6874
  2126
michael@7822
  2127
void
michael@7822
  2128
root_figure::properties::set_callbackobject (const octave_value& v)
michael@7822
  2129
{
michael@7822
  2130
  graphics_handle val (v);
michael@7822
  2131
michael@7822
  2132
  if (error_state)
michael@7822
  2133
    return;
michael@7822
  2134
michael@7822
  2135
  if (xisnan (val.value ()))
michael@7822
  2136
    {
michael@7822
  2137
      if (! cbo_stack.empty ())
michael@7822
  2138
	{
michael@7822
  2139
	  val = cbo_stack.front ();
michael@7822
  2140
michael@7822
  2141
	  cbo_stack.pop_front ();
michael@7822
  2142
	}
michael@7822
  2143
michael@7822
  2144
      callbackobject = val;
michael@7822
  2145
    }
michael@7822
  2146
  else if (is_handle (val))
michael@7822
  2147
    {
michael@7822
  2148
      if (get_callbackobject ().ok ())
michael@7822
  2149
	cbo_stack.push_front (get_callbackobject ());
michael@7822
  2150
michael@7822
  2151
      callbackobject = val;
michael@7822
  2152
    }
michael@7822
  2153
  else
michael@7822
  2154
    gripe_set_invalid ("callbackobject");
michael@7822
  2155
}
michael@7822
  2156
jwe@8059
  2157
void
jwe@8560
  2158
root_figure::properties::update_units (void)
jwe@8560
  2159
{
jwe@8560
  2160
  caseless_str xunits = get_units ();
jwe@8560
  2161
jwe@8560
  2162
  Matrix ss = default_screensize ();
jwe@8560
  2163
jwe@8560
  2164
  double dpi = get_screenpixelsperinch ();
jwe@8560
  2165
jwe@8560
  2166
  if (xunits.compare ("inches"))
jwe@8560
  2167
    {
jwe@8560
  2168
      ss(0) = 0;
jwe@8560
  2169
      ss(1) = 0;
jwe@8560
  2170
      ss(2) /= dpi;
jwe@8560
  2171
      ss(3) /= dpi;
jwe@8560
  2172
    }
jwe@8560
  2173
  else if (xunits.compare ("centimeters"))
jwe@8560
  2174
    {
jwe@8560
  2175
      ss(0) = 0;
jwe@8560
  2176
      ss(1) = 0;
jwe@8560
  2177
      ss(2) *= 2.54 / dpi;
jwe@8560
  2178
      ss(3) *= 2.54 / dpi;
jwe@8560
  2179
    }
jwe@8560
  2180
  else if (xunits.compare ("normalized"))
jwe@8560
  2181
    {
jwe@8560
  2182
      ss = Matrix (1, 4, 1.0);
jwe@8560
  2183
    }
jwe@8560
  2184
  else if (xunits.compare ("points"))
jwe@8560
  2185
    {
jwe@8560
  2186
      ss(0) = 0;
jwe@8560
  2187
      ss(1) = 0;
jwe@8560
  2188
      ss(2) *= 72 / dpi;
jwe@8560
  2189
      ss(3) *= 72 / dpi;
jwe@8560
  2190
    }
jwe@8560
  2191
jwe@8560
  2192
  set_screensize (ss);
jwe@8560
  2193
}
jwe@8560
  2194
jwe@8560
  2195
void
jwe@8059
  2196
root_figure::properties::remove_child (const graphics_handle& gh)
jwe@8059
  2197
{
jwe@8059
  2198
  gh_manager::pop_figure (gh);
jwe@8059
  2199
jwe@8059
  2200
  graphics_handle cf = gh_manager::current_figure ();
jwe@8059
  2201
jwe@8059
  2202
  xset (0, "currentfigure", cf.value ());
jwe@8059
  2203
  
jwe@8059
  2204
  base_properties::remove_child (gh);
jwe@8059
  2205
}
jwe@8059
  2206
jwe@6406
  2207
property_list
jwe@6406
  2208
root_figure::factory_properties = root_figure::init_factory_properties ();
jwe@6406
  2209
jwe@6406
  2210
// ---------------------------------------------------------------------
jwe@6406
  2211
jwe@7363
  2212
void
jwe@7363
  2213
figure::properties::set_currentaxes (const octave_value& v)
jwe@7363
  2214
{
jwe@7378
  2215
  graphics_handle val (v);
jwe@6705
  2216
jwe@6874
  2217
  if (error_state)
jwe@6874
  2218
    return;
jwe@6874
  2219
jwe@7070
  2220
  if (xisnan (val.value ()) || is_handle (val))
jwe@6874
  2221
    currentaxes = val;
jwe@6874
  2222
  else
jwe@6874
  2223
    gripe_set_invalid ("currentaxes");
jwe@6874
  2224
}
jwe@6874
  2225
jwe@6874
  2226
void
jwe@8266
  2227
figure::properties::remove_child (const graphics_handle& gh)
jwe@8266
  2228
{
jwe@8266
  2229
  base_properties::remove_child (gh);
jwe@8266
  2230
jwe@8266
  2231
  if (gh == currentaxes.handle_value ())
jwe@8266
  2232
    {
jwe@8266
  2233
      graphics_handle new_currentaxes;
jwe@8266
  2234
jwe@8266
  2235
      for (octave_idx_type i = 0; i < children.numel (); i++)
jwe@8266
  2236
	{
jwe@8266
  2237
	  graphics_handle kid = children(i);
jwe@8266
  2238
jwe@8266
  2239
	  graphics_object go = gh_manager::get_object (kid);
jwe@8266
  2240
jwe@8266
  2241
	  if (go.isa ("axes"))
jwe@8266
  2242
	    {
jwe@8266
  2243
	      new_currentaxes = kid;
jwe@8266
  2244
	      break;
jwe@8266
  2245
	    }
jwe@8266
  2246
	}
jwe@8266
  2247
jwe@8266
  2248
      currentaxes = new_currentaxes;
jwe@8266
  2249
    }
jwe@8266
  2250
}
jwe@8266
  2251
jwe@8266
  2252
void
jwe@6874
  2253
figure::properties::set_visible (const octave_value& val)
jwe@6874
  2254
{
jwe@6874
  2255
  std::string s = val.string_value ();
jwe@6874
  2256
jwe@6874
  2257
  if (! error_state)
jwe@6874
  2258
    {
jwe@6874
  2259
      if (s == "on")
jwe@6874
  2260
	xset (0, "currentfigure", __myhandle__.value ());
jwe@6874
  2261
jwe@6874
  2262
      visible = val;
jwe@6874
  2263
    }
jwe@6874
  2264
}
jwe@6874
  2265
jwe@7445
  2266
Matrix
jwe@7447
  2267
figure::properties::get_boundingbox (bool) const
jwe@7445
  2268
{
michael@9238
  2269
  Matrix screen_size = xget (0, "screensize").matrix_value ().extract_n (0, 2, 1, 2);
jwe@7445
  2270
  Matrix pos;
jwe@7445
  2271
jwe@7445
  2272
  pos = convert_position (get_position ().matrix_value (), get_units (),
michael@9238
  2273
			  "pixels", screen_size);
jwe@7445
  2274
jwe@7445
  2275
  pos(0)--;
jwe@7445
  2276
  pos(1)--;
jwe@7447
  2277
  pos(1) = screen_size(1) - pos(1) - pos(3);
jwe@7445
  2278
jwe@7445
  2279
  return pos;
jwe@7445
  2280
}
jwe@7445
  2281
michael@7828
  2282
void
michael@7828
  2283
figure::properties::set_boundingbox (const Matrix& bb)
michael@7828
  2284
{
michael@9238
  2285
  Matrix screen_size = xget (0, "screensize").matrix_value ().extract_n (0, 2, 1, 2);
michael@7828
  2286
  Matrix pos = bb;
michael@7828
  2287
michael@7828
  2288
  pos(1) = screen_size(1) - pos(1) - pos(3);
michael@7828
  2289
  pos(1)++;
michael@7828
  2290
  pos(0)++;
michael@9238
  2291
  pos = convert_position (pos, "pixels", get_units (), screen_size);
michael@7828
  2292
michael@7828
  2293
  set_position (pos);
michael@7828
  2294
}
michael@7828
  2295
michael@7828
  2296
void
michael@7828
  2297
figure::properties::set_position (const octave_value& v)
michael@7828
  2298
{
michael@7828
  2299
  if (! error_state)
michael@7828
  2300
    {
michael@7828
  2301
      Matrix old_bb, new_bb;
michael@7828
  2302
michael@7828
  2303
      old_bb = get_boundingbox ();
michael@7828
  2304
      position = v;
michael@7828
  2305
      new_bb = get_boundingbox ();
michael@7828
  2306
michael@7828
  2307
      if (old_bb != new_bb)
michael@7828
  2308
	{
michael@7828
  2309
	  if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
michael@7828
  2310
	    {
michael@7828
  2311
	      execute_resizefcn ();
michael@7828
  2312
	      update_boundingbox ();
michael@7828
  2313
	    }
michael@7828
  2314
	}
michael@7828
  2315
michael@7828
  2316
      mark_modified ();
michael@7828
  2317
    }
michael@7828
  2318
}
michael@7828
  2319
jwe@8059
  2320
std::string
jwe@8059
  2321
figure::properties::get_title (void) const
jwe@8059
  2322
{
jwe@8059
  2323
  if (is_numbertitle ())
jwe@8059
  2324
    {
jwe@8059
  2325
      std::ostringstream os;
jwe@8062
  2326
      std::string nm = get_name ();
jwe@8059
  2327
jwe@8059
  2328
      os << "Figure " << __myhandle__.value ();
jwe@8062
  2329
      if (! nm.empty ())
jwe@8059
  2330
	os << ": " << get_name ();
jwe@8059
  2331
jwe@8059
  2332
      return os.str ();
jwe@8059
  2333
    }
jwe@8059
  2334
  else
jwe@8059
  2335
    return get_name ();
jwe@8059
  2336
}
jwe@8059
  2337
jwe@6836
  2338
octave_value
dbateman@7189
  2339
figure::get_default (const caseless_str& name) const
jwe@6836
  2340
{
jwe@6836
  2341
  octave_value retval = default_properties.lookup (name);
jwe@6836
  2342
jwe@6836
  2343
  if (retval.is_undefined ())
jwe@6836
  2344
    {
jwe@6836
  2345
      graphics_handle parent = get_parent ();
jwe@6836
  2346
      graphics_object parent_obj = gh_manager::get_object (parent);
jwe@6836
  2347
jwe@6836
  2348
      retval = parent_obj.get_default (name);
jwe@6836
  2349
    }
jwe@6836
  2350
jwe@6836
  2351
  return retval;
jwe@6836
  2352
}
jwe@6836
  2353
jwe@6406
  2354
// ---------------------------------------------------------------------
jwe@6406
  2355
jwe@8249
  2356
void
jwe@8249
  2357
axes::properties::init (void)
jwe@8249
  2358
{
jwe@8249
  2359
  position.add_constraint (dim_vector (1, 4));
jwe@8249
  2360
  position.add_constraint (dim_vector (0, 0));
jwe@8249
  2361
  outerposition.add_constraint (dim_vector (1, 4));
jwe@8249
  2362
  colororder.add_constraint (dim_vector (-1, 3));
jwe@8249
  2363
  dataaspectratio.add_constraint (dim_vector (1, 3));
jwe@8249
  2364
  plotboxaspectratio.add_constraint (dim_vector (1, 3));
jwe@8249
  2365
  xlim.add_constraint (2);
jwe@8249
  2366
  ylim.add_constraint (2);
jwe@8249
  2367
  zlim.add_constraint (2);
jwe@8249
  2368
  clim.add_constraint (2);
jwe@8249
  2369
  alim.add_constraint (2);
jwe@8249
  2370
  xtick.add_constraint (dim_vector (1, -1));
jwe@8249
  2371
  ytick.add_constraint (dim_vector (1, -1));
jwe@8249
  2372
  ztick.add_constraint (dim_vector (1, -1));
jwe@8249
  2373
  Matrix vw (1, 2, 0);
jwe@8249
  2374
  vw(1) = 90;
jwe@8249
  2375
  view = vw;
jwe@8249
  2376
  view.add_constraint (dim_vector (1, 2));
jwe@8249
  2377
  cameraposition.add_constraint (dim_vector (1, 3));
jwe@8249
  2378
  Matrix upv (1, 3, 0.0);
jwe@8249
  2379
  upv(2) = 1.0;
jwe@8249
  2380
  cameraupvector = upv;
jwe@8249
  2381
  cameraupvector.add_constraint (dim_vector (1, 3));
jwe@8249
  2382
  currentpoint.add_constraint (dim_vector (2, 3));
jwe@8249
  2383
  ticklength.add_constraint (dim_vector (1, 2));
jwe@8249
  2384
  tightinset.add_constraint (dim_vector (1, 4));
jwe@8249
  2385
jwe@8249
  2386
  x_zlim.resize (1, 2);
jwe@8557
  2387
jwe@8249
  2388
  sx = "linear";
jwe@8249
  2389
  sy = "linear";
jwe@8249
  2390
  sz = "linear";
jwe@8249
  2391
jwe@8249
  2392
  xset (xlabel.handle_value (), "handlevisibility", "off");
jwe@8249
  2393
  xset (ylabel.handle_value (), "handlevisibility", "off");
jwe@8249
  2394
  xset (zlabel.handle_value (), "handlevisibility", "off");
jwe@8249
  2395
  xset (title.handle_value (), "handlevisibility", "off");
jwe@8249
  2396
jwe@8557
  2397
  xset (xlabel.handle_value (), "horizontalalignment", "center");
jwe@8557
  2398
  xset (ylabel.handle_value (), "horizontalalignment", "center");
jwe@8557
  2399
  xset (zlabel.handle_value (), "horizontalalignment", "right");
jwe@8557
  2400
  xset (title.handle_value (), "horizontalalignment", "center");
jwe@8557
  2401
jwe@8557
  2402
  xset (xlabel.handle_value (), "verticalalignment", "cap");
jwe@8557
  2403
  xset (ylabel.handle_value (), "verticalalignment", "bottom");
jwe@8557
  2404
  xset (title.handle_value (), "verticalalignment", "bottom");
jwe@8557
  2405
jwe@8557
  2406
  xset (ylabel.handle_value (), "rotation", 90.0);
jwe@8557
  2407
jwe@8249
  2408
  adopt (xlabel.handle_value ());
jwe@8249
  2409
  adopt (ylabel.handle_value ());
jwe@8249
  2410
  adopt (zlabel.handle_value ());
jwe@8249
  2411
  adopt (title.handle_value ());
jwe@8249
  2412
}
jwe@8249
  2413
shaiay@7860
  2414
void 
shaiay@7860
  2415
axes::properties::sync_positions (void)
shaiay@7860
  2416
{
jwe@8208
  2417
#if 0
shaiay@7860
  2418
  // FIXME -- this should take font metrics into consideration,
jwe@8208
  2419
  // and also the fact that the colorbox leaves the outerposition
jwe@8208
  2420
  // alone but alters the position. For now just don't adjust the
jwe@8208
  2421
  // positions relative to each other.
jwe@8208
  2422
shaiay@7860
  2423
  if (activepositionproperty.is ("outerposition"))
shaiay@7860
  2424
    {
shaiay@7860
  2425
      Matrix outpos = outerposition.get ().matrix_value ();
shaiay@7860
  2426
      Matrix defpos = default_axes_position ();
shaiay@7860
  2427
      Matrix pos(outpos);
shaiay@7860
  2428
      pos(0) = outpos(0) + defpos(0) * outpos(2);
shaiay@7860
  2429
      pos(1) = outpos(1) + defpos(1) * outpos(3);
shaiay@7860
  2430
      pos(2) = outpos(2) * defpos(2);
shaiay@7860
  2431
      pos(3) = outpos(3) * defpos(3);
shaiay@7860
  2432
      position = pos;
shaiay@7860
  2433
    }
shaiay@7860
  2434
  else
shaiay@7860
  2435
    {
shaiay@7860
  2436
      Matrix pos = position.get ().matrix_value ();
shaiay@7860
  2437
      pos(0) -= pos(2)*0.05;
shaiay@7860
  2438
      pos(1) -= pos(3)*0.05;
shaiay@7860
  2439
      pos(2) *= 1.1;
shaiay@7860
  2440
      pos(3) *= 1.1;
shaiay@7860
  2441
      outerposition = pos;
shaiay@7860
  2442
    }
jwe@8208
  2443
#endif
shaiay@7860
  2444
shaiay@7860
  2445
  update_transform ();
shaiay@7860
  2446
}
shaiay@7860
  2447
jwe@7363
  2448
void
jwe@8249
  2449
axes::properties::set_text_child (handle_property& hp,
jwe@8249
  2450
				  const std::string& who,
jwe@8249
  2451
				  const octave_value& v)
jwe@6962
  2452
{
jwe@8249
  2453
  graphics_handle val = ::reparent (v, "set", who, __myhandle__, false);
jwe@6962
  2454
jwe@6874
  2455
  if (! error_state)
jwe@6874
  2456
    {
jwe@8249
  2457
      xset (val, "handlevisibility", "off");
jwe@8249
  2458
jwe@8249
  2459
      gh_manager::free (hp.handle_value ());
jwe@8249
  2460
jwe@8249
  2461
      base_properties::remove_child (hp.handle_value ());
jwe@8249
  2462
jwe@8249
  2463
      hp = val;
jwe@8249
  2464
jwe@8249
  2465
      adopt (hp.handle_value ());
jwe@6874
  2466
    }
jwe@6874
  2467
}
jwe@6874
  2468
jwe@6874
  2469
void
jwe@7363
  2470
axes::properties::set_xlabel (const octave_value& v)
jwe@6874
  2471
{
jwe@8249
  2472
  set_text_child (xlabel, "xlabel", v);
jwe@6874
  2473
}
jwe@6874
  2474
jwe@6874
  2475
void
jwe@7363
  2476
axes::properties::set_ylabel (const octave_value& v)
jwe@6874
  2477
{
jwe@8249
  2478
  set_text_child (ylabel, "ylabel", v);
jwe@6874
  2479
}
jwe@6874
  2480
jwe@6874
  2481
void
jwe@7363
  2482
axes::properties::set_zlabel (const octave_value& v)
jwe@6874
  2483
{
jwe@8249
  2484
  set_text_child (zlabel, "zlabel", v);
jwe@8249
  2485
}
jwe@8249
  2486
jwe@8249
  2487
void
jwe@8249
  2488
axes::properties::set_title (const octave_value& v)
jwe@8249
  2489
{
jwe@8249
  2490
  set_text_child (title, "title", v);
jwe@6874
  2491
}
jwe@6874
  2492
jwe@6874
  2493
void
jwe@6844
  2494
axes::properties::set_defaults (base_graphics_object& obj,
jwe@6890
  2495
				const std::string& mode)
jwe@6705
  2496
{
jwe@6705
  2497
  box = "on";
jwe@6705
  2498
  key = "off";
jwe@6705
  2499
  keybox = "off";
dbateman@8291
  2500
  keyreverse = "off";
jwe@7363
  2501
  keypos = 1.0;
jwe@6962
  2502
  colororder = default_colororder ();
jwe@6705
  2503
  dataaspectratio = Matrix (1, 3, 1.0);
jwe@6705
  2504
  dataaspectratiomode = "auto";
jwe@7363
  2505
  layer = "bottom";
jwe@6705
  2506
jwe@6705
  2507
  Matrix tlim (1, 2, 0.0);
jwe@6705
  2508
  tlim(1) = 1;
jwe@6705
  2509
  xlim = tlim;
jwe@6705
  2510
  ylim = tlim;
jwe@6705
  2511
  zlim = tlim;
jwe@6807
  2512
  
jwe@6807
  2513
  Matrix cl (1, 2, 0);
jwe@6807
  2514
  cl(1) = 1;
jwe@6807
  2515
  clim = cl;
jwe@6807
  2516
  
jwe@7363
  2517
  xlimmode = "auto";
jwe@7363
  2518
  ylimmode = "auto";
jwe@7363
  2519
  zlimmode = "auto";
jwe@7363
  2520
  climmode = "auto";
jwe@8208
  2521
jwe@6705
  2522
  xgrid = "off";
jwe@6705
  2523
  ygrid = "off";
jwe@6705
  2524
  zgrid = "off";
jwe@6705
  2525
  xminorgrid = "off";
jwe@6705
  2526
  yminorgrid = "off";
jwe@6705
  2527
  zminorgrid = "off";
jwe@6705
  2528
  xtick = Matrix ();
jwe@6705
  2529
  ytick = Matrix ();
jwe@6705
  2530
  ztick = Matrix ();
jwe@6705
  2531
  xtickmode = "auto";
jwe@6705
  2532
  ytickmode = "auto";
jwe@6705
  2533
  ztickmode = "auto";
jwe@6705
  2534
  xticklabel = "";
jwe@6705
  2535
  yticklabel = "";
jwe@6705
  2536
  zticklabel = "";
jwe@6705
  2537
  xticklabelmode = "auto";
jwe@6705
  2538
  yticklabelmode = "auto";
jwe@6705
  2539
  zticklabelmode = "auto";
jwe@7453
  2540
  color = color_values (1, 1, 1);
jwe@7364
  2541
  xcolor = color_values ("black");
jwe@7364
  2542
  ycolor = color_values ("black");
jwe@7364
  2543
  zcolor = color_values ("black");
jwe@7363
  2544
  xscale = "linear";
jwe@7363
  2545
  yscale = "linear";
jwe@7363
  2546
  zscale = "linear";
jwe@6705
  2547
  xdir = "normal";
jwe@6705
  2548
  ydir = "normal";
jwe@6705
  2549
  zdir = "normal";
jwe@7363
  2550
  yaxislocation = "left";
jwe@7363
  2551
  xaxislocation = "bottom";
jwe@6705
  2552
jwe@7427
  2553
  // Note: camera properties will be set through update_transform
jwe@7427
  2554
  camerapositionmode = "auto";
jwe@7427
  2555
  cameratargetmode = "auto";
jwe@7427
  2556
  cameraupvectormode = "auto";
jwe@7427
  2557
  cameraviewanglemode = "auto";
jwe@7427
  2558
  plotboxaspectratio = Matrix (1, 3, 1.0);
jwe@7427
  2559
  drawmode = "normal";
michael@7820
  2560
  gridlinestyle = ":";
jwe@7427
  2561
  linestyleorder = "-";
jwe@7427
  2562
  linewidth = 0.5;
michael@7820
  2563
  minorgridlinestyle = ":";
jwe@7427
  2564
  // Note: plotboxaspectratio will be set through update_aspectratiors
jwe@7427
  2565
  plotboxaspectratiomode = "auto";
jwe@7427
  2566
  projection = "orthographic";
jwe@7427
  2567
  tickdir = "in";
jwe@7427
  2568
  tickdirmode = "auto";
bpabbott@8740
  2569
  ticklength = default_axes_ticklength ();
jwe@7427
  2570
  tightinset = Matrix (1, 4, 0.0);
jwe@7427
  2571
jwe@7427
  2572
  sx = "linear";
jwe@7427
  2573
  sy = "linear";
jwe@7427
  2574
  sz = "linear";
jwe@7427
  2575
jwe@6705
  2576
  Matrix tview (1, 2, 0.0);
jwe@6705
  2577
  tview(1) = 90;
jwe@6705
  2578
  view = tview;
jwe@6705
  2579
jwe@6765
  2580
  visible = "on";
jwe@6705
  2581
  nextplot = "replace";
jwe@6705
  2582
jwe@6705
  2583
  if (mode != "replace")
jwe@6705
  2584
    {
dbateman@8228
  2585
      fontangle = "normal";
jwe@8944
  2586
      fontname = OCTAVE_DEFAULT_FONTNAME;
dbateman@8228
  2587
      fontsize = 12;
dbateman@8228
  2588
      fontunits = "points";
dbateman@8228
  2589
      fontweight = "normal";
dbateman@8228
  2590
jwe@6406
  2591
      Matrix touterposition (1, 4, 0.0);
jwe@6406
  2592
      touterposition(2) = 1;
jwe@6406
  2593
      touterposition(3) = 1;
jwe@6406
  2594
      outerposition = touterposition;
shaiay@7860
  2595
shaiay@7860
  2596
      position = default_axes_position ();
dbateman@8228
  2597
dbateman@8228
  2598
      activepositionproperty = "outerposition";
jwe@6406
  2599
    }
jwe@6406
  2600
jwe@6705
  2601
  delete_children ();
jwe@6406
  2602
jwe@6705
  2603
  children = Matrix ();
jwe@6705
  2604
jwe@8249
  2605
  xlabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
jwe@8249
  2606
  ylabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
jwe@8249
  2607
  zlabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
jwe@8249
  2608
  title = gh_manager::make_graphics_handle ("text", __myhandle__, false);
jwe@8249
  2609
jwe@8249
  2610
  xset (xlabel.handle_value (), "handlevisibility", "off");
jwe@8249
  2611
  xset (ylabel.handle_value (), "handlevisibility", "off");
jwe@8249
  2612
  xset (zlabel.handle_value (), "handlevisibility", "off");
jwe@8249
  2613
  xset (title.handle_value (), "handlevisibility", "off");
jwe@8249
  2614
jwe@8636
  2615
  xset (xlabel.handle_value (), "horizontalalignment", "center");
jwe@8636
  2616
  xset (ylabel.handle_value (), "horizontalalignment", "center");
jwe@8636
  2617
  xset (zlabel.handle_value (), "horizontalalignment", "right");
jwe@8636
  2618
  xset (title.handle_value (), "horizontalalignment", "center");
jwe@8636
  2619
jwe@8636
  2620
  xset (xlabel.handle_value (), "verticalalignment", "cap");
jwe@8636
  2621
  xset (ylabel.handle_value (), "verticalalignment", "bottom");
jwe@8636
  2622
  xset (title.handle_value (), "verticalalignment", "bottom");
jwe@8636
  2623
jwe@8636
  2624
  xset (ylabel.handle_value (), "rotation", 90.0);
jwe@8636
  2625
jwe@8249
  2626
  adopt (xlabel.handle_value ());
jwe@8249
  2627
  adopt (ylabel.handle_value ());
jwe@8249
  2628
  adopt (zlabel.handle_value ());
jwe@8249
  2629
  adopt (title.handle_value ());
jwe@8249
  2630
jwe@7427
  2631
  update_transform ();
jwe@7427
  2632
jwe@6705
  2633
  override_defaults (obj);
jwe@6705
  2634
}
jwe@6705
  2635
jwe@8208
  2636
void
jwe@8208
  2637
axes::properties::delete_text_child (handle_property& hp)
jwe@6874
  2638
{
jwe@8208
  2639
  graphics_handle h = hp.handle_value ();
jwe@8208
  2640
jwe@8208
  2641
  if (h.ok ())
jwe@8208
  2642
    {
jwe@8208
  2643
      graphics_object go = gh_manager::get_object (h);
jwe@8208
  2644
jwe@8208
  2645
      if (go.valid_object ())
jwe@8208
  2646
	gh_manager::free (h);
jwe@8249
  2647
jwe@8249
  2648
      base_properties::remove_child (h);
jwe@8208
  2649
    }
jwe@8208
  2650
jwe@8249
  2651
  // FIXME -- is it necessary to check whether the axes object is
jwe@8249
  2652
  // being deleted now?  I think this function is only called when an
jwe@8249
  2653
  // individual child object is delete and not when the parent axes
jwe@8249
  2654
  // object is deleted.
jwe@8249
  2655
jwe@8208
  2656
  if (! is_beingdeleted ())
jwe@8249
  2657
    {
jwe@8249
  2658
      hp = gh_manager::make_graphics_handle ("text", __myhandle__, false);
jwe@8249
  2659
jwe@8249
  2660
      xset (hp.handle_value (), "handlevisibility", "off");
jwe@8249
  2661
jwe@8249
  2662
      adopt (hp.handle_value ());
jwe@8249
  2663
    }
jwe@6705
  2664
}
jwe@6406
  2665
jwe@6705
  2666
void
jwe@6844
  2667
axes::properties::remove_child (const graphics_handle& h)
jwe@6705
  2668
{
jwe@8249
  2669
  if (xlabel.handle_value ().ok () && h == xlabel.handle_value ())
jwe@8208
  2670
    delete_text_child (xlabel);
jwe@7363
  2671
  else if (ylabel.handle_value ().ok () && h == ylabel.handle_value ())
jwe@8208
  2672
    delete_text_child (ylabel);
jwe@7363
  2673
  else if (zlabel.handle_value ().ok () && h == zlabel.handle_value ())
jwe@8208
  2674
    delete_text_child (zlabel);
jwe@8249
  2675
  else if (title.handle_value ().ok () && h == title.handle_value ())
jwe@8249
  2676
    delete_text_child (title);
jwe@6705
  2677
  else
jwe@6705
  2678
    base_properties::remove_child (h);
jwe@6705
  2679
}
jwe@6406
  2680
jwe@8249
  2681
Matrix
jwe@8249
  2682
base_properties::get_children (void) const
jwe@6705
  2683
{
jwe@8249
  2684
  Matrix retval = children;
jwe@8249
  2685
  
jwe@8249
  2686
  graphics_object go = gh_manager::get_object (0);
jwe@8249
  2687
jwe@8249
  2688
  root_figure::properties& props =
jwe@8249
  2689
      dynamic_cast<root_figure::properties&> (go.get_properties ());
jwe@8249
  2690
jwe@8249
  2691
  if (! props.is_showhiddenhandles ())
jwe@8249
  2692
    {
jwe@8249
  2693
      octave_idx_type k = 0;
jwe@8249
  2694
jwe@8249
  2695
      for (octave_idx_type i = 0; i < children.numel (); i++)
jwe@8249
  2696
	{
jwe@8249
  2697
	  graphics_handle kid = children (i);
jwe@8249
  2698
jwe@8249
  2699
	  if (gh_manager::is_handle_visible (kid))
jwe@8249
  2700
	    retval(k++) = children(i);
jwe@8249
  2701
	}
jwe@8249
  2702
jwe@8249
  2703
      retval.resize (k, 1);
jwe@8249
  2704
    }
jwe@8249
  2705
jwe@8249
  2706
  return retval;;
jwe@6705
  2707
}
jwe@6406
  2708
jwe@7427
  2709
inline Matrix
jwe@7427
  2710
xform_matrix (void)
jwe@7427
  2711
{
jwe@7427
  2712
  Matrix m (4, 4, 0.0);
jwe@7427
  2713
  for (int i = 0; i < 4; i++)
jwe@7427
  2714
    m(i,i) = 1;
jwe@7427
  2715
  return m;
jwe@7427
  2716
}
jwe@7427
  2717
jwe@7427
  2718
inline ColumnVector
jwe@7427
  2719
xform_vector (void)
jwe@7427
  2720
{
jwe@7427
  2721
  ColumnVector v (4, 0.0);
jwe@7427
  2722
  v(3) = 1;
jwe@7427
  2723
  return v;
jwe@7427
  2724
}
jwe@7427
  2725
jwe@7427
  2726
inline ColumnVector
jwe@7427
  2727
xform_vector (double x, double y, double z)
jwe@7427
  2728
{
jwe@7427
  2729
  ColumnVector v (4, 1.0);
jwe@7427
  2730
  v(0) = x; v(1) = y; v(2) = z;
jwe@7427
  2731
  return v;
jwe@7427
  2732
}
jwe@7427
  2733
jwe@7427
  2734
inline ColumnVector
jwe@7427
  2735
transform (const Matrix& m, double x, double y, double z)
jwe@7427
  2736
{
jwe@7427
  2737
  return (m * xform_vector (x, y, z));
jwe@7427
  2738
}
jwe@7427
  2739
jwe@7427
  2740
inline Matrix
jwe@7427
  2741
xform_scale (double x, double y, double z)
jwe@7427
  2742
{
jwe@7427
  2743
  Matrix m (4, 4, 0.0);
jwe@7427
  2744
  m(0,0) = x; m(1,1) = y; m(2,2) = z; m(3,3) = 1;
jwe@7427
  2745
  return m;
jwe@7427
  2746
}
jwe@7427
  2747
jwe@7427
  2748
inline Matrix
jwe@7427
  2749
xform_translate (double x, double y, double z)
jwe@7427
  2750
{
jwe@7427
  2751
  Matrix m = xform_matrix ();
jwe@7427
  2752
  m(0,3) = x; m(1,3) = y; m(2,3) = z; m(3,3) = 1;
jwe@7427
  2753
  return m;
jwe@7427
  2754
}
jwe@7427
  2755
jwe@7427
  2756
inline void
jwe@7427
  2757
scale (Matrix& m, double x, double y, double z)
jwe@7427
  2758
{
jwe@7427
  2759
  m = m * xform_scale (x, y, z);
jwe@7427
  2760
}
jwe@7427
  2761
jwe@7427
  2762
inline void
jwe@7427
  2763
translate (Matrix& m, double x, double y, double z)
jwe@7427
  2764
{
jwe@7427
  2765
  m = m * xform_translate (x, y, z);
jwe@7427
  2766
}
jwe@7427
  2767
jwe@7427
  2768
inline void
jwe@7427
  2769
xform (ColumnVector& v, const Matrix& m)
jwe@7427
  2770
{
jwe@7427
  2771
  v = m*v;
jwe@7427
  2772
}
jwe@7427
  2773
jwe@7427
  2774
inline void
jwe@7427
  2775
scale (ColumnVector& v, double x, double y, double z)
jwe@7427
  2776
{
jwe@7427
  2777
  v(0) *= x;
jwe@7427
  2778
  v(1) *= y;
jwe@7427
  2779
  v(2) *= z;
jwe@7427
  2780
}
jwe@7427
  2781
jwe@7427
  2782
inline void
jwe@7427
  2783
translate (ColumnVector& v, double x, double y, double z)
jwe@7427
  2784
{
jwe@7427
  2785
  v(0) += x;
jwe@7427
  2786
  v(1) += y;
jwe@7427
  2787
  v(2) += z;
jwe@7427
  2788
}
jwe@7427
  2789
jwe@7427
  2790
inline void
jwe@7427
  2791
normalize (ColumnVector& v)
jwe@7427
  2792
{
jwe@7427
  2793
  double fact = 1.0/sqrt(v(0)*v(0)+v(1)*v(1)+v(2)*v(2));
jwe@7427
  2794
  scale (v, fact, fact, fact);
jwe@7427
  2795
}
jwe@7427
  2796
jwe@7427
  2797
inline double
jwe@7427
  2798
dot (const ColumnVector& v1, const ColumnVector& v2)
jwe@7427
  2799
{
jwe@7427
  2800
  return (v1(0)*v2(0)+v1(1)*v2(1)+v1(2)*v2(2));
jwe@7427
  2801
}
jwe@7427
  2802
jwe@7427
  2803
inline double
jwe@7427
  2804
norm (const ColumnVector& v)
jwe@7427
  2805
{
jwe@7427
  2806
  return sqrt (dot (v, v));
jwe@7427
  2807
}
jwe@7427
  2808
jwe@7427
  2809
inline ColumnVector
jwe@7427
  2810
cross (const ColumnVector& v1, const ColumnVector& v2)
jwe@7427
  2811
{
jwe@7427
  2812
  ColumnVector r = xform_vector ();
jwe@7427
  2813
  r(0) = v1(1)*v2(2)-v1(2)*v2(1);
jwe@7427
  2814
  r(1) = v1(2)*v2(0)-v1(0)*v2(2);
jwe@7427
  2815
  r(2) = v1(0)*v2(1)-v1(1)*v2(0);
jwe@7427
  2816
  return r;
jwe@7427
  2817
}
jwe@7427
  2818
jwe@7427
  2819
inline Matrix
jwe@7427
  2820
unit_cube (void)
jwe@7427
  2821
{
jwe@7427
  2822
  static double data[32] = {
jwe@7427
  2823
      0,0,0,1,
jwe@7427
  2824
      1,0,0,1,
jwe@7427
  2825
      0,1,0,1,
jwe@7427
  2826
      0,0,1,1,
jwe@7427
  2827
      1,1,0,1,
jwe@7427
  2828
      1,0,1,1,
jwe@7427
  2829
      0,1,1,1,
jwe@7427
  2830
      1,1,1,1};
jwe@7427
  2831
  Matrix m (4, 8);
jwe@7427
  2832
  memcpy (m.fortran_vec (), data, sizeof(double)*32);
jwe@7427
  2833
  return m;
jwe@7427
  2834
}
jwe@7427
  2835
jwe@7427
  2836
inline ColumnVector
jwe@7427
  2837
cam2xform (const Array<double>& m)
jwe@7427
  2838
{
jwe@7427
  2839
  ColumnVector retval (4, 1.0);
jwe@7427
  2840
  memcpy (retval.fortran_vec (), m.fortran_vec (), sizeof(double)*3);
jwe@7427
  2841
  return retval;
jwe@7427
  2842
}
jwe@7427
  2843
jwe@7427
  2844
inline RowVector
jwe@7427
  2845
xform2cam (const ColumnVector& v)
jwe@7427
  2846
{
jwe@7427
  2847
  return v.extract_n (0, 3).transpose ();
jwe@7427
  2848
}
jwe@7427
  2849
jwe@7427
  2850
void
jwe@7427
  2851
axes::properties::update_camera (void)
jwe@7427
  2852
{
jwe@7427
  2853
  double xd = (xdir_is ("normal") ? 1 : -1);
jwe@7427
  2854
  double yd = (ydir_is ("normal") ? 1 : -1);
jwe@7427
  2855
  double zd = (zdir_is ("normal") ? 1 : -1);
jwe@7427
  2856
jwe@7526
  2857
  Matrix xlimits = sx.scale (get_xlim ().matrix_value ());
jwe@7526
  2858
  Matrix ylimits = sy.scale (get_ylim ().matrix_value ());
jwe@7526
  2859
  Matrix zlimits = sz.scale (get_zlim ().matrix_value ());
jwe@7526
  2860
jwe@7526
  2861
  double xo = xlimits(xd > 0 ? 0 : 1);
jwe@7526
  2862
  double yo = ylimits(yd > 0 ? 0 : 1);
jwe@7526
  2863
  double zo = zlimits(zd > 0 ? 0 : 1);
jwe@7427
  2864
  
jwe@7427
  2865
  Matrix pb  = get_plotboxaspectratio ().matrix_value ();
jwe@7427
  2866
  
jwe@7427
  2867
  bool autocam = (camerapositionmode_is ("auto")
jwe@7427
  2868
		  && cameratargetmode_is ("auto")
jwe@7427
  2869
	    	  && cameraupvectormode_is ("auto")
jwe@7427
  2870
		  && cameraviewanglemode_is ("auto"));
jwe@7427
  2871
  bool dowarp = (autocam && dataaspectratiomode_is("auto")
jwe@7427
  2872
		 && plotboxaspectratiomode_is ("auto"));
jwe@7427
  2873
jwe@7427
  2874
  ColumnVector c_eye (xform_vector ());
jwe@7427
  2875
  ColumnVector c_center (xform_vector ());
jwe@7427
  2876
  ColumnVector c_upv (xform_vector ());
jwe@7427
  2877
  
jwe@7427
  2878
  if (cameratargetmode_is ("auto"))
jwe@7427
  2879
    {
jwe@7526
  2880
      c_center(0) = (xlimits(0)+xlimits(1))/2;
jwe@7526
  2881
      c_center(1) = (ylimits(0)+ylimits(1))/2;
jwe@7526
  2882
      c_center(2) = (zlimits(0)+zlimits(1))/2;
jwe@7427
  2883
jwe@7427
  2884
      cameratarget = xform2cam (c_center);
jwe@7427
  2885
    }
jwe@7427
  2886
  else
jwe@7427
  2887
    c_center = cam2xform (get_cameratarget ().matrix_value ());
jwe@7427
  2888
  
jwe@7427
  2889
  if (camerapositionmode_is ("auto"))
jwe@7427
  2890
    {
jwe@7526
  2891
      Matrix tview = get_view ().matrix_value ();
jwe@7526
  2892
      double az = tview(0), el = tview(1);
jwe@7427
  2893
      double d = 5*sqrt(pb(0)*pb(0)+pb(1)*pb(1)+pb(2)*pb(2));
jwe@7427
  2894
jwe@7427
  2895
      if (el == 90 || el == -90)
jwe@7427
  2896
	c_eye(2) = d*signum(el);
jwe@7427
  2897
      else
jwe@7427
  2898
	{
jwe@7427
  2899
	  az *= M_PI/180.0;
jwe@7427
  2900
	  el *= M_PI/180.0;
jwe@7427
  2901
	  c_eye(0) = d*cos(el)*sin(az);
jwe@7427
  2902
	  c_eye(1) = -d*cos(el)*cos(az);
jwe@7427
  2903
	  c_eye(2) = d*sin(el);
jwe@7427
  2904
	}
jwe@7526
  2905
      c_eye(0) = c_eye(0)*(xlimits(1)-xlimits(0))/(xd*pb(0))+c_center(0);
jwe@7526
  2906
      c_eye(1) = c_eye(1)*(ylimits(1)-ylimits(0))/(yd*pb(1))+c_center(1);
jwe@7526
  2907
      c_eye(2) = c_eye(2)*(zlimits(1)-zlimits(0))/(zd*pb(2))+c_center(2);
jwe@7427
  2908
jwe@7427
  2909
      cameraposition = xform2cam (c_eye);
jwe@7427
  2910
    }
jwe@7427
  2911
  else
jwe@7427
  2912
    c_eye = cam2xform (get_cameraposition ().matrix_value ());
jwe@7427
  2913
jwe@7427
  2914
  if (cameraupvectormode_is ("auto"))
jwe@7427
  2915
    {
jwe@7526
  2916
      Matrix tview = get_view ().matrix_value ();
jwe@7526
  2917
      double az = tview(0), el = tview(1);
jwe@7427
  2918
jwe@7427
  2919
      if (el == 90 || el == -90)
jwe@7427
  2920
	{
jwe@7526
  2921
	  c_upv(0) = -sin(az*M_PI/180.0)*(xlimits(1)-xlimits(0))/pb(0);
jwe@7526
  2922
	  c_upv(1) = cos(az*M_PI/180.0)*(ylimits(1)-ylimits(0))/pb(1);
jwe@7427
  2923
	}
jwe@7427
  2924
      else
jwe@7427
  2925
	c_upv(2) = 1;
jwe@7427
  2926
jwe@7427
  2927
      cameraupvector = xform2cam (c_upv);
jwe@7427
  2928
    }
jwe@7427
  2929
  else
jwe@7427
  2930
    c_upv = cam2xform (get_cameraupvector ().matrix_value ());
jwe@7427
  2931
jwe@7427
  2932
  Matrix x_view = xform_matrix ();
jwe@7427
  2933
  Matrix x_projection = xform_matrix ();
jwe@7427
  2934
  Matrix x_viewport = xform_matrix ();
jwe@7427
  2935
  Matrix x_normrender = xform_matrix ();
jwe@7427
  2936
  Matrix x_pre = xform_matrix ();
jwe@7427
  2937
  
jwe@7427
  2938
  x_render = xform_matrix ();
jwe@7427
  2939
  x_render_inv = xform_matrix ();
jwe@7427
  2940
jwe@7427
  2941
  scale (x_pre, pb(0), pb(1), pb(2));
jwe@7427
  2942
  translate (x_pre, -0.5, -0.5, -0.5);
jwe@7526
  2943
  scale (x_pre, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
jwe@7526
  2944
	 zd/(zlimits(1)-zlimits(0)));
jwe@7427
  2945
  translate (x_pre, -xo, -yo, -zo);
jwe@7427
  2946
jwe@7427
  2947
  xform (c_eye, x_pre);
jwe@7427
  2948
  xform (c_center, x_pre);
jwe@7526
  2949
  scale (c_upv, pb(0)/(xlimits(1)-xlimits(0)), pb(1)/(ylimits(1)-ylimits(0)), 
jwe@7526
  2950
	 pb(2)/(zlimits(1)-zlimits(0)));
jwe@7427
  2951
  translate (c_center, -c_eye(0), -c_eye(1), -c_eye(2));
jwe@7427
  2952
jwe@7427
  2953
  ColumnVector F (c_center), f (F), UP (c_upv);
jwe@7427
  2954
  normalize (f);
jwe@7427
  2955
  normalize (UP);
jwe@7427
  2956
jwe@7440
  2957
  if (std::abs (dot (f, UP)) > 1e-15)
jwe@7427
  2958
    {
jwe@7427
  2959
      double fa = 1/sqrt(1-f(2)*f(2));
jwe@7427
  2960
      scale (UP, fa, fa, fa);
jwe@7427
  2961
    }
jwe@7427
  2962
jwe@7427
  2963
  ColumnVector s = cross (f, UP);
jwe@7427
  2964
  ColumnVector u = cross (s, f);
jwe@7427
  2965
jwe@7427
  2966
  scale (x_view, 1, 1, -1);
jwe@7427
  2967
  Matrix l = xform_matrix ();
jwe@7427
  2968
  l(0,0) = s(0); l(0,1) = s(1); l(0,2) = s(2);
jwe@7427
  2969
  l(1,0) = u(0); l(1,1) = u(1); l(1,2) = u(2);
jwe@7427
  2970
  l(2,0) = -f(0); l(2,1) = -f(1); l(2,2) = -f(2);
jwe@7427
  2971
  x_view = x_view * l;
jwe@7427
  2972
  translate (x_view, -c_eye(0), -c_eye(1), -c_eye(2));
jwe@7427
  2973
  scale (x_view, pb(0), pb(1), pb(2));
jwe@7427
  2974
  translate (x_view, -0.5, -0.5, -0.5);
jwe@7427
  2975
jwe@7427
  2976
  Matrix x_cube = x_view * unit_cube ();
jwe@7427
  2977
  ColumnVector cmin = x_cube.row_min (), cmax = x_cube.row_max ();
jwe@7427
  2978
  double xM = cmax(0)-cmin(0);
jwe@7427
  2979
  double yM = cmax(1)-cmin(1);
jwe@7427
  2980
jwe@7447
  2981
  Matrix bb = get_boundingbox (true);
jwe@7427
  2982
jwe@7427
  2983
  double v_angle;
jwe@7427
  2984
jwe@7427
  2985
  if (cameraviewanglemode_is ("auto"))
jwe@7427
  2986
    {
jwe@7427
  2987
      double af;
jwe@7427
  2988
jwe@8333
  2989
      // FIXME -- was this really needed?  When compared to Matlab, it
jwe@7427
  2990
      // does not seem to be required. Need investigation with concrete
jwe@7427
  2991
      // backend to see results visually.
jwe@7427
  2992
      if (false && dowarp)
jwe@7427
  2993
        af = 1.0 / (xM > yM ? xM : yM);
jwe@7427
  2994
      else
jwe@7427
  2995
        {
jwe@7427
  2996
          if ((bb(2)/bb(3)) > (xM/yM))
jwe@7427
  2997
            af = 1.0 / yM;
jwe@7427
  2998
          else
jwe@7427
  2999
            af = 1.0 / xM;
jwe@7427
  3000
        }
jwe@7427
  3001
      v_angle = 2 * (180.0 / M_PI) * atan (1 / (2 * af * norm (F)));
jwe@7427
  3002
jwe@7427
  3003
      cameraviewangle = v_angle;
jwe@7427
  3004
    }
jwe@7427
  3005
  else
jwe@7427
  3006
    v_angle = get_cameraviewangle ();
jwe@7427
  3007
jwe@7427
  3008
  double pf = 1 / (2 * tan ((v_angle / 2) * M_PI / 180.0) * norm (F));
jwe@7427
  3009
  scale (x_projection, pf, pf, 1);
jwe@7427
  3010
jwe@7427
  3011
  if (dowarp)
jwe@7427
  3012
    {
jwe@7427
  3013
      xM *= pf;
jwe@7427
  3014
      yM *= pf;
jwe@7447
  3015
      translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
jwe@7427
  3016
      scale (x_viewport, bb(2)/xM, -bb(3)/yM, 1);
jwe@7427
  3017
    }
jwe@7427
  3018
  else
jwe@7427
  3019
    {
jwe@7427
  3020
      double pix = 1;
jwe@7427
  3021
      if (autocam)
jwe@7427
  3022
	{
jwe@7427
  3023
	  if ((bb(2)/bb(3)) > (xM/yM))
jwe@7427
  3024
	    pix = bb(3);
jwe@7427
  3025
	  else
jwe@7427
  3026
	    pix = bb(2);
jwe@7427
  3027
	}
jwe@7427
  3028
      else
jwe@7427
  3029
	pix = (bb(2) < bb(3) ? bb(2) : bb(3));
jwe@7447
  3030
      translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
jwe@7427
  3031
      scale (x_viewport, pix, -pix, 1);
jwe@7427
  3032
    }
jwe@7427
  3033
jwe@7427
  3034
  x_normrender = x_viewport * x_projection * x_view;
jwe@7427
  3035
jwe@7427
  3036
  x_cube = x_normrender * unit_cube ();
jwe@7427
  3037
  cmin = x_cube.row_min ();
jwe@7427
  3038
  cmax = x_cube.row_max ();
jwe@7427
  3039
  x_zlim.resize (1, 2);
jwe@7427
  3040
  x_zlim(0) = cmin(2);
jwe@7427
  3041
  x_zlim(1) = cmax(2);
jwe@7427
  3042
jwe@7427
  3043
  x_render = x_normrender;
jwe@7526
  3044
  scale (x_render, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
jwe@7526
  3045
	 zd/(zlimits(1)-zlimits(0)));
jwe@7427
  3046
  translate (x_render, -xo, -yo, -zo);
jwe@7427
  3047
jwe@7427
  3048
  x_viewtransform = x_view;
jwe@7427
  3049
  x_projectiontransform = x_projection;
jwe@7427
  3050
  x_viewporttransform = x_viewport;
jwe@7427
  3051
  x_normrendertransform = x_normrender;
jwe@7427
  3052
  x_rendertransform = x_render;
jwe@7427
  3053
jwe@7427
  3054
  x_render_inv = x_render.inverse ();
jwe@7427
  3055
jwe@7427
  3056
  // Note: these matrices are a slight modified version of the regular
jwe@7427
  3057
  // matrices, more suited for OpenGL rendering (x_gl_mat1 => light
jwe@7427
  3058
  // => x_gl_mat2)
jwe@7427
  3059
  x_gl_mat1 = x_view;
jwe@7526
  3060
  scale (x_gl_mat1, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
jwe@7526
  3061
	 zd/(zlimits(1)-zlimits(0)));
jwe@7427
  3062
  translate (x_gl_mat1, -xo, -yo, -zo);
jwe@7427
  3063
  x_gl_mat2 = x_viewport * x_projection;
jwe@7427
  3064
}
jwe@7427
  3065
jwe@7427
  3066
void
jwe@7427
  3067
axes::properties::update_aspectratios (void)
jwe@7427
  3068
{
jwe@7526
  3069
  Matrix xlimits = get_xlim ().matrix_value ();
jwe@7526
  3070
  Matrix ylimits = get_ylim ().matrix_value ();
jwe@7526
  3071
  Matrix zlimits = get_zlim ().matrix_value ();
jwe@7526
  3072
jwe@7526
  3073
  double dx = (xlimits(1)-xlimits(0));
jwe@7526
  3074
  double dy = (ylimits(1)-ylimits(0));
jwe@7526
  3075
  double dz = (zlimits(1)-zlimits(0));
jwe@7427
  3076
jwe@7427
  3077
  if (dataaspectratiomode_is ("auto"))
jwe@7427
  3078
    {
jwe@7427
  3079
      double dmin = xmin (xmin (dx, dy), dz);
jwe@7427
  3080
      Matrix da (1, 3, 0.0);
jwe@7427
  3081
jwe@7427
  3082
      da(0) = dx/dmin;
jwe@7427
  3083
      da(1) = dy/dmin;
jwe@7427
  3084
      da(2) = dz/dmin;
jwe@7427
  3085
jwe@7427
  3086
      dataaspectratio = da;
jwe@7427
  3087
    }
jwe@7427
  3088
jwe@7427
  3089
  if (plotboxaspectratiomode_is ("auto"))
jwe@7427
  3090
    {
jwe@7427
  3091
      if (dataaspectratiomode_is ("auto"))
jwe@7427
  3092
	plotboxaspectratio = Matrix (1, 3, 1.0);
jwe@7427
  3093
      else
jwe@7427
  3094
	{
jwe@7427
  3095
	  Matrix da = get_dataaspectratio ().matrix_value ();
jwe@7427
  3096
	  Matrix pba (1, 3, 0.0);
jwe@7427
  3097
jwe@7427
  3098
	  pba(0) = dx/da(0);
jwe@7427
  3099
	  pba(1) = dy/da(1);
jwe@7427
  3100
	  pba(2) = dz/da(2);
jwe@7427
  3101
	}
jwe@7427
  3102
    }
jwe@7427
  3103
  
jwe@8333
  3104
  // FIXME -- if plotboxaspectratiomode is "manual", limits
jwe@8333
  3105
  // and/or dataaspectratio might be adapted.
jwe@7427
  3106
}
jwe@7427
  3107
jwe@7447
  3108
// The INTERNAL flag defines whether position or outerposition is used.
jwe@7447
  3109
jwe@7427
  3110
Matrix
jwe@7447
  3111
axes::properties::get_boundingbox (bool internal) const
jwe@7427
  3112
{
jwe@7447
  3113
  graphics_object obj = gh_manager::get_object (get_parent ());
jwe@7447
  3114
  Matrix parent_bb = obj.get_properties ().get_boundingbox (true);
jwe@7447
  3115
  Matrix pos = (internal ?
jwe@7447
  3116
		  get_position ().matrix_value ()
jwe@7447
  3117
		  : get_outerposition ().matrix_value ());
jwe@7447
  3118
jwe@7447
  3119
jwe@7447
  3120
  pos = convert_position (pos, get_units (), "pixels",
michael@9238
  3121
			  parent_bb.extract_n (0, 2, 1, 2));
jwe@7427
  3122
  pos(0)--;
jwe@7427
  3123
  pos(1)--;
jwe@7447
  3124
  pos(1) = parent_bb(3) - pos(1) - pos(3);
jwe@7427
  3125
jwe@7427
  3126
  return pos;
jwe@7427
  3127
}
jwe@7427
  3128
jwe@7435
  3129
ColumnVector
jwe@7435
  3130
graphics_xform::xform_vector (double x, double y, double z)
jwe@7869
  3131
{
jwe@7869
  3132
  return ::xform_vector (x, y, z);
jwe@7869
  3133
}
jwe@7435
  3134
jwe@7435
  3135
Matrix
jwe@7435
  3136
graphics_xform::xform_eye (void)
jwe@7869
  3137
{
jwe@7869
  3138
  return ::xform_matrix ();
jwe@7869
  3139
}
jwe@7435
  3140
jwe@7435
  3141
ColumnVector
jwe@7435
  3142
graphics_xform::transform (double x, double y, double z,
jwe@7435
  3143
			   bool use_scale) const
jwe@7435
  3144
{
jwe@7435
  3145
  if (use_scale)
jwe@7435
  3146
    {
jwe@7435
  3147
      x = sx.scale (x);
jwe@7435
  3148
      y = sy.scale (y);
jwe@7435
  3149
      z = sz.scale (z);
jwe@7435
  3150
    }
jwe@7435
  3151
jwe@7435
  3152
  return ::transform (xform, x, y, z);
jwe@7435
  3153
}
jwe@7435
  3154
jwe@7435
  3155
ColumnVector
jwe@7435
  3156
graphics_xform::untransform (double x, double y, double z,
jwe@7435
  3157
			     bool use_scale) const
jwe@7435
  3158
{
jwe@7435
  3159
  ColumnVector v = ::transform (xform_inv, x, y, z);
jwe@7435
  3160
jwe@7435
  3161
  if (use_scale)
jwe@7435
  3162
    {
jwe@7435
  3163
      v(0) = sx.unscale (v(0));
jwe@7435
  3164
      v(1) = sy.unscale (v(1));
jwe@7435
  3165
      v(2) = sz.unscale (v(2));
jwe@7435
  3166
    }
jwe@7435
  3167
jwe@7435
  3168
  return v;
jwe@7435
  3169
}
jwe@7435
  3170
jwe@6836
  3171
octave_value
dbateman@7189
  3172
axes::get_default (const caseless_str& name) const
jwe@6836
  3173
{
jwe@6836
  3174
  octave_value retval = default_properties.lookup (name);
jwe@6836
  3175
jwe@6836
  3176
  if (retval.is_undefined ())
jwe@6836
  3177
    {
jwe@6836
  3178
      graphics_handle parent = get_parent ();
jwe@6836
  3179
      graphics_object parent_obj = gh_manager::get_object (parent);
jwe@6836
  3180
jwe@6836
  3181
      retval = parent_obj.get_default (name);
jwe@6836
  3182
    }
jwe@6836
  3183
jwe@6836
  3184
  return retval;
jwe@6836
  3185
}
jwe@6836
  3186
jwe@8333
  3187
// FIXME -- remove.
jwe@8333
  3188
// FIXME -- maybe this should go into array_property class?
michael@7862
  3189
/*
michael@7836
  3190
static void
michael@7836
  3191
check_limit_vals (double& min_val, double& max_val, double& min_pos,
michael@7836
  3192
		  const array_property& data)
michael@7836
  3193
{
michael@7836
  3194
  double val = data.min_val ();
michael@7836
  3195
  if (! (xisinf (val) || xisnan (val)) && val < min_val)
michael@7836
  3196
    min_val = val;
michael@7836
  3197
  val = data.max_val ();
michael@7836
  3198
  if (! (xisinf (val) || xisnan (val)) && val > max_val)
michael@7836
  3199
    max_val = val;
michael@7836
  3200
  val = data.min_pos ();
michael@7836
  3201
  if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos)
michael@7836
  3202
    min_pos = val;
michael@7836
  3203
}
michael@7862
  3204
*/
michael@7862
  3205
michael@7862
  3206
static void
michael@7862
  3207
check_limit_vals (double& min_val, double& max_val, double& min_pos,
michael@7862
  3208
		  const octave_value& data)
michael@7862
  3209
{
michael@7862
  3210
  if (data.is_matrix_type ())
michael@7862
  3211
    {
michael@7862
  3212
      Matrix m = data.matrix_value ();
michael@7862
  3213
michael@7862
  3214
      if (! error_state && m.numel () == 3)
michael@7862
  3215
	{
michael@7862
  3216
	  double val;
michael@7862
  3217
michael@7862
  3218
	  val = m(0);
michael@7862
  3219
	  if (! (xisinf (val) || xisnan (val)) && val < min_val)
michael@7862
  3220
	    min_val = val;
michael@7862
  3221
michael@7862
  3222
	  val = m(1);
michael@7862
  3223
	  if (! (xisinf (val) || xisnan (val)) && val > max_val)
michael@7862
  3224
	    max_val = val;
michael@7862
  3225
michael@7862
  3226
	  val = m(2);
michael@7862
  3227
	  if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos)
michael@7862
  3228
	    min_pos = val;
michael@7862
  3229
	}
michael@7862
  3230
    }
michael@7862
  3231
}
michael@7836
  3232
shaiay@7827
  3233
// magform(x) Returns (a, b), where x = a * 10^b, a >= 1., and b is
shaiay@7827
  3234
// integral.
shaiay@7827
  3235
jwe@7869
  3236
static void
jwe@7869
  3237
magform (double x, double& a, int& b)
shaiay@7827
  3238
{
shaiay@7827
  3239
  if (x == 0)
shaiay@7827
  3240
    {
shaiay@7827
  3241
      a = 0;
shaiay@7827
  3242
      b = 0;
shaiay@7827
  3243
    }
shaiay@7827
  3244
  else
shaiay@7827
  3245
    {
shaiay@7827
  3246
      double l = std::log10 (std::abs (x));
shaiay@7827
  3247
      double r = std::fmod (l, 1.);
shaiay@7827
  3248
      a = std::pow (10.0, r);
shaiay@7827
  3249
      b = static_cast<int> (l-r);
shaiay@7827
  3250
      if (a < 1)
shaiay@7827
  3251
	{
shaiay@7827
  3252
	  a *= 10;
shaiay@7827
  3253
	  b -= 1;
shaiay@7827
  3254
	}
shaiay@7827
  3255
shaiay@7827
  3256
      if (x < 0)
shaiay@7827
  3257
	a = -a;
shaiay@7827
  3258
    }
shaiay@7827
  3259
}
shaiay@7827
  3260
shaiay@7827
  3261
// A translation from Tom Holoryd's python code at
shaiay@7827
  3262
// http://kurage.nimh.nih.gov/tomh/tics.py
shaiay@7827
  3263
// FIXME -- add log ticks
shaiay@7827
  3264
shaiay@7827
  3265
double
shaiay@7827
  3266
axes::properties::calc_tick_sep (double lo, double hi)
shaiay@7827
  3267
{
shaiay@7827
  3268
  int ticint = 5;
shaiay@7827
  3269
shaiay@7827
  3270
  // Reference: Lewart, C. R., "Algorithms SCALE1, SCALE2, and
shaiay@7827
  3271
  // SCALE3 for Determination of Scales on Computer Generated
shaiay@7827
  3272
  // Plots", Communications of the ACM, 10 (1973), 639-640.
shaiay@7827
  3273
  // Also cited as ACM Algorithm 463.
shaiay@7827
  3274
shaiay@7827
  3275
  double a;
shaiay@7827
  3276
  int b, x;
shaiay@7827
  3277
shaiay@7827
  3278
  magform ((hi-lo)/ticint, a, b);
shaiay@7827
  3279
shaiay@7827
  3280
  static const double sqrt_2 = sqrt (2.0);
shaiay@7827
  3281
  static const double sqrt_10 = sqrt (10.0);
shaiay@7827
  3282
  static const double sqrt_50 = sqrt (50.0);
shaiay@7827
  3283
shaiay@7827
  3284
  if (a < sqrt_2)
shaiay@7827
  3285
    x = 1;
shaiay@7827
  3286
  else if (a < sqrt_10)
shaiay@7827
  3287
    x = 2;
shaiay@7827
  3288
  else if (a < sqrt_50)
shaiay@7827
  3289
    x = 5;
shaiay@7827
  3290
  else
shaiay@7827
  3291
    x = 10;
shaiay@7827
  3292
shaiay@7827
  3293
  return x * std::pow (10., b);
shaiay@7827
  3294
shaiay@7827
  3295
}
shaiay@7827
  3296
jwe@7222
  3297
// Attempt to make "nice" limits from the actual max and min of the
jwe@7222
  3298
// data.  For log plots, we will also use the smallest strictly positive
jwe@7222
  3299
// value.
jwe@7222
  3300
shaiay@7827
  3301
Matrix
jwe@7869
  3302
axes::properties::get_axis_limits (double xmin, double xmax,
jwe@7869
  3303
				   double min_pos, bool logscale)
jwe@7222
  3304
{
jwe@7222
  3305
  Matrix retval;
jwe@7222
  3306
jwe@7222
  3307
  double min_val = xmin;
jwe@7222
  3308
  double max_val = xmax;
jwe@7222
  3309
jwe@7222
  3310
  if (! (xisinf (min_val) || xisinf (max_val)))
jwe@7222
  3311
    {
jwe@7222
  3312
      if (logscale)
jwe@7222
  3313
	{
jwe@7222
  3314
	  if (xisinf (min_pos))
jwe@7222
  3315
	    {
jwe@7222
  3316
	      // warning ("axis: logscale with no positive values to plot");
jwe@7222
  3317
	      return retval;
jwe@7222
  3318
	    }
jwe@7222
  3319
jwe@7222
  3320
	  if (min_val <= 0)
jwe@7222
  3321
	    {
jwe@7222
  3322
	      warning ("axis: omitting nonpositive data in log plot");
jwe@7222
  3323
	      min_val = min_pos;
jwe@7222
  3324
	    }
jwe@7222
  3325
	  // FIXME -- maybe this test should also be relative?
jwe@7222
  3326
	  if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
jwe@7222
  3327
	    {
jwe@7222
  3328
	      min_val *= 0.9;
jwe@7222
  3329
	      max_val *= 1.1;
jwe@7222
  3330
	    }
jwe@7222
  3331
	  min_val = pow (10, floor (log10 (min_val)));
jwe@7222
  3332
	  max_val = pow (10, ceil (log10 (max_val)));
jwe@7222
  3333
	}
jwe@7222
  3334
      else
jwe@7222
  3335
	{
jwe@7222
  3336
	  if (min_val == 0 && max_val == 0)
jwe@7222
  3337
	    {
jwe@7222
  3338
	      min_val = -1;
jwe@7222
  3339
	      max_val = 1;
jwe@7222
  3340
	    }
jwe@7222
  3341
	  // FIXME -- maybe this test should also be relative?
jwe@7222
  3342
	  else if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
jwe@7222
  3343
	    {
jwe@7222
  3344
	      min_val -= 0.1 * std::abs (min_val);
jwe@7222
  3345
	      max_val += 0.1 * std::abs (max_val);
jwe@7222
  3346
	    }
shaiay@7827
  3347
shaiay@7827
  3348
	  double tick_sep = calc_tick_sep (min_val , max_val);
shaiay@7827
  3349
	  min_val = tick_sep * std::floor (min_val / tick_sep);
shaiay@7827
  3350
	  max_val = tick_sep * ceil (max_val / tick_sep);
jwe@7222
  3351
	}
jwe@7222
  3352
    }
jwe@7222
  3353
jwe@7222
  3354
  retval.resize (1, 2);
jwe@7222
  3355
jwe@7222
  3356
  retval(0) = min_val;
jwe@7222
  3357
  retval(1) = max_val;
jwe@7222
  3358
jwe@7222
  3359
  return retval;
jwe@7222
  3360
}
jwe@7222
  3361
jwe@7446
  3362
void 
jwe@7869
  3363
axes::properties::calc_ticks_and_lims (array_property& lims,
jwe@7869
  3364
				       array_property& ticks,
jwe@7869
  3365
				       bool limmode_is_auto, bool is_logscale)
jwe@7446
  3366
{
shaiay@7827
  3367
  // FIXME -- add log ticks and lims
shaiay@7827
  3368
shaiay@7827
  3369
  if (lims.get ().is_empty ())
shaiay@7827
  3370
    return;
shaiay@7827
  3371
shaiay@7827
  3372
  double lo = (lims.get ().matrix_value ()) (0);
shaiay@7827
  3373
  double hi = (lims.get ().matrix_value ()) (1);
shaiay@7843
  3374
  // FIXME should this be checked for somewhere else? (i.e. set{x,y,z}lim)
shaiay@7843
  3375
  if (hi < lo) 
shaiay@7843
  3376
    {
shaiay@7843
  3377
      double tmp = hi;
shaiay@7843
  3378
      hi = lo;
shaiay@7843
  3379
      lo = tmp;
shaiay@7843
  3380
    }
shaiay@7857
  3381
shaiay@7857
  3382
  if (is_logscale)
shaiay@7857
  3383
    {
shaiay@7857
  3384
      // FIXME we should check for negtives here
shaiay@7857
  3385
      hi = std::log10 (hi);
shaiay@7857
  3386
      lo = std::log10 (lo);
shaiay@7857
  3387
    }
shaiay@7857
  3388
shaiay@7827
  3389
  double tick_sep = calc_tick_sep (lo , hi);
shaiay@7827
  3390
shaiay@7827
  3391
  int i1 = static_cast<int> (std::floor (lo / tick_sep));
shaiay@7827
  3392
  int i2 = static_cast<int> (std::ceil (hi / tick_sep));
shaiay@7827
  3393
shaiay@7827
  3394
  if (limmode_is_auto)
jwe@7446
  3395
    {
shaiay@7827
  3396
      // adjust limits to include min and max tics
shaiay@7827
  3397
      Matrix tmp_lims (1,2);
shaiay@7827
  3398
      tmp_lims(0) = tick_sep * i1;
shaiay@7827
  3399
      tmp_lims(1) = tick_sep * i2;
shaiay@7827
  3400
shaiay@7857
  3401
      if (is_logscale) 
shaiay@7857
  3402
	{
shaiay@7857
  3403
	  tmp_lims(0) = std::pow (10.,tmp_lims(0));
shaiay@7857
  3404
	  tmp_lims(1) = std::pow (10.,tmp_lims(1));
shaiay@7857
  3405
	}
shaiay@7827
  3406
      lims = tmp_lims;
jwe@7446
  3407
    }
jwe@7446
  3408
  else
jwe@7446
  3409
    {
shaiay@7827
  3410
      // adjust min and max tics if they are out of limits
shaiay@7827
  3411
      i1 = static_cast<int> (std::ceil (lo / tick_sep));
shaiay@7827
  3412
      i2 = static_cast<int> (std::floor (hi / tick_sep));
jwe@7446
  3413
    }
shaiay@7827
  3414
      
shaiay@7827
  3415
  Matrix tmp_ticks (1, i2-i1+1);
shaiay@7857
  3416
  for (int i = 0; i <= i2-i1; i++) 
shaiay@7857
  3417
    {
shaiay@7857
  3418
      tmp_ticks (i) = tick_sep * (i+i1);
shaiay@7857
  3419
      if (is_logscale)
shaiay@7857
  3420
	tmp_ticks (i) = std::pow (10., tmp_ticks (i));
shaiay@7857
  3421
    }
shaiay@7827
  3422
shaiay@7827
  3423
  ticks = tmp_ticks;
jwe@7446
  3424
}
jwe@7446
  3425
michael@7862
  3426
static void
michael@7862
  3427
get_children_limits (double& min_val, double& max_val, double& min_pos,
michael@7862
  3428
		     const Matrix& kids, char limit_type)
michael@7862
  3429
{
michael@7862
  3430
  octave_idx_type n = kids.numel ();
michael@7862
  3431
michael@7862
  3432
  switch (limit_type)
michael@7862
  3433
    {
michael@7862
  3434
    case 'x':
michael@7862
  3435
      for (octave_idx_type i = 0; i < n; i++)
michael@7862
  3436
	{
michael@7862
  3437
	  graphics_object obj = gh_manager::get_object (kids(i));
michael@7862
  3438
michael@7862
  3439
	  if (obj.is_xliminclude ())
michael@7862
  3440
	    {
michael@7862
  3441
	      octave_value lim = obj.get_xlim ();
michael@7862
  3442
michael@7862
  3443
	      check_limit_vals (min_val, max_val, min_pos, lim);
michael@7862
  3444
	    }
michael@7862
  3445
	}
michael@7862
  3446
      break;
michael@7862
  3447
michael@7862
  3448
    case 'y':
michael@7862
  3449
      for (octave_idx_type i = 0; i < n; i++)
michael@7862
  3450
	{
michael@7862
  3451
	  graphics_object obj = gh_manager::get_object (kids(i));
michael@7862
  3452
michael@7862
  3453
	  if (obj.is_yliminclude ())
michael@7862
  3454
	    {
michael@7862
  3455
	      octave_value lim = obj.get_ylim ();
michael@7862
  3456
michael@7862
  3457
	      check_limit_vals (min_val, max_val, min_pos, lim);
michael@7862
  3458
	    }
michael@7862
  3459
	}
michael@7862
  3460
      break;
michael@7862
  3461
    
michael@7862
  3462
    case 'z':
michael@7862
  3463
      for (octave_idx_type i = 0; i < n; i++)
michael@7862
  3464
	{
michael@7862
  3465
	  graphics_object obj = gh_manager::get_object (kids(i));
michael@7862
  3466
michael@7862
  3467
	  if (obj.is_zliminclude ())
michael@7862
  3468
	    {
michael@7862
  3469
	      octave_value lim = obj.get_zlim ();
michael@7862
  3470
michael@7862
  3471
	      check_limit_vals (min_val, max_val, min_pos, lim);
michael@7862
  3472
	    }
michael@7862
  3473
	}
michael@7862
  3474
      break;
michael@7862
  3475
    
michael@7862
  3476
    case 'c':
michael@7862
  3477
      for (octave_idx_type i = 0; i < n; i++)
michael@7862
  3478
	{
michael@7862
  3479
	  graphics_object obj = gh_manager::get_object (kids(i));
michael@7862
  3480
michael@7862
  3481
	  if (obj.is_climinclude ())
michael@7862
  3482
	    {
michael@7862
  3483
	      octave_value lim = obj.get_clim ();
michael@7862
  3484
michael@7862
  3485
	      check_limit_vals (min_val, max_val, min_pos, lim);
michael@7862
  3486
	    }
michael@7862
  3487
	}
michael@7862
  3488
      break;
michael@7862
  3489
    
michael@7862
  3490
    case 'a':
michael@7862
  3491
      for (octave_idx_type i = 0; i < n; i++)
michael@7862
  3492
	{
michael@7862
  3493
	  graphics_object obj = gh_manager::get_object (kids(i));
michael@7862
  3494
michael@7862
  3495
	  if (obj.is_aliminclude ())
michael@7862
  3496
	    {
michael@7862
  3497
	      octave_value lim = obj.get_alim ();
michael@7862
  3498
michael@7862
  3499
	      check_limit_vals (min_val, max_val, min_pos, lim);
michael@7862
  3500
	    }
michael@7862
  3501
	}
michael@7862
  3502
      break;
michael@7862
  3503
michael@7862
  3504
    default:
michael@7862
  3505
      break;
michael@7862
  3506
    }
michael@7862
  3507
}
michael@7862
  3508
jwe@7222
  3509
static bool updating_axis_limits = false;
jwe@7222
  3510
jwe@7214
  3511
void
jwe@7222
  3512
axes::update_axis_limits (const std::string& axis_type)
jwe@7214
  3513
{
jwe@7222
  3514
  if (updating_axis_limits)
jwe@7222
  3515
    return;
jwe@7222
  3516
jwe@7222
  3517
  Matrix kids = xproperties.get_children ();
jwe@7222
  3518
jwe@7222
  3519
  double min_val = octave_Inf;
jwe@7222
  3520
  double max_val = -octave_Inf;
jwe@7222
  3521
  double min_pos = octave_Inf;
jwe@7222
  3522
jwe@7222
  3523
  char update_type = 0;
jwe@7222
  3524
jwe@7222
  3525
  Matrix limits;
jwe@7222
  3526
jwe@7222
  3527
  if (axis_type == "xdata" || axis_type == "xscale"
jwe@7222
  3528
      || axis_type == "xldata" || axis_type == "xudata"
michael@7862
  3529
      || axis_type == "xlimmode" || axis_type == "xliminclude"
michael@7862
  3530
      || axis_type == "xlim")
jwe@7222
  3531
    {
jwe@7363
  3532
      if (xproperties.xlimmode_is ("auto"))
jwe@7222
  3533
	{
michael@7862
  3534
	  get_children_limits (min_val, max_val, min_pos, kids, 'x');
michael@7862
  3535
	  
shaiay@7827
  3536
	  limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
shaiay@7827
  3537
						xproperties.xscale_is ("log"));
jwe@7222
  3538
jwe@7222
  3539
	  update_type = 'x';
jwe@7222
  3540
	}
jwe@7222
  3541
    }
jwe@7222
  3542
  else if (axis_type == "ydata" || axis_type == "yscale"
jwe@7222
  3543
	   || axis_type == "ldata" || axis_type == "udata"
michael@7862
  3544
	   || axis_type == "ylimmode" || axis_type == "yliminclude"
michael@7862
  3545
	   || axis_type == "ylim")
jwe@7222
  3546
    {
jwe@7363
  3547
      if (xproperties.ylimmode_is ("auto"))
jwe@7222
  3548
	{
michael@7862
  3549
	  get_children_limits (min_val, max_val, min_pos, kids, 'y');
jwe@7222
  3550
shaiay@7827
  3551
	  limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
shaiay@7827
  3552
						xproperties.yscale_is ("log"));
jwe@7222
  3553
jwe@7222
  3554
	  update_type = 'y';
jwe@7222
  3555
	}
jwe@7222
  3556
    }
jwe@7222
  3557
  else if (axis_type == "zdata" || axis_type == "zscale"
michael@7862
  3558
	   || axis_type == "zlimmode" || axis_type == "zliminclude"
michael@7862
  3559
	   || axis_type == "zlim")
jwe@7222
  3560
    {
jwe@7363
  3561
      if (xproperties.zlimmode_is ("auto"))
jwe@7222
  3562
	{
michael@7862
  3563
	  get_children_limits (min_val, max_val, min_pos, kids, 'z');
jwe@7222
  3564
shaiay@7827
  3565
	  limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
shaiay@7827
  3566
						xproperties.zscale_is ("log"));
jwe@7222
  3567
jwe@7222
  3568
	  update_type = 'z';
jwe@7222
  3569
	}
jwe@7222
  3570
    }
michael@7862
  3571
  else if (axis_type == "cdata" || axis_type == "climmode"
michael@7862
  3572
	   || axis_type == "cdatamapping" || axis_type == "climinclude"
michael@7862
  3573
	   || axis_type == "clim")
jwe@7222
  3574
    {
jwe@7363
  3575
      if (xproperties.climmode_is ("auto"))
jwe@7222
  3576
	{
michael@7862
  3577
	  get_children_limits (min_val, max_val, min_pos, kids, 'c');
michael@7862
  3578
michael@7862
  3579
	  if (min_val > max_val)
jwe@7222
  3580
	    {
michael@7862
  3581
	      min_val = min_pos = 0;
michael@7862
  3582
	      max_val = 1;
jwe@7222
  3583
	    }
michael@7862
  3584
	  else if (min_val == max_val)
jwe@7222
  3585
	    max_val = min_val + 1;
jwe@7222
  3586
jwe@7222
  3587
	  limits.resize (1, 2);
jwe@7222
  3588
jwe@7222
  3589
	  limits(0) = min_val;
jwe@7222
  3590
	  limits(1) = max_val;
jwe@7222
  3591
jwe@7222
  3592
	  update_type = 'c';
jwe@7222
  3593
	}
jwe@7222
  3594
jwe@7222
  3595
    }
michael@7862
  3596
  else if (axis_type == "alphadata" || axis_type == "alimmode"
michael@7862
  3597
	   || axis_type == "alphadatamapping" || axis_type == "aliminclude"
michael@7862
  3598
	   || axis_type == "alim")
michael@7862
  3599
    {
michael@7862
  3600
      if (xproperties.alimmode_is ("auto"))
michael@7862
  3601
	{
michael@7862
  3602
	  get_children_limits (min_val, max_val, min_pos, kids, 'a');
michael@7862
  3603
michael@7862
  3604
	  if (min_val > max_val)
michael@7862
  3605
	    {
michael@7862
  3606
	      min_val = min_pos = 0;
michael@7862
  3607
	      max_val = 1;
michael@7862
  3608
	    }
michael@7862
  3609
	  else if (min_val == max_val)
michael@7862
  3610
	    max_val = min_val + 1;
michael@7862
  3611
michael@7862
  3612
	  limits.resize (1, 2);
michael@7862
  3613
michael@7862
  3614
	  limits(0) = min_val;
michael@7862
  3615
	  limits(1) = max_val;
michael@7862
  3616
michael@7862
  3617
	  update_type = 'a';
michael@7862
  3618
	}
michael@7862
  3619
michael@7862
  3620
    }
jwe@7222
  3621
jwe@7222
  3622
  unwind_protect_bool (updating_axis_limits);
jwe@7222
  3623
  updating_axis_limits = true;
jwe@7222
  3624
jwe@7222
  3625
  switch (update_type)
jwe@7222
  3626
    {
jwe@7222
  3627
    case 'x':
jwe@7222
  3628
      xproperties.set_xlim (limits);
jwe@7222
  3629
      xproperties.set_xlimmode ("auto");
jwe@7446
  3630
      xproperties.update_xlim ();
jwe@7222
  3631
      break;
jwe@7222
  3632
jwe@7222
  3633
    case 'y':
jwe@7222
  3634
      xproperties.set_ylim (limits);
jwe@7222
  3635
      xproperties.set_ylimmode ("auto");
jwe@7446
  3636
      xproperties.update_ylim ();
jwe@7222
  3637
      break;
jwe@7222
  3638
jwe@7222
  3639
    case 'z':
jwe@7222
  3640
      xproperties.set_zlim (limits);
jwe@7222
  3641
      xproperties.set_zlimmode ("auto");
jwe@7446
  3642
      xproperties.update_zlim ();
jwe@7222
  3643
      break;
jwe@7222
  3644
jwe@7222
  3645
    case 'c':
jwe@7222
  3646
      xproperties.set_clim (limits);
jwe@7222
  3647
      xproperties.set_climmode ("auto");
jwe@7222
  3648
      break;
jwe@7222
  3649
michael@7862
  3650
    case 'a':
michael@7862
  3651
      xproperties.set_alim (limits);
michael@7862
  3652
      xproperties.set_alimmode ("auto");
michael@7862
  3653
      break;
michael@7862
  3654
jwe@7222
  3655
    default:
jwe@7222
  3656
      break;
jwe@7222
  3657
    }
jwe@7222
  3658
jwe@7427
  3659
  xproperties.update_transform ();
jwe@7427
  3660
jwe@7222
  3661
  unwind_protect::run ();
jwe@7214
  3662
}
jwe@7214
  3663
michael@7855
  3664
void
michael@7855
  3665
axes::properties::zoom (const Matrix& xl, const Matrix& yl)
michael@7855
  3666
{
michael@7855
  3667
  zoom_stack.push_front (xlimmode.get ());
michael@7855
  3668
  zoom_stack.push_front (xlim.get ());
michael@7855
  3669
  zoom_stack.push_front (ylimmode.get ());
michael@7855
  3670
  zoom_stack.push_front (ylim.get ());
michael@7855
  3671
michael@7855
  3672
  xlim = xl;
michael@7855
  3673
  xlimmode = "manual";
michael@7855
  3674
  ylim = yl;
michael@7855
  3675
  ylimmode = "manual";
michael@7855
  3676
michael@7855
  3677
  update_transform ();
michael@7855
  3678
  update_xlim (false);
michael@7855
  3679
  update_ylim (false);
michael@7855
  3680
}
michael@7855
  3681
michael@7855
  3682
void
michael@7855
  3683
axes::properties::unzoom (void)
michael@7855
  3684
{
michael@7855
  3685
  if (zoom_stack.size () >= 4)
michael@7855
  3686
    {
michael@7855
  3687
      ylim = zoom_stack.front ();
michael@7855
  3688
      zoom_stack.pop_front ();
michael@7855
  3689
      ylimmode = zoom_stack.front ();
michael@7855
  3690
      zoom_stack.pop_front ();
michael@7855
  3691
      xlim = zoom_stack.front ();
michael@7855
  3692
      zoom_stack.pop_front ();
michael@7855
  3693
      xlimmode = zoom_stack.front ();
michael@7855
  3694
      zoom_stack.pop_front ();
michael@7855
  3695
michael@7855
  3696
      update_transform ();
michael@7855
  3697
      update_xlim (false);
michael@7855
  3698
      update_ylim (false);
michael@7855
  3699
    }
michael@7855
  3700
}
michael@7855
  3701
michael@7855
  3702
void
michael@7855
  3703
axes::properties::clear_zoom_stack (void)
michael@7855
  3704
{
michael@7855
  3705
  while (zoom_stack.size () > 4)
michael@7855
  3706
    zoom_stack.pop_front ();
michael@7855
  3707
michael@7855
  3708
  unzoom ();
michael@7855
  3709
}
michael@7855
  3710
jwe@7363
  3711
// ---------------------------------------------------------------------
jwe@7363
  3712
michael@7862
  3713
Matrix
michael@7862
  3714
line::properties::compute_xlim (void) const
michael@7862
  3715
{
michael@7862
  3716
  Matrix m (1, 3);
michael@7862
  3717
michael@7862
  3718
  m(0) = xmin (xdata.min_val (), xmin (xldata.min_val (), xudata.min_val ()));
michael@7862
  3719
  m(1) = xmax (xdata.max_val (), xmax (xldata.max_val (), xudata.max_val ()));
michael@7862
  3720
  m(2) = xmin (xdata.min_pos (), xmin (xldata.min_pos (), xudata.min_pos ()));
michael@7862
  3721
michael@7862
  3722
  return m;
michael@7862
  3723
}
michael@7862
  3724
michael@7862
  3725
Matrix
michael@7862
  3726
line::properties::compute_ylim (void) const
michael@7862
  3727
{
michael@7862
  3728
  Matrix m (1, 3);
michael@7862
  3729
michael@7862
  3730
  m(0) = xmin (ydata.min_val (), xmin (ldata.min_val (), udata.min_val ()));
michael@7862
  3731
  m(1) = xmax (ydata.max_val (), xmax (ldata.max_val (), udata.max_val ()));
michael@7862
  3732
  m(2) = xmin (ydata.min_pos (), xmin (ldata.min_pos (), udata.min_pos ()));
michael@7862
  3733
michael@7862
  3734
  return m;
michael@7862
  3735
}
jwe@6406
  3736
jwe@6406
  3737
// ---------------------------------------------------------------------
jwe@6406
  3738
jwe@7363
  3739
// Note: "text" code is entirely auto-generated
jwe@6406
  3740
jwe@6406
  3741
// ---------------------------------------------------------------------
jwe@6406
  3742
jwe@7363
  3743
// Note: "image" code is entirely auto-generated
jwe@6406
  3744
jwe@6406
  3745
// ---------------------------------------------------------------------
jwe@6406
  3746
michael@7833
  3747
octave_value
michael@7833
  3748
patch::properties::get_color_data (void) const
michael@7833
  3749
{
michael@7833
  3750
  return convert_cdata (*this, get_facevertexcdata (),
michael@7833
  3751
			cdatamapping_is ("scaled"), 2);
michael@7833
  3752
}
jwe@6406
  3753
jwe@6406
  3754
// ---------------------------------------------------------------------
jwe@6406
  3755
michael@7829
  3756
octave_value
michael@7829
  3757
surface::properties::get_color_data (void) const
michael@7829
  3758
{
michael@7829
  3759
  return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
michael@7829
  3760
}
michael@7829
  3761
michael@7829
  3762
inline void
michael@7829
  3763
cross_product (double x1, double y1, double z1,
michael@7829
  3764
	       double x2, double y2, double z2,
michael@7829
  3765
	       double& x, double& y, double& z)
michael@7829
  3766
{
michael@7829
  3767
  x += (y1 * z2 - z1 * y2);
michael@7829
  3768
  y += (z1 * x2 - x1 * z2);
michael@7829
  3769
  z += (x1 * y2 - y1 * x2);
michael@7829
  3770
}
michael@7829
  3771
michael@7829
  3772
void
michael@7829
  3773
surface::properties::update_normals (void)
michael@7829
  3774
{
michael@7829
  3775
  if (normalmode_is ("auto"))
michael@7829
  3776
    {
michael@7829
  3777
      Matrix x = get_xdata ().matrix_value ();
michael@7829
  3778
      Matrix y = get_ydata ().matrix_value ();
michael@7829
  3779
      Matrix z = get_zdata ().matrix_value ();
michael@7829
  3780
Kai@8449
  3781
michael@7829
  3782
      int p = z.columns (), q = z.rows ();
Kai@8449
  3783
      int i1 = 0, i2 = 0, i3 = 0;
Kai@8449
  3784
      int j1 = 0, j2 = 0, j3 = 0;
michael@7829
  3785
michael@7829
  3786
      bool x_mat = (x.rows () == q);
michael@7829
  3787
      bool y_mat = (y.columns () == p);
michael@7829
  3788
michael@7829
  3789
      NDArray n (dim_vector (q, p, 3), 0.0);
michael@7829
  3790
Kai@8449
  3791
      for (int i = 0; i < p; i++)
michael@7829
  3792
	{
michael@7829
  3793
	  if (y_mat)
michael@7829
  3794
	    {
Kai@8449
  3795
	      i1 = i - 1;
michael@7829
  3796
	      i2 = i;
Kai@8449
  3797
	      i3 = i + 1;
michael@7829
  3798
	    }
michael@7829
  3799
Kai@8449
  3800
	  for (int j = 0; j < q; j++)
michael@7829
  3801
	    {
michael@7829
  3802
	      if (x_mat)
michael@7829
  3803
		{
Kai@8449
  3804
		  j1 = j - 1;
michael@7829
  3805
		  j2 = j;
Kai@8449
  3806
		  j3 = j + 1;
michael@7829
  3807
		}
michael@7829
  3808
Kai@8449
  3809
	      double& nx = n(j, i, 0);
Kai@8449
  3810
	      double& ny = n(j, i, 1);
Kai@8449
  3811
	      double& nz = n(j, i, 2);
Kai@8449
  3812
Kai@8449
  3813
              if ((j > 0) && (i > 0))
Kai@8449
  3814
                  // upper left quadrangle
Kai@8449
  3815
	          cross_product (x(j1,i-1)-x(j2,i), y(j-1,i1)-y(j,i2), z(j-1,i-1)-z(j,i),
Kai@8449
  3816
		                 x(j2,i-1)-x(j1,i), y(j,i1)-y(j-1,i2), z(j,i-1)-z(j-1,i),
Kai@8449
  3817
			         nx, ny, nz);
Kai@8449
  3818
Kai@8449
  3819
              if ((j > 0) && (i < (p -1)))
Kai@8449
  3820
                  // upper right quadrangle
Kai@8449
  3821
                  cross_product (x(j1,i+1)-x(j2,i), y(j-1,i3)-y(j,i2), z(j-1,i+1)-z(j,i),
Kai@8449
  3822
		                 x(j1,i)-x(j2,i+1), y(j-1,i2)-y(j,i3), z(j-1,i)-z(j,i+1),
Kai@8449
  3823
			         nx, ny, nz);
Kai@8449
  3824
Kai@8449
  3825
              if ((j < (q - 1)) && (i > 0))
Kai@8449
  3826
                  // lower left quadrangle
Kai@8449
  3827
                  cross_product (x(j2,i-1)-x(j3,i), y(j,i1)-y(j+1,i2), z(j,i-1)-z(j+1,i),
Kai@8449
  3828
		                 x(j3,i-1)-x(j2,i), y(j+1,i1)-y(j,i2), z(j+1,i-1)-z(j,i),
Kai@8449
  3829
			         nx, ny, nz);
Kai@8449
  3830
Kai@8449
  3831
              if ((j < (q - 1)) && (i < (p -1)))
Kai@8449
  3832
                  // lower right quadrangle
Kai@8449
  3833
	          cross_product (x(j3,i)-x(j2,i+1), y(j+1,i2)-y(j,i3), z(j+1,i)-z(j,i+1),
Kai@8449
  3834
                                 x(j3,i+1)-x(j2,i), y(j+1,i3)-y(j,i2), z(j+1,i+1)-z(j,i),
Kai@8449
  3835
			         nx, ny, nz);
Kai@8449
  3836
Kai@8449
  3837
              double d = - std::max(std::max(fabs(nx), fabs(ny)), fabs(nz));
michael@7829
  3838
michael@7829
  3839
	      nx /= d;
michael@7829
  3840
	      ny /= d;
michael@7829
  3841
	      nz /= d;
michael@7829
  3842
	    }
michael@7829
  3843
	}
michael@7829
  3844
      vertexnormals = n;
michael@7829
  3845
    }
michael@7829
  3846
}
jwe@6406
  3847
jwe@6406
  3848
// ---------------------------------------------------------------------
jwe@6406
  3849
michael@7865
  3850
void
michael@7865
  3851
hggroup::update_axis_limits (const std::string& axis_type)
michael@7865
  3852
{
michael@7865
  3853
  Matrix kids = xproperties.get_children ();
michael@7865
  3854
michael@7865
  3855
  double min_val = octave_Inf;
michael@7865
  3856
  double max_val = -octave_Inf;
michael@7865
  3857
  double min_pos = octave_Inf;
michael@7865
  3858
michael@7865
  3859
  char update_type = 0;
michael@7865
  3860
Michael@8081
  3861
  if (axis_type == "xlim" || axis_type == "xliminclude")
michael@7865
  3862
    {
michael@7865
  3863
      get_children_limits (min_val, max_val, min_pos, kids, 'x');
michael@7865
  3864
      
michael@7865
  3865
      update_type = 'x';
michael@7865
  3866
    }
Michael@8081
  3867
  else if (axis_type == "ylim" || axis_type == "yliminclude")
michael@7865
  3868
    {
michael@7865
  3869
      get_children_limits (min_val, max_val, min_pos, kids, 'y');
michael@7865
  3870
michael@7865
  3871
      update_type = 'y';
michael@7865
  3872
    }
Michael@8081
  3873
  else if (axis_type == "zlim" || axis_type == "zliminclude")
michael@7865
  3874
    {
michael@7865
  3875
      get_children_limits (min_val, max_val, min_pos, kids, 'z');
michael@7865
  3876
michael@7865
  3877
      update_type = 'z';
michael@7865
  3878
    }
Michael@8081
  3879
  else if (axis_type == "clim" || axis_type == "climinclude")
michael@7865
  3880
    {
michael@7865
  3881
      get_children_limits (min_val, max_val, min_pos, kids, 'c');
michael@7865
  3882
michael@7865
  3883
      update_type = 'c';
michael@7865
  3884
michael@7865
  3885
    }
Michael@8081
  3886
  else if (axis_type == "alim" || axis_type == "aliminclude")
michael@7865
  3887
    {
michael@7865
  3888
      get_children_limits (min_val, max_val, min_pos, kids, 'a');
michael@7865
  3889
michael@7865
  3890
      update_type = 'a';
michael@7865
  3891
    }
michael@7865
  3892
michael@7865
  3893
  Matrix limits (1, 3, 0.0);
michael@7865
  3894
michael@7865
  3895
  limits(0) = min_val;
michael@7865
  3896
  limits(1) = max_val;
michael@7865
  3897
  limits(2) = min_pos;
michael@7865
  3898
michael@7865
  3899
  switch (update_type)
michael@7865
  3900
    {
michael@7865
  3901
    case 'x':
michael@7865
  3902
      xproperties.set_xlim (limits);
michael@7865
  3903
      break;
michael@7865
  3904
michael@7865
  3905
    case 'y':
michael@7865
  3906
      xproperties.set_ylim (limits);
michael@7865
  3907
      break;
michael@7865
  3908
michael@7865
  3909
    case 'z':
michael@7865
  3910
      xproperties.set_zlim (limits);
michael@7865
  3911
      break;
michael@7865
  3912
michael@7865
  3913
    case 'c':
michael@7865
  3914
      xproperties.set_clim (limits);
michael@7865
  3915
      break;
michael@7865
  3916
michael@7865
  3917
    case 'a':
michael@7865
  3918
      xproperties.set_alim (limits);
michael@7865
  3919
      break;
michael@7865
  3920
michael@7865
  3921
    default:
michael@7865
  3922
      break;
michael@7865
  3923
    }
michael@7865
  3924
michael@7865
  3925
  base_graphics_object::update_axis_limits (axis_type);
michael@7865
  3926
}
michael@7865
  3927
michael@7865
  3928
// ---------------------------------------------------------------------
michael@7865
  3929
jwe@6406
  3930
octave_value
dbateman@7189
  3931
base_graphics_object::get_default (const caseless_str& name) const
jwe@6406
  3932
{
jwe@6406
  3933
  graphics_handle parent = get_parent ();
jwe@6406
  3934
  graphics_object parent_obj = gh_manager::get_object (parent);
jwe@6406
  3935
jwe@6406
  3936
  return parent_obj.get_default (type () + name);
jwe@6406
  3937
}
jwe@6406
  3938
jwe@6406
  3939
octave_value
dbateman@7189
  3940
base_graphics_object::get_factory_default (const caseless_str& name) const
jwe@6406
  3941
{
jwe@6406
  3942
  graphics_object parent_obj = gh_manager::get_object (0);
jwe@6406
  3943
jwe@6406
  3944
  return parent_obj.get_factory_default (type () + name);
jwe@6406
  3945
}
jwe@6406
  3946
jwe@7286
  3947
// We use a random value for the handle to avoid issues with plots and
jwe@7286
  3948
// scalar values for the first argument.
jwe@6406
  3949
gh_manager::gh_manager (void)
jwe@7286
  3950
  : handle_map (), handle_free_list (),
jwe@7286
  3951
    next_handle (-1.0 - (rand () + 1.0) / (RAND_MAX + 2.0))
jwe@6406
  3952
{
jwe@6406
  3953
  handle_map[0] = graphics_object (new root_figure ());
michael@7847
  3954
michael@7847
  3955
  // Make sure the default backend is registered.
michael@7847
  3956
  graphics_backend::default_backend ();
jwe@6406
  3957
}
jwe@6406
  3958
jwe@6406
  3959
graphics_handle
jwe@6406
  3960
gh_manager::do_make_graphics_handle (const std::string& go_name,
jwe@7370
  3961
				     const graphics_handle& p, bool do_createfcn)
jwe@6406
  3962
{
jwe@6406
  3963
  graphics_handle h = get_handle (go_name);
jwe@6406
  3964
jwe@6406
  3965
  base_graphics_object *go = 0;
jwe@6406
  3966
michael@7864
  3967
  go = make_graphics_object_from_type (go_name, h, p);
michael@7864
  3968
  
jwe@6406
  3969
  if (go)
jwe@7370
  3970
    {
jwe@8059
  3971
      graphics_object obj (go);
jwe@8059
  3972
jwe@8059
  3973
      handle_map[h] = obj;
jwe@7370
  3974
      if (do_createfcn)
jwe@7370
  3975
        go->get_properties ().execute_createfcn ();
jwe@8058
  3976
jwe@8058
  3977
      // notify backend
jwe@8058
  3978
      graphics_backend backend = go->get_backend ();
jwe@8058
  3979
      if (backend)
jwe@8059
  3980
        backend.object_created (obj);
jwe@7370
  3981
    }
jwe@6406
  3982
  else
jwe@6406
  3983
    error ("gh_manager::do_make_graphics_handle: invalid object type `%s'",
jwe@6406
  3984
	   go_name.c_str ());
jwe@6406
  3985
jwe@6406
  3986
  return h;
jwe@6406
  3987
}
jwe@6406
  3988
jwe@6406
  3989
graphics_handle
jwe@6406
  3990
gh_manager::do_make_figure_handle (double val)
jwe@6406
  3991
{
jwe@6406
  3992
  graphics_handle h = val;
jwe@6406
  3993
jwe@8058
  3994
  base_graphics_object* go = new figure (h, 0);
jwe@8059
  3995
  graphics_object obj (go);
jwe@8059
  3996
jwe@8059
  3997
  handle_map[h] = obj;
jwe@8058
  3998
jwe@8058
  3999
  // notify backend
jwe@8058
  4000
  graphics_backend backend = go->get_backend ();
jwe@8058
  4001
  if (backend)
jwe@8059
  4002
    backend.object_created (obj);
jwe@8058
  4003
  
jwe@6406
  4004
  return h;
jwe@6406
  4005
}
jwe@6406
  4006
jwe@6406
  4007
void
jwe@6406
  4008
gh_manager::do_push_figure (const graphics_handle& h)
jwe@6406
  4009
{
jwe@6406
  4010
  do_pop_figure (h);
jwe@6406
  4011
jwe@6406
  4012
  figure_list.push_front (h);
jwe@6406
  4013
}
jwe@6406
  4014
jwe@6406
  4015
void
jwe@6406
  4016
gh_manager::do_pop_figure (const graphics_handle& h)
jwe@6406
  4017
{
jwe@6406
  4018
  for (figure_list_iterator p = figure_list.begin ();
jwe@6406
  4019
       p != figure_list.end ();
jwe@6406
  4020
       p++)
jwe@6406
  4021
    {
jwe@6406
  4022
      if (*p == h)
jwe@6406
  4023
	{
jwe@6406
  4024
	  figure_list.erase (p);
jwe@6406
  4025
	  break;
jwe@6406
  4026
	}
jwe@6406
  4027
    }
jwe@6406
  4028
}
jwe@6406
  4029
jwe@7936
  4030
class
jwe@7964
  4031
callback_event : public base_graphics_event
jwe@7936
  4032
{
jwe@7936
  4033
public:
jwe@7964
  4034
  callback_event (const graphics_handle& h, const std::string& name,
jwe@7964
  4035
		  const octave_value& data = Matrix ())
jwe@7964
  4036
      : base_graphics_event (), handle (h), callback_name (name),
jwe@7936
  4037
        callback_data (data) { }
jwe@7936
  4038
jwe@7936
  4039
  void execute (void)
jwe@7936
  4040
    {
jwe@7936
  4041
      gh_manager::execute_callback (handle, callback_name, callback_data);
jwe@7936
  4042
    }
jwe@7936
  4043
jwe@7936
  4044
private:
jwe@7964
  4045
  callback_event (void)
jwe@7964
  4046
      : base_graphics_event () { }
jwe@7936
  4047
jwe@7936
  4048
private:
jwe@7936
  4049
  graphics_handle handle;
jwe@7936
  4050
  std::string callback_name;
jwe@7936
  4051
  octave_value callback_data;
jwe@7936
  4052
};
jwe@7936
  4053
jwe@7936
  4054
class
jwe@7964
  4055
function_event : public base_graphics_event
jwe@7936
  4056
{
jwe@7936
  4057
public:
jwe@7964
  4058
  function_event (graphics_event::event_fcn fcn, void* data = 0)
jwe@7964
  4059
      : base_graphics_event (), function (fcn),
jwe@7936
  4060
        function_data (data) { }
jwe@7936
  4061
jwe@7936
  4062
  void execute (void)
jwe@7936
  4063
    {
jwe@7936
  4064
      function (function_data);
jwe@7936
  4065
    }
jwe@7936
  4066
jwe@7936
  4067
private:
jwe@7964
  4068
  function_event (void)
jwe@7964
  4069
      : base_graphics_event () { }
jwe@7936
  4070
jwe@7936
  4071
private:
jwe@7964
  4072
  graphics_event::event_fcn function;
jwe@7936
  4073
  void* function_data;
jwe@7936
  4074
};
jwe@7936
  4075
jwe@7936
  4076
class
jwe@7964
  4077
set_event : public base_graphics_event
jwe@7936
  4078
{
jwe@7936
  4079
public:
jwe@7964
  4080
  set_event (const graphics_handle& h, const std::string& name,
jwe@7964
  4081
	     const octave_value& value)
jwe@7964
  4082
      : base_graphics_event (), handle (h), property_name (name),
jwe@7936
  4083
        property_value (value) { }
jwe@7936
  4084
jwe@7936
  4085
  void execute (void)
jwe@7936
  4086
    {
jwe@7936
  4087
      gh_manager::autolock guard;
jwe@7936
  4088
jwe@7936
  4089
      xset (handle, property_name, property_value);
jwe@7936
  4090
    }
jwe@7936
  4091
jwe@7936
  4092
private:
jwe@7964
  4093
  set_event (void)
jwe@7964
  4094
      : base_graphics_event () { }
jwe@7936
  4095
jwe@7936
  4096
private:
jwe@7936
  4097
  graphics_handle handle;
jwe@7936
  4098
  std::string property_name;
jwe@7936
  4099
  octave_value property_value;
jwe@7936
  4100
};
jwe@7936
  4101
jwe@7964
  4102
graphics_event
jwe@7964
  4103
graphics_event::create_callback_event (const graphics_handle& h,
jwe@7964
  4104
				       const std::string& name,
jwe@7964
  4105
				       const octave_value& data)
jwe@7936
  4106
{
jwe@7964
  4107
  graphics_event e;
jwe@7964
  4108
jwe@7964
  4109
  e.rep = new callback_event (h, name, data);
jwe@7936
  4110
jwe@7936
  4111
  return e;
jwe@7936
  4112
}
jwe@7936
  4113
jwe@7964
  4114
graphics_event
jwe@7964
  4115
graphics_event::create_function_event (graphics_event::event_fcn fcn,
jwe@7964
  4116
				       void *data)
jwe@7936
  4117
{
jwe@7964
  4118
  graphics_event e;
jwe@7964
  4119
jwe@7964
  4120
  e.rep = new function_event (fcn, data);
jwe@7936
  4121
jwe@7936
  4122
  return e;
jwe@7936
  4123
}
jwe@7936
  4124
jwe@7964
  4125
graphics_event
jwe@7964
  4126
graphics_event::create_set_event (const graphics_handle& h,
jwe@7964
  4127
				  const std::string& name,
jwe@7964
  4128
				  const octave_value& data)
jwe@7936
  4129
{
jwe@7964
  4130
  graphics_event e;
jwe@7964
  4131
jwe@7964
  4132
  e.rep = new set_event (h, name, data);
jwe@7936
  4133
jwe@7936
  4134
  return e;
jwe@7936
  4135
}
jwe@7936
  4136
jwe@7936
  4137
static void
jwe@7936
  4138
xset_gcbo (const graphics_handle& h)
jwe@7936
  4139
{
jwe@7936
  4140
  graphics_object go = gh_manager::get_object (0);
jwe@7936
  4141
  root_figure::properties& props =
jwe@7936
  4142
      dynamic_cast<root_figure::properties&> (go.get_properties ());
jwe@7936
  4143
jwe@7936
  4144
  props.set_callbackobject (h.as_octave_value ());
jwe@7936
  4145
}
jwe@7936
  4146
jwe@7936
  4147
void
jwe@7936
  4148
gh_manager::do_restore_gcbo (void)
jwe@7936
  4149
{
jwe@7936
  4150
  gh_manager::autolock guard;
jwe@7936
  4151
jwe@7936
  4152
  callback_objects.pop_front ();
jwe@7936
  4153
jwe@7936
  4154
  xset_gcbo (callback_objects.empty ()
jwe@7936
  4155
	     ? graphics_handle ()
jwe@7936
  4156
	     : callback_objects.front ().get_handle ());
jwe@7936
  4157
}
jwe@7936
  4158
jwe@7936
  4159
void
jwe@7936
  4160
gh_manager::do_execute_callback (const graphics_handle& h,
jwe@7936
  4161
				 const octave_value& cb_arg,
jwe@7936
  4162
				 const octave_value& data)
jwe@7936
  4163
{
jwe@7936
  4164
  octave_value_list args;
jwe@7936
  4165
  octave_function *fcn = 0;
jwe@7936
  4166
jwe@7936
  4167
  args(0) = h.as_octave_value ();
jwe@7936
  4168
  if (data.is_defined ())
jwe@7936
  4169
    args(1) = data;
jwe@7936
  4170
  else
jwe@7936
  4171
    args(1) = Matrix ();
jwe@7936
  4172
jwe@7936
  4173
  unwind_protect::begin_frame ("execute_callback");
jwe@7936
  4174
  unwind_protect::add (gh_manager::restore_gcbo);
jwe@7936
  4175
jwe@7936
  4176
  if (true)
jwe@7936
  4177
    {
jwe@7936
  4178
      gh_manager::autolock guard;
jwe@7936
  4179
  
jwe@7936
  4180
      callback_objects.push_front (get_object (h));
jwe@7936
  4181
      xset_gcbo (h);
jwe@7936
  4182
    }
jwe@7936
  4183
jwe@7936
  4184
  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
jwe@7936
  4185
jwe@7936
  4186
  // Copy CB because "function_value" method is non-const.
jwe@7936
  4187
jwe@7936
  4188
  octave_value cb = cb_arg;
jwe@7936
  4189
jwe@7936
  4190
  if (cb.is_function_handle ())
jwe@7936
  4191
    fcn = cb.function_value ();
jwe@7936
  4192
  else if (cb.is_string ())
jwe@7936
  4193
    {
jwe@7936
  4194
      int status;
jwe@7936
  4195
      std::string s = cb.string_value ();
jwe@7936
  4196
jwe@7936
  4197
      eval_string (s, false, status);
jwe@7936
  4198
    }
jwe@7936
  4199
  else if (cb.is_cell () && cb.length () > 0
jwe@7936
  4200
           && (cb.rows () == 1 || cb.columns () == 1)
jwe@7936
  4201
           && cb.cell_value ()(0).is_function_handle ())
jwe@7936
  4202
    {
jwe@7936
  4203
      Cell c = cb.cell_value ();
jwe@7936
  4204
jwe@7936
  4205
      fcn = c(0).function_value ();
jwe@7936
  4206
      if (! error_state)
jwe@7936
  4207
        {
dbateman@8052
  4208
          for (int i = 1; i < c.length () ; i++)
dbateman@8052
  4209
            args(1+i) = c(i);
jwe@7936
  4210
        }
jwe@7936
  4211
    }
jwe@7936
  4212
  else
jwe@7936
  4213
    {
jwe@7936
  4214
      std::string nm = cb.class_name ();
jwe@7936
  4215
      error ("trying to execute non-executable object (class = %s)",
jwe@7936
  4216
	     nm.c_str ());
jwe@7936
  4217
    }
jwe@7936
  4218
jwe@7936
  4219
  if (fcn && ! error_state)
jwe@7936
  4220
    feval (fcn, args);
jwe@7936
  4221
  
jwe@7936
  4222
  END_INTERRUPT_WITH_EXCEPTIONS;
jwe@7936
  4223
jwe@7936
  4224
  unwind_protect::run_frame ("execute_callback");
jwe@7936
  4225
}
jwe@7936
  4226
jwe@7936
  4227
void
jwe@7964
  4228
gh_manager::do_post_event (const graphics_event& e)
jwe@7936
  4229
{
jwe@7936
  4230
  event_queue.push_back (e);
jwe@7936
  4231
jwe@7936
  4232
  command_editor::add_event_hook (gh_manager::process_events);
jwe@7936
  4233
}
jwe@7936
  4234
jwe@7936
  4235
void
jwe@7936
  4236
gh_manager::do_post_callback (const graphics_handle& h, const std::string name,
jwe@7936
  4237
			      const octave_value& data)
jwe@7936
  4238
{
jwe@7936
  4239
  gh_manager::autolock guard;
jwe@7936
  4240
jwe@7936
  4241
  graphics_object go = get_object (h);
jwe@7936
  4242
jwe@7936
  4243
  if (go.valid_object ())
jwe@7936
  4244
    {
jwe@7936
  4245
      if (callback_objects.empty ())
jwe@7964
  4246
	do_post_event (graphics_event::create_callback_event (h, name, data));
jwe@7936
  4247
      else
jwe@7936
  4248
	{
jwe@7936
  4249
	  const graphics_object& current = callback_objects.front ();
jwe@7936
  4250
jwe@7936
  4251
	  if (current.get_properties ().is_interruptible ())
jwe@7964
  4252
	    do_post_event (graphics_event::create_callback_event (h, name, data));
jwe@7936
  4253
	  else
jwe@7936
  4254
	    {
jwe@7936
  4255
	      caseless_str busy_action (go.get_properties ().get_busyaction ());
jwe@7936
  4256
jwe@7936
  4257
	      if (busy_action.compare ("queue"))
jwe@7964
  4258
		do_post_event (graphics_event::create_callback_event (h, name, data));
jwe@7936
  4259
	      else
jwe@7936
  4260
		{
jwe@7936
  4261
		  caseless_str cname (name);
jwe@7936
  4262
jwe@7936
  4263
		  if (cname.compare ("deletefcn")
jwe@7936
  4264
		      || cname.compare ("createfcn")
jwe@7936
  4265
		      || (go.isa ("figure")
jwe@7936
  4266
			  && (cname.compare ("closerequestfcn")
jwe@7936
  4267
			      || cname.compare ("resizefcn"))))
jwe@7964
  4268
		    do_post_event (graphics_event::create_callback_event (h, name, data));
jwe@7936
  4269
		}
jwe@7936
  4270
	    }
jwe@7936
  4271
	}
jwe@7936
  4272
    }
jwe@7936
  4273
}
jwe@7936
  4274
jwe@7936
  4275
void
jwe@7964
  4276
gh_manager::do_post_function (graphics_event::event_fcn fcn, void* fcn_data)
jwe@7936
  4277
{
jwe@7936
  4278
  gh_manager::autolock guard;
jwe@7936
  4279
jwe@7964
  4280
  do_post_event (graphics_event::create_function_event (fcn, fcn_data));
jwe@7936
  4281
}
jwe@7936
  4282
jwe@7936
  4283
void
jwe@7936
  4284
gh_manager::do_post_set (const graphics_handle& h, const std::string name,
jwe@7936
  4285
			 const octave_value& value)
jwe@7936
  4286
{
jwe@7936
  4287
  gh_manager::autolock guard;
jwe@7936
  4288
jwe@7964
  4289
  do_post_event (graphics_event::create_set_event (h, name, value));
jwe@7936
  4290
}
jwe@7936
  4291
jwe@7936
  4292
int
jwe@7936
  4293
gh_manager::do_process_events (bool force)
jwe@7936
  4294
{
jwe@7964
  4295
  graphics_event e;
jwe@7936
  4296
jwe@7936
  4297
  do
jwe@7936
  4298
    {
jwe@7964
  4299
      e = graphics_event ();
jwe@7936
  4300
jwe@7936
  4301
      gh_manager::lock ();
jwe@7936
  4302
jwe@7936
  4303
      if (! event_queue.empty ())
jwe@7936
  4304
	{
jwe@7936
  4305
	  if (callback_objects.empty () || force)
jwe@7936
  4306
	    {
jwe@7936
  4307
	      e = event_queue.front ();
jwe@7936
  4308
	      
jwe@7936
  4309
	      event_queue.pop_front ();
jwe@7936
  4310
	    }
jwe@7936
  4311
	  else
jwe@7936
  4312
	    {
jwe@7936
  4313
	      const graphics_object& go = callback_objects.front ();
jwe@7936
  4314
jwe@7936
  4315
	      if (go.get_properties ().is_interruptible ())
jwe@7936
  4316
		{
jwe@7936
  4317
		  e = event_queue.front ();
jwe@7936
  4318
jwe@7936
  4319
		  event_queue.pop_front ();
jwe@7936
  4320
		}
jwe@7936
  4321
	    }
jwe@7936
  4322
	}
jwe@7936
  4323
jwe@7936
  4324
      gh_manager::unlock ();
jwe@7936
  4325
jwe@7936
  4326
      if (e.ok ())
jwe@7936
  4327
	e.execute ();
jwe@7936
  4328
    }
jwe@7936
  4329
  while (e.ok ());
jwe@7936
  4330
jwe@7936
  4331
  gh_manager::lock ();
jwe@7936
  4332
jwe@7936
  4333
  if (event_queue.empty ())
jwe@7936
  4334
    command_editor::remove_event_hook (gh_manager::process_events);
jwe@7936
  4335
jwe@7936
  4336
  gh_manager::unlock ();
jwe@7936
  4337
jwe@7936
  4338
  return 0;
jwe@7936
  4339
}
jwe@7936
  4340
jwe@6406
  4341
property_list::plist_map_type
jwe@6406
  4342
root_figure::init_factory_properties (void)
jwe@6406
  4343
{
jwe@6406
  4344
  property_list::plist_map_type plist_map;
jwe@6406
  4345
jwe@6844
  4346
  plist_map["figure"] = figure::properties::factory_defaults ();
jwe@6844
  4347
  plist_map["axes"] = axes::properties::factory_defaults ();
jwe@6844
  4348
  plist_map["line"] = line::properties::factory_defaults ();
jwe@6844
  4349
  plist_map["text"] = text::properties::factory_defaults ();
jwe@6844
  4350
  plist_map["image"] = image::properties::factory_defaults ();
jwe@6844
  4351
  plist_map["patch"] = patch::properties::factory_defaults ();
jwe@6844
  4352
  plist_map["surface"] = surface::properties::factory_defaults ();
michael@7865
  4353
  plist_map["hggroup"] = hggroup::properties::factory_defaults ();
jwe@6406
  4354
jwe@6406
  4355
  return plist_map;
jwe@6406
  4356
}
jwe@6406
  4357
jwe@6406
  4358
// ---------------------------------------------------------------------
jwe@6406
  4359
jwe@6406
  4360
DEFUN (ishandle, args, ,
jwe@6406
  4361
  "-*- texinfo -*-\n\
jwe@6678
  4362
@deftypefn {Built-in Function} {} ishandle (@var{h})\n\
jwe@6406
  4363
Return true if @var{h} is a graphics handle and false otherwise.\n\
jwe@6406
  4364
@end deftypefn")
jwe@6406
  4365
{
jwe@7936
  4366
  gh_manager::autolock guard;
jwe@7936
  4367
jwe@6406
  4368
  octave_value retval;
jwe@6406
  4369
jwe@6406
  4370
  if (args.length () == 1)
jwe@6406
  4371
    retval = is_handle (args(0));
jwe@6406
  4372
  else
jwe@6406
  4373
    print_usage ();
jwe@6406
  4374
jwe@6406
  4375
  return retval;
jwe@6406
  4376
}
jwe@6406
  4377
jwe@6406
  4378
DEFUN (set, args, ,
jwe@6406
  4379
  "-*- texinfo -*-\n\
jwe@6678
  4380
@deftypefn {Built-in Function} {} set (@var{h}, @var{p}, @var{v}, @dots{})\n\
jwe@6732
  4381
Set the named property value or vector @var{p} to the value @var{v}\n\
jwe@6894
  4382
for the graphics handle @var{h}.\n\
jwe@6406
  4383
@end deftypefn")
jwe@6406
  4384
{
jwe@7936
  4385
  gh_manager::autolock guard;
jwe@7936
  4386
jwe@6406
  4387
  octave_value retval;
jwe@6406
  4388
jwe@6406
  4389
  int nargin = args.length ();
jwe@6406
  4390
jwe@6406
  4391
  if (nargin > 0)
jwe@6406
  4392
    {
jwe@6732
  4393
      ColumnVector hcv (args(0).vector_value ());
jwe@6406
  4394
jwe@6406
  4395
      if (! error_state)
jwe@6732
  4396
        {
jwe@6733
  4397
	  bool request_drawnow = false;
jwe@6733
  4398
jwe@6732
  4399
          for (octave_idx_type n = 0; n < hcv.length (); n++) 
jwe@6732
  4400
            {
jwe@6732
  4401
              graphics_object obj = gh_manager::get_object (hcv(n));
jwe@6406
  4402
jwe@6732
  4403
              if (obj)
jwe@6732
  4404
                {
jwe@6732
  4405
                  obj.set (args.splice (0, 1));
jwe@6406
  4406
jwe@6733
  4407
                  request_drawnow = true;
jwe@6732
  4408
                }
jwe@6732
  4409
              else
jwe@6733
  4410
		{
jwe@6733
  4411
		  error ("set: invalid handle (= %g)", hcv(n));
jwe@6733
  4412
		  break;
jwe@6733
  4413
		}
jwe@6732
  4414
            }
jwe@6733
  4415
jwe@6733
  4416
	  if (! error_state && request_drawnow)
jwe@7409
  4417
	    Vdrawnow_requested = true;
jwe@6732
  4418
        }
jwe@6406
  4419
      else
jwe@6732
  4420
        error ("set: expecting graphics handle as first argument");
jwe@6406
  4421
    }
jwe@6406
  4422
  else
jwe@6406
  4423
    print_usage ();
jwe@6406
  4424
jwe@6406
  4425
  return retval;
jwe@6406
  4426
}
jwe@6406
  4427
jwe@6406
  4428
DEFUN (get, args, ,
jwe@6406
  4429
  "-*- texinfo -*-\n\
jwe@6678
  4430
@deftypefn {Built-in Function} {} get (@var{h}, @var{p})\n\
jwe@6406
  4431
Return the named property @var{p} from the graphics handle @var{h}.\n\
jwe@6406
  4432
If @var{p} is omitted, return the complete property list for @var{h}.\n\
jwe@6732
  4433
If @var{h} is a vector, return a cell array including the property\n\
jwe@6732
  4434
values or lists respectively.\n\
jwe@6406
  4435
@end deftypefn")
jwe@6406
  4436
{
jwe@7936
  4437
  gh_manager::autolock guard;
jwe@7936
  4438
jwe@6406
  4439
  octave_value retval;
jwe@8896
  4440
jwe@8896
  4441
  Cell vals;
jwe@6406
  4442
jwe@6406
  4443
  int nargin = args.length ();
jwe@6406
  4444
jwe@6406
  4445
  if (nargin == 1 || nargin == 2)
jwe@6406
  4446
    {
jwe@6732
  4447
      ColumnVector hcv (args(0).vector_value ());
jwe@6406
  4448
jwe@6406
  4449
      if (! error_state)
jwe@6732
  4450
        {
jwe@6733
  4451
	  octave_idx_type len = hcv.length ();
jwe@6733
  4452
jwe@8896
  4453
	  vals.resize (dim_vector (len, 1));
jwe@6733
  4454
jwe@6733
  4455
          for (octave_idx_type n = 0; n < len; n++)
jwe@6732
  4456
            {
jwe@6732
  4457
              graphics_object obj = gh_manager::get_object (hcv(n));
jwe@6406
  4458
jwe@6732
  4459
              if (obj)
jwe@6732
  4460
                {
jwe@6732
  4461
                  if (nargin == 1)
jwe@8896
  4462
                    vals(n) = obj.get ();
jwe@6732
  4463
                  else
jwe@6732
  4464
                    {
dbateman@7189
  4465
                      caseless_str property = args(1).string_value ();
jwe@6406
  4466
jwe@6732
  4467
                      if (! error_state)
jwe@8896
  4468
                        vals(n) = obj.get (property);
jwe@6732
  4469
                      else
jwe@6733
  4470
			{
jwe@6733
  4471
			  error ("get: expecting property name as second argument");
jwe@6733
  4472
			  break;
jwe@6733
  4473
			}
jwe@6732
  4474
                    }
jwe@6732
  4475
                }
jwe@6732
  4476
              else
jwe@6733
  4477
		{
jwe@6733
  4478
		  error ("get: invalid handle (= %g)", hcv(n));
jwe@6733
  4479
		  break;
jwe@6733
  4480
		}
jwe@6732
  4481
            }
jwe@6732
  4482
        }
jwe@6406
  4483
      else
jwe@6732
  4484
        error ("get: expecting graphics handle as first argument");
jwe@6406
  4485
    }
jwe@6406
  4486
  else
jwe@6406
  4487
    print_usage ();
jwe@6406
  4488
jwe@6733
  4489
  if (! error_state)
jwe@6732
  4490
    {
jwe@8896
  4491
      octave_idx_type len = vals.numel ();
jwe@6733
  4492
jwe@6733
  4493
      if (len > 1)
jwe@8896
  4494
	retval = vals;
jwe@6733
  4495
      else if (len == 1)
jwe@8896
  4496
	retval = vals(0);
jwe@6732
  4497
    }
jwe@6732
  4498
jwe@6406
  4499
  return retval;
jwe@6406
  4500
}
jwe@6406
  4501
jwe@8812
  4502
// Return all properties from the graphics handle @var{h}.
jwe@8812
  4503
// If @var{h} is a vector, return a cell array including the
jwe@8812
  4504
// property values or lists respectively.
jwe@8812
  4505
jwe@7379
  4506
DEFUN (__get__, args, ,
jwe@7379
  4507
  "-*- texinfo -*-\n\
jwe@7379
  4508
@deftypefn {Built-in Function} {} __get__ (@var{h})\n\
jwe@8812
  4509
Undocumented internal function.\n\
jwe@7379
  4510
@end deftypefn")
jwe@7379
  4511
{
jwe@7936
  4512
  gh_manager::autolock guard;
jwe@7936
  4513
jwe@7379
  4514
  octave_value retval;
jwe@8896
  4515
jwe@8896
  4516
  Cell vals;
jwe@7379
  4517
jwe@7379
  4518
  int nargin = args.length ();
jwe@7379
  4519
jwe@7379
  4520
  if (nargin == 1)
jwe@7379
  4521
    {
jwe@7379
  4522
      ColumnVector hcv (args(0).vector_value ());
jwe@7379
  4523
jwe@7379
  4524
      if (! error_state)
jwe@7379
  4525
        {
jwe@7379
  4526
          octave_idx_type len = hcv.length ();
jwe@7379
  4527
jwe@8896
  4528
          vals.resize (dim_vector (len, 1));
jwe@7379
  4529
jwe@7379
  4530
          for (octave_idx_type n = 0; n < len; n++)
jwe@7379
  4531
            {
jwe@7379
  4532
              graphics_object obj = gh_manager::get_object (hcv(n));
jwe@7379
  4533
jwe@7379
  4534
              if (obj)
jwe@8896
  4535
                vals(n) = obj.get (true);
jwe@7379
  4536
              else
jwe@7379
  4537
                {
jwe@7379
  4538
                  error ("get: invalid handle (= %g)", hcv(n));
jwe@7379
  4539
                  break;
jwe@7379
  4540
                }
jwe@7379
  4541
            }
jwe@7379
  4542
        }
jwe@7379
  4543
      else
jwe@7379
  4544
        error ("get: expecting graphics handle as first argument");
jwe@7379
  4545
    }
jwe@7379
  4546
  else
jwe@7379
  4547
    print_usage ();
jwe@7379
  4548
jwe@7379
  4549
  if (! error_state)
jwe@7379
  4550
    {
jwe@8896
  4551
      octave_idx_type len = vals.numel ();
jwe@7379
  4552
jwe@7379
  4553
      if (len > 1)
jwe@8896
  4554
        retval = vals;
jwe@7379
  4555
      else if (len == 1)
jwe@8896
  4556
        retval = vals(0);
jwe@7379
  4557
    }
jwe@7379
  4558
jwe@7379
  4559
  return retval;
jwe@7379
  4560
}
jwe@7379
  4561
jwe@6406
  4562
static octave_value
jwe@6406
  4563
make_graphics_object (const std::string& go_name,
jwe@6874
  4564
		      const octave_value_list& args)
jwe@6406
  4565
{
jwe@6406
  4566
  octave_value retval;
jwe@6406
  4567
michael@7865
  4568
  double val = octave_NaN;
michael@7865
  4569
michael@7865
  4570
  octave_value_list xargs = args.splice (0, 1);
michael@7865
  4571
michael@7865
  4572
  caseless_str p ("parent");
michael@7865
  4573
michael@7865
  4574
  for (int i = 0; i < xargs.length (); i++)
michael@7865
  4575
    if (xargs(i).is_string ()
michael@7865
  4576
	&& p.compare (xargs(i).string_value ()))
michael@7865
  4577
      {
michael@7865
  4578
	if (i < (xargs.length () - 1))
michael@7865
  4579
	  {
michael@7865
  4580
	    val = xargs(i+1).double_value ();
michael@7865
  4581
michael@7865
  4582
	    if (! error_state)
michael@7865
  4583
	      {
michael@7865
  4584
		xargs = xargs.splice (i, 2);
michael@7865
  4585
		break;
michael@7865
  4586
	      }
michael@7865
  4587
	  }
michael@7865
  4588
	else
michael@7865
  4589
	  error ("__go_%s__: missing value for parent property",
michael@7865
  4590
		 go_name.c_str ());
michael@7865
  4591
      }
michael@7865
  4592
michael@7865
  4593
  if (! error_state && xisnan (val))
michael@7865
  4594
    val = args(0).double_value ();
jwe@6406
  4595
jwe@6406
  4596
  if (! error_state)
jwe@6406
  4597
    {
jwe@6406
  4598
      graphics_handle parent = gh_manager::lookup (val);
jwe@6406
  4599
jwe@7056
  4600
      if (parent.ok ())
jwe@6406
  4601
	{
jwe@6406
  4602
	  graphics_handle h
jwe@7370
  4603
	    = gh_manager::make_graphics_handle (go_name, parent, false);
jwe@6406
  4604
jwe@6406
  4605
	  if (! error_state)
jwe@6406
  4606
	    {
jwe@6406
  4607
	      adopt (parent, h);
jwe@6406
  4608
michael@7865
  4609
	      xset (h, xargs);
jwe@7370
  4610
	      xcreatefcn (h);
jwe@6406
  4611
jwe@6874
  4612
	      retval = h.value ();
jwe@7296
  4613
jwe@7296
  4614
	      if (! error_state)
jwe@7409
  4615
		Vdrawnow_requested = true;
jwe@6406
  4616
	    }
jwe@6406
  4617
	  else
jwe@6406
  4618
	    error ("__go%s__: unable to create graphics handle",
jwe@6406
  4619
		   go_name.c_str ());
jwe@6406
  4620
	}
jwe@6406
  4621
      else
jwe@6406
  4622
	error ("__go_%s__: invalid parent", go_name.c_str ());
jwe@6406
  4623
    }
jwe@6406
  4624
  else
jwe@6406
  4625
    error ("__go_%s__: invalid parent", go_name.c_str ());
jwe@6406
  4626
jwe@6406
  4627
  return retval;
jwe@6406
  4628
}
jwe@6406
  4629
jwe@6406
  4630
DEFUN (__go_figure__, args, ,
jwe@6406
  4631
   "-*- texinfo -*-\n\
jwe@6406
  4632
@deftypefn {Built-in Function} {} __go_figure__ (@var{fignum})\n\
jwe@6945
  4633
Undocumented internal function.\n\
jwe@6406
  4634
@end deftypefn")
jwe@6406
  4635
{
jwe@7936
  4636
  gh_manager::autolock guard;
jwe@7936
  4637
jwe@6406
  4638
  octave_value retval;
jwe@6406
  4639
jwe@6406
  4640
  if (args.length () > 0)
jwe@6406
  4641
    {
jwe@6406
  4642
      double val = args(0).double_value ();
jwe@6406
  4643
jwe@6406
  4644
      if (! error_state)
jwe@6406
  4645
	{
jwe@6406
  4646
	  if (is_figure (val))
jwe@6406
  4647
	    {
jwe@6406
  4648
	      graphics_handle h = gh_manager::lookup (val);
jwe@6406
  4649
jwe@6406
  4650
	      xset (h, args.splice (0, 1));
jwe@6406
  4651
jwe@6874
  4652
	      retval = h.value ();
jwe@6406
  4653
	    }
jwe@6406
  4654
	  else
jwe@6406
  4655
	    {
jwe@6406
  4656
	      graphics_handle h = octave_NaN;
jwe@6406
  4657
jwe@6406
  4658
	      if (xisnan (val))
jwe@7370
  4659
		h = gh_manager::make_graphics_handle ("figure", 0, false);
jwe@6406
  4660
	      else if (val > 0 && D_NINT (val) == val)
jwe@6406
  4661
		h = gh_manager::make_figure_handle (val);
jwe@6406
  4662
	      else
jwe@6406
  4663
		error ("__go_figure__: invalid figure number");
jwe@6406
  4664
jwe@7056
  4665
	      if (! error_state && h.ok ())
jwe@6406
  4666
		{
jwe@6406
  4667
		  adopt (0, h);
jwe@6406
  4668
jwe@6406
  4669
		  xset (h, args.splice (0, 1));
jwe@7370
  4670
		  xcreatefcn (h);
jwe@6406
  4671
jwe@6874
  4672
		  retval = h.value ();
jwe@6406
  4673
		}
jwe@6406
  4674
	      else
jwe@6406
  4675
		error ("__go_figure__: failed to create figure handle");
jwe@6406
  4676
	    }
jwe@6406
  4677
	}
jwe@6406
  4678
      else
jwe@6406
  4679
	error ("__go_figure__: expecting figure number to be double value");
jwe@6406
  4680
    }
jwe@6406
  4681
  else
jwe@6406
  4682
    print_usage ();
jwe@6406
  4683
jwe@6406
  4684
  return retval;
jwe@6406
  4685
}
jwe@6406
  4686
jwe@6406
  4687
#define GO_BODY(TYPE) \
jwe@7936
  4688
  gh_manager::autolock guard; \
jwe@7936
  4689
 \
jwe@6406
  4690
  octave_value retval; \
jwe@6406
  4691
 \
jwe@6406
  4692
  if (args.length () > 0) \
jwe@6406
  4693
    retval = make_graphics_object (#TYPE, args); \
jwe@6406
  4694
  else \
jwe@6406
  4695
    print_usage (); \
jwe@6406
  4696
 \
jwe@6406
  4697
  return retval
jwe@6406
  4698
jwe@6406
  4699
DEFUN (__go_axes__, args, ,
jwe@6406
  4700
  "-*- texinfo -*-\n\
jwe@6406
  4701
@deftypefn {Built-in Function} {} __go_axes__ (@var{parent})\n\
jwe@6945
  4702
Undocumented internal function.\n\
jwe@6406
  4703
@end deftypefn")
jwe@6406
  4704
{
jwe@6406
  4705
  GO_BODY (axes);
jwe@6406
  4706
}
jwe@6406
  4707
jwe@6406
  4708
DEFUN (__go_line__, args, ,
jwe@6406
  4709
  "-*- texinfo -*-\n\
jwe@6406
  4710
@deftypefn {Built-in Function} {} __go_line__ (@var{parent})\n\
jwe@6945
  4711
Undocumented internal function.\n\
jwe@6406
  4712
@end deftypefn")
jwe@6406
  4713
{
jwe@6406
  4714
  GO_BODY (line);
jwe@6406
  4715
}
jwe@6406
  4716
jwe@6406
  4717
DEFUN (__go_text__, args, ,
jwe@6406
  4718
  "-*- texinfo -*-\n\
jwe@6406
  4719
@deftypefn {Built-in Function} {} __go_text__ (@var{parent})\n\
jwe@6945
  4720
Undocumented internal function.\n\
jwe@6406
  4721
@end deftypefn")
jwe@6406
  4722
{
jwe@6406
  4723
  GO_BODY (text);
jwe@6406
  4724
}
jwe@6406
  4725
jwe@6406
  4726
DEFUN (__go_image__, args, ,
jwe@6406
  4727
  "-*- texinfo -*-\n\
jwe@6406
  4728
@deftypefn {Built-in Function} {} __go_image__ (@var{parent})\n\
jwe@6945
  4729
Undocumented internal function.\n\
jwe@6406
  4730
@end deftypefn")
jwe@6406
  4731
{
jwe@6406
  4732
  GO_BODY (image);
jwe@6406
  4733
}
jwe@6406
  4734
jwe@6406
  4735
DEFUN (__go_surface__, args, ,
jwe@6406
  4736
  "-*- texinfo -*-\n\
jwe@6406
  4737
@deftypefn {Built-in Function} {} __go_surface__ (@var{parent})\n\
jwe@6945
  4738
Undocumented internal function.\n\
jwe@6406
  4739
@end deftypefn")
jwe@6406
  4740
{
jwe@6406
  4741
  GO_BODY (surface);
jwe@6406
  4742
}
jwe@6406
  4743
jwe@6807
  4744
DEFUN (__go_patch__, args, ,
jwe@6807
  4745
  "-*- texinfo -*-\n\
jwe@6807
  4746
@deftypefn {Built-in Function} {} __go_patch__ (@var{parent})\n\
jwe@6945
  4747
Undocumented internal function.\n\
jwe@6807
  4748
@end deftypefn")
jwe@6807
  4749
{
jwe@6807
  4750
  GO_BODY (patch);
jwe@6807
  4751
}
jwe@6807
  4752
michael@7865
  4753
DEFUN (__go_hggroup__, args, ,
michael@7865
  4754
  "-*- texinfo -*-\n\
michael@7865
  4755
@deftypefn {Built-in Function} {} __go_hggroup__ (@var{parent})\n\
michael@7865
  4756
Undocumented internal function.\n\
michael@7865
  4757
@end deftypefn")
michael@7865
  4758
{
michael@7865
  4759
  GO_BODY (hggroup);
michael@7865
  4760
}
michael@7865
  4761
jwe@6406
  4762
DEFUN (__go_delete__, args, ,
jwe@6406
  4763
  "-*- texinfo -*-\n\
jwe@6406
  4764
@deftypefn {Built-in Function} {} __go_delete__ (@var{h})\n\
jwe@6945
  4765
Undocumented internal function.\n\
jwe@6406
  4766
@end deftypefn")
jwe@6406
  4767
{
jwe@7936
  4768
  gh_manager::autolock guard;
jwe@7936
  4769
jwe@6406
  4770
  octave_value_list retval;
jwe@6406
  4771
jwe@6406
  4772
  if (args.length () == 1)
jwe@6406
  4773
    {
jwe@6406
  4774
      graphics_handle h = octave_NaN;
jwe@6406
  4775
dbateman@8196
  4776
      const NDArray vals = args (0).array_value ();
jwe@6406
  4777
jwe@6406
  4778
      if (! error_state)
jwe@6406
  4779
	{
dbateman@8341
  4780
	  // Check is all the handles to delete are valid first
dbateman@8341
  4781
	  // as callbacks might delete one of the handles we
dbateman@8341
  4782
	  // later want to delete
dbateman@8196
  4783
	  for (octave_idx_type i = 0; i < vals.numel (); i++)
jwe@6406
  4784
	    {
dbateman@8196
  4785
	      h = gh_manager::lookup (vals.elem (i));
dbateman@8196
  4786
dbateman@8341
  4787
	      if (! h.ok ())
dbateman@8196
  4788
		{
dbateman@8196
  4789
		  error ("delete: invalid graphics object (= %g)", 
dbateman@8196
  4790
			 vals.elem (i));
dbateman@8196
  4791
		  break;
dbateman@8196
  4792
		}
jwe@6406
  4793
	    }
dbateman@8341
  4794
dbateman@8341
  4795
	  if (! error_state)
dbateman@8341
  4796
	    {
dbateman@8341
  4797
	      for (octave_idx_type i = 0; i < vals.numel (); i++)
dbateman@8341
  4798
		{
dbateman@8341
  4799
		  h = gh_manager::lookup (vals.elem (i));
dbateman@8341
  4800
dbateman@8341
  4801
		  if (h.ok ())
dbateman@8341
  4802
		    {
dbateman@8341
  4803
		      graphics_object obj = gh_manager::get_object (h);
dbateman@8341
  4804
dbateman@8341
  4805
		      // Don't do recursive deleting, due to callbacks
dbateman@8341
  4806
		      if (! obj.get_properties ().is_beingdeleted ())
dbateman@8341
  4807
			{
dbateman@8341
  4808
			  graphics_handle parent_h = obj.get_parent ();
dbateman@8341
  4809
dbateman@8341
  4810
			  graphics_object parent_obj = 
dbateman@8341
  4811
			    gh_manager::get_object (parent_h);
dbateman@8341
  4812
dbateman@8341
  4813
			  // NOTE: free the handle before removing it from its
dbateman@8341
  4814
			  //       parent's children, such that the object's 
dbateman@8341
  4815
			  //       state is correct when the deletefcn callback
dbateman@8341
  4816
			  //       is executed
dbateman@8341
  4817
dbateman@8341
  4818
			  gh_manager::free (h);
dbateman@8341
  4819
dbateman@8341
  4820
			  // A callback function might have already deleted 
dbateman@8341
  4821
			  // the parent
dbateman@8341
  4822
			  if (parent_obj.valid_object ())
dbateman@8341
  4823
			    parent_obj.remove_child (h);
dbateman@8341
  4824
dbateman@8341
  4825
			  Vdrawnow_requested = true;
dbateman@8341
  4826
			}
dbateman@8341
  4827
		    }
dbateman@8341
  4828
		}
dbateman@8341
  4829
	    }
jwe@6406
  4830
	}
jwe@6406
  4831
      else
jwe@6406
  4832
	error ("delete: invalid graphics object");
jwe@6406
  4833
    }
jwe@6406
  4834
  else
jwe@6406
  4835
    print_usage ();
jwe@6406
  4836
jwe@6406
  4837
  return retval;
jwe@6406
  4838
}
jwe@6406
  4839
jwe@6406
  4840
DEFUN (__go_axes_init__, args, ,
jwe@6406
  4841
  "-*- texinfo -*-\n\
jwe@6406
  4842
@deftypefn {Built-in Function} {} __go_axes_init__ (@var{h}, @var{mode})\n\
jwe@6945
  4843
Undocumented internal function.\n\
jwe@6406
  4844
@end deftypefn")
jwe@6406
  4845
{
jwe@7936
  4846
  gh_manager::autolock guard;
jwe@7936
  4847
jwe@6406
  4848
  octave_value retval;
jwe@6406
  4849
jwe@6406
  4850
  int nargin = args.length ();
jwe@6406
  4851
jwe@6406
  4852
  std::string mode = "";
jwe@6406
  4853
jwe@6406
  4854
  if (nargin == 2)
jwe@6406
  4855
    {
jwe@6406
  4856
      mode = args(1).string_value ();
jwe@6406
  4857
jwe@6406
  4858
      if (error_state)
jwe@6406
  4859
	return retval;
jwe@6406
  4860
    }
jwe@6406
  4861
jwe@6406
  4862
  if (nargin == 1 || nargin == 2)
jwe@6406
  4863
    {
jwe@6406
  4864
      graphics_handle h = octave_NaN;
jwe@6406
  4865
jwe@6406
  4866
      double val = args(0).double_value ();
jwe@6406
  4867
jwe@6406
  4868
      if (! error_state)
jwe@6406
  4869
	{
jwe@6406
  4870
	  h = gh_manager::lookup (val);
jwe@6406
  4871
jwe@7056
  4872
	  if (h.ok ())
jwe@6406
  4873
	    {
jwe@6406
  4874
	      graphics_object obj = gh_manager::get_object (h);
jwe@6406
  4875
jwe@6406
  4876
	      obj.set_defaults (mode);
jwe@8208
  4877
jwe@8208
  4878
	      h = gh_manager::lookup (val);
jwe@8208
  4879
	      if (! h.ok ())
jwe@8208
  4880
		error ("__go_axes_init__: axis deleted during initialization (= %g)", val);
jwe@6406
  4881
	    }
jwe@6406
  4882
	  else
jwe@6406
  4883
	    error ("__go_axes_init__: invalid graphics object (= %g)", val);
jwe@6406
  4884
	}
jwe@6406
  4885
      else
jwe@6406
  4886
	error ("__go_axes_init__: invalid graphics object");
jwe@6406
  4887
    }
jwe@6406
  4888
  else
jwe@6406
  4889
    print_usage ();
jwe@6406
  4890
jwe@6406
  4891
  return retval;
jwe@6406
  4892
}
jwe@6406
  4893
jwe@6406
  4894
DEFUN (__go_handles__, , ,
jwe@6406
  4895
   "-*- texinfo -*-\n\
jwe@6406
  4896
@deftypefn {Built-in Function} {} __go_handles__ ()\n\
jwe@6945
  4897
Undocumented internal function.\n\
jwe@6406
  4898
@end deftypefn")
jwe@6406
  4899
{
jwe@7936
  4900
  gh_manager::autolock guard;
jwe@7936
  4901
jwe@6425
  4902
  return octave_value (gh_manager::handle_list ());
jwe@6425
  4903
}
jwe@6425
  4904
jwe@6425
  4905
DEFUN (__go_figure_handles__, , ,
jwe@6425
  4906
   "-*- texinfo -*-\n\
jwe@6425
  4907
@deftypefn {Built-in Function} {} __go_figure_handles__ ()\n\
jwe@6945
  4908
Undocumented internal function.\n\
jwe@6425
  4909
@end deftypefn")
jwe@6425
  4910
{
jwe@7936
  4911
  gh_manager::autolock guard;
jwe@7936
  4912
jwe@6425
  4913
  return octave_value (gh_manager::figure_handle_list ());
jwe@6406
  4914
}
jwe@6406
  4915
jwe@7967
  4916
DEFUN (__go_execute_callback__, args, ,
jwe@7967
  4917
   "-*- texinfo -*-\n\
jwe@7967
  4918
@deftypefn {Built-in Function} {} __go_execute_callback__ (@var{h}, @var{name})\n\
jwe@7967
  4919
@deftypefnx {Built-in Function} {} __go_execute_callback__ (@var{h}, @var{name}, @var{param})\n\
jwe@7967
  4920
Undocumented internal function.\n\
jwe@7967
  4921
@end deftypefn")
jwe@7967
  4922
{
jwe@7967
  4923
  octave_value retval;
jwe@7967
  4924
jwe@7967
  4925
  int nargin = args.length ();
jwe@7967
  4926
jwe@7967
  4927
  if (nargin == 2 || nargin == 3)
jwe@7967
  4928
    {
jwe@7967
  4929
      double val = args(0).double_value ();
jwe@7967
  4930
jwe@7967
  4931
      if (! error_state)
jwe@7967
  4932
	{
jwe@7967
  4933
	  graphics_handle h = gh_manager::lookup (val);
jwe@7967
  4934
jwe@7967
  4935
	  if (h.ok ())
jwe@7967
  4936
	    {
jwe@7967
  4937
	      std::string name = args(1).string_value ();
jwe@7967
  4938
jwe@7967
  4939
	      if (! error_state)
jwe@7967
  4940
		{
jwe@7967
  4941
		  if (nargin == 2)
jwe@7967
  4942
		    gh_manager::execute_callback (h, name);
jwe@7967
  4943
		  else
jwe@7967
  4944
		    gh_manager::execute_callback (h, name, args(2));
jwe@7967
  4945
		}
jwe@7967
  4946
	      else
jwe@7967
  4947
		error ("__go_execute_callback__: invalid callback name");
jwe@7967
  4948
	    }
jwe@7967
  4949
	  else
jwe@7967
  4950
	    error ("__go_execute_callback__: invalid graphics object (= %g)",
jwe@7967
  4951
		   val);
jwe@7967
  4952
	}
jwe@7967
  4953
      else
jwe@7967
  4954
	error ("__go_execute_callback__: invalid graphics object");
jwe@7967
  4955
    }
jwe@7967
  4956
  else
jwe@7967
  4957
    print_usage ();
jwe@7967
  4958
jwe@7967
  4959
  return retval;
jwe@7967
  4960
}
jwe@7967
  4961
jwe@7924
  4962
DEFUN (available_backends, , ,
shaiay@7835
  4963
   "-*- texinfo -*-\n\
shaiay@7835
  4964
@deftypefn {Built-in Function} {} available_backends ()\n\
rdrider0-list@9318
  4965
Return a cell array of registered graphics backends.\n\
shaiay@7835
  4966
@end deftypefn")
shaiay@7835
  4967
{
jwe@7936
  4968
  gh_manager::autolock guard;
jwe@7936
  4969
shaiay@7835
  4970
  return octave_value (graphics_backend::available_backends_list ());
shaiay@7835
  4971
}
shaiay@7835
  4972
jwe@7409
  4973
static void
jwe@7409
  4974
clear_drawnow_request (void *)
jwe@7409
  4975
{
jwe@7409
  4976
  Vdrawnow_requested = false;
jwe@7409
  4977
}
jwe@7409
  4978
jwe@7408
  4979
DEFUN (drawnow, args, ,
jwe@7408
  4980
   "-*- texinfo -*-\n\
rdrider0-list@9318
  4981
@deftypefn  {Built-in Function} {} drawnow ()\n\
rdrider0-list@9318
  4982
@deftypefnx {Built-in Function} {} drawnow (\"expose\")\n\
rdrider0-list@9318
  4983
@deftypefnx {Built-in Function} {} drawnow (@var{term}, @var{file}, @var{mono}, @var{debug_file})\n\
rdrider0-list@9318
  4984
Update figure windows and their children.  The event queue is flushed and\n\
rdrider0-list@9318
  4985
any callbacks generated are executed.  With the optional argument\n\
rdrider0-list@9318
  4986
@code{\"expose\"}, only graphic objects are updated and no other events or\n\
rdrider0-list@9318
  4987
callbacks are processed.\n\
rdrider0-list@9318
  4988
The third calling form of @code{drawnow} is for debugging and is\n\
rdrider0-list@9318
  4989
undocumented.\n\
jwe@7408
  4990
@end deftypefn")
jwe@7408
  4991
{
jwe@7408
  4992
  static int drawnow_executing = 0;
jwe@7408
  4993
  static bool __go_close_all_registered__ = false;
jwe@7408
  4994
jwe@7408
  4995
  octave_value retval;
jwe@7408
  4996
jwe@7936
  4997
  gh_manager::lock ();
jwe@7936
  4998
jwe@7409
  4999
  unwind_protect::begin_frame ("Fdrawnow");
jwe@7409
  5000
  unwind_protect::add (clear_drawnow_request);
jwe@7409
  5001
jwe@7409
  5002
  unwind_protect_int (drawnow_executing);
jwe@7409
  5003
jwe@7409
  5004
  if (++drawnow_executing <= 1)
jwe@7408
  5005
    {
jwe@7409
  5006
      if (! __go_close_all_registered__)
jwe@7408
  5007
	{
jwe@7409
  5008
	  octave_add_atexit_function ("__go_close_all__");
jwe@7409
  5009
jwe@7409
  5010
	  __go_close_all_registered__ = true;
jwe@7409
  5011
	}
jwe@7409
  5012
jwe@7936
  5013
      if (args.length () == 0 || args.length () == 1)
jwe@7409
  5014
	{
jwe@7409
  5015
	  Matrix hlist = gh_manager::figure_handle_list ();
jwe@7409
  5016
jwe@7409
  5017
	  for (int i = 0; ! error_state && i < hlist.length (); i++)
jwe@7408
  5018
	    {
jwe@7409
  5019
	      graphics_handle h = gh_manager::lookup (hlist(i));
jwe@7409
  5020
jwe@7409
  5021
	      if (h.ok () && h != 0)
jwe@7408
  5022
		{
jwe@7409
  5023
		  graphics_object go = gh_manager::get_object (h);
jwe@7409
  5024
		  figure::properties& fprops = dynamic_cast <figure::properties&> (go.get_properties ());
jwe@7409
  5025
jwe@7409
  5026
		  if (fprops.is_modified ())
jwe@7408
  5027
		    {
jwe@7409
  5028
		      if (fprops.is_visible ())
jwe@7936
  5029
			{
jwe@7936
  5030
			  gh_manager::unlock ();
jwe@7936
  5031
jwe@8059
  5032
			  fprops.get_backend ().redraw_figure (go);
jwe@7936
  5033
jwe@7936
  5034
			  gh_manager::lock ();
jwe@7936
  5035
			}
jwe@8059
  5036
jwe@7409
  5037
		      fprops.set_modified (false);
jwe@7408
  5038
		    }
jwe@7408
  5039
		}
jwe@7408
  5040
	    }
jwe@7936
  5041
jwe@7936
  5042
	  bool do_events = true;
jwe@7936
  5043
jwe@7936
  5044
	  if (args.length () == 1)
jwe@7936
  5045
	    {
jwe@7936
  5046
	      caseless_str val (args(0).string_value ());
jwe@7936
  5047
jwe@7936
  5048
	      if (! error_state && val.compare ("expose"))
jwe@7936
  5049
		do_events = false;
jwe@7936
  5050
	      else
jwe@8687
  5051
		{
jwe@8687
  5052
		  error ("drawnow: invalid argument, expected `expose' as argument");
jwe@8687
  5053
		  return retval;
jwe@8687
  5054
		}
jwe@7936
  5055
	    }
jwe@7936
  5056
jwe@7936
  5057
	  if (do_events)
jwe@7936
  5058
	    {
jwe@7936
  5059
	      gh_manager::unlock ();
jwe@7936
  5060
jwe@7936
  5061
	      gh_manager::process_events ();
jwe@7936
  5062
jwe@7936
  5063
	      gh_manager::lock ();
jwe@7936
  5064
	    }
jwe@7408
  5065
	}
jwe@7409
  5066
      else if (args.length () >= 2 && args.length () <= 4)
jwe@7408
  5067
	{
jwe@7409
  5068
	  std::string term, file, debug_file;
jwe@7409
  5069
	  bool mono;
jwe@7409
  5070
jwe@7409
  5071
	  term = args(0).string_value ();
jwe@7408
  5072
jwe@7408
  5073
	  if (! error_state)
jwe@7408
  5074
	    {
jwe@7409
  5075
	      file = args(1).string_value ();
jwe@7408
  5076
jwe@7408
  5077
	      if (! error_state)
jwe@7408
  5078
		{
jwe@8007
  5079
		  size_t pos = file.find_last_of (file_ops::dir_sep_chars ());
jwe@7409
  5080
jwe@8021
  5081
		  if (pos != std::string::npos)
jwe@7409
  5082
		    {
jwe@8687
  5083
		      std::string dirname = file.substr (0, pos+1);
jwe@8687
  5084
jwe@8687
  5085
		      file_stat fs (dirname);
jwe@7409
  5086
jwe@7409
  5087
		      if (! (fs && fs.is_dir ()))
jwe@8687
  5088
			{
jwe@8687
  5089
			  error ("drawnow: nonexistent directory `%s'",
jwe@8687
  5090
				 dirname.c_str ());
jwe@8687
  5091
jwe@8687
  5092
			  return retval;
jwe@8687
  5093
			}
jwe@7409
  5094
		    }
jwe@7409
  5095
jwe@7409
  5096
		  mono = (args.length () >= 3 ? args(2).bool_value () : false);
jwe@7408
  5097
jwe@7408
  5098
		  if (! error_state)
jwe@7408
  5099
		    {
jwe@7409
  5100
		      debug_file = (args.length () > 3 ? args(3).string_value ()
jwe@7409
  5101
				    : "");
jwe@7409
  5102
jwe@7409
  5103
		      if (! error_state)
jwe@7408
  5104
			{
jwe@7409
  5105
			  graphics_handle h = gcf ();
jwe@7409
  5106
jwe@7409
  5107
			  if (h.ok ())
jwe@7409
  5108
			    {
jwe@7409
  5109
			      graphics_object go = gh_manager::get_object (h);
jwe@7409
  5110
jwe@7936
  5111
			      gh_manager::unlock ();
jwe@7936
  5112
jwe@7419
  5113
			      go.get_backend ()
jwe@8059
  5114
				.print_figure (go, term, file, mono, debug_file);
jwe@7936
  5115
jwe@7936
  5116
			      gh_manager::lock ();
jwe@7409
  5117
			    }
jwe@7409
  5118
			  else
jwe@7409
  5119
			    error ("drawnow: nothing to draw");
jwe@7408
  5120
			}
jwe@7408
  5121
		      else
jwe@7409
  5122
			error ("drawnow: invalid debug_file, expected a string value");
jwe@7408
  5123
		    }
jwe@7408
  5124
		  else
jwe@7409
  5125
		    error ("drawnow: invalid colormode, expected a boolean value");
jwe@7408
  5126
		}
jwe@7408
  5127
	      else
jwe@7409
  5128
		error ("drawnow: invalid file, expected a string value");
jwe@7408
  5129
	    }
jwe@7408
  5130
	  else
jwe@7409
  5131
	    error ("drawnow: invalid terminal, expected a string value");
jwe@7408
  5132
	}
jwe@7408
  5133
      else
jwe@7409
  5134
	print_usage ();
jwe@7408
  5135
    }
jwe@7409
  5136
jwe@7409
  5137
  unwind_protect::run_frame ("Fdrawnow");
jwe@7408
  5138
jwe@7936
  5139
  gh_manager::unlock ();
jwe@7936
  5140
jwe@7408
  5141
  return retval;
jwe@7408
  5142
}
jwe@7408
  5143
michael@7859
  5144
DEFUN (addlistener, args, ,
michael@7849
  5145
   "-*- texinfo -*-\n\
michael@7859
  5146
@deftypefn {Built-in Function} {} addlistener (@var{h}, @var{prop}, @var{fcn})\n\
michael@7849
  5147
Register @var{fcn} as listener for the property @var{prop} of the graphics\n\
rdrider0-list@9040
  5148
object @var{h}.  Property listeners are executed (in order of registration)\n\
rdrider0-list@9040
  5149
when the property is set.  The new value is already available when the\n\
michael@7849
  5150
listeners are executed.\n\
michael@7849
  5151
\n\
michael@7849
  5152
@var{prop} must be a string naming a valid property in @var{h}.\n\
michael@7849
  5153
\n\
michael@7849
  5154
@var{fcn} can be a function handle, a string or a cell array whose first\n\
rdrider0-list@9040
  5155
element is a function handle.  If @var{fcn} is a function handle, the\n\
michael@7849
  5156
corresponding function should accept at least 2 arguments, that will be\n\
rdrider0-list@9040
  5157
set to the object handle and the empty matrix respectively.  If @var{fcn}\n\
rdrider0-list@9040
  5158
is a string, it must be any valid octave expression.  If @var{fcn} is a cell\n\
michael@7849
  5159
array, the first element must be a function handle with the same signature\n\
rdrider0-list@9040
  5160
as described above.  The next elements of the cell array are passed\n\
michael@7849
  5161
as additional arguments to the function.\n\
michael@7849
  5162
\n\
michael@7864
  5163
Example:\n\
michael@7864
  5164
\n\
michael@7849
  5165
@example\n\
rdrider0-list@9064
  5166
@group\n\
michael@7849
  5167
function my_listener (h, dummy, p1)\n\
michael@7849
  5168
  fprintf (\"my_listener called with p1=%s\\n\", p1);\n\
michael@7849
  5169
endfunction\n\
michael@7849
  5170
\n\
michael@7859
  5171
addlistener (gcf, \"position\", @{@@my_listener, \"my string\"@})\n\
rdrider0-list@9064
  5172
@end group\n\
michael@7849
  5173
@end example\n\
michael@7849
  5174
\n\
michael@7849
  5175
@end deftypefn")
michael@7849
  5176
{
jwe@7936
  5177
  gh_manager::autolock guard;
jwe@7936
  5178
michael@7849
  5179
  octave_value retval;
michael@7849
  5180
michael@7849
  5181
  if (args.length () == 3)
michael@7849
  5182
    {
michael@7849
  5183
      double h = args(0).double_value ();
michael@7849
  5184
michael@7849
  5185
      if (! error_state)
michael@7849
  5186
	{
michael@7849
  5187
	  std::string pname = args(1).string_value ();
michael@7849
  5188
michael@7849
  5189
	  if (! error_state)
michael@7849
  5190
	    {
michael@7849
  5191
	      graphics_handle gh = gh_manager::lookup (h);
michael@7849
  5192
michael@7849
  5193
	      if (gh.ok ())
michael@7849
  5194
		{
michael@7849
  5195
		  graphics_object go = gh_manager::get_object (gh);
michael@7849
  5196
michael@7849
  5197
		  go.add_property_listener (pname, args(2), POSTSET);
michael@7849
  5198
		}
michael@7849
  5199
	      else
michael@7859
  5200
		error ("addlistener: invalid graphics object (= %g)",
michael@7849
  5201
		       h);
michael@7849
  5202
	    }
michael@7849
  5203
	  else
michael@7859
  5204
	    error ("addlistener: invalid property name, expected a string value");
michael@7849
  5205
	}
michael@7849
  5206
      else
michael@7859
  5207
	error ("addlistener: invalid handle");
michael@7849
  5208
    }
michael@7849
  5209
  else
michael@7849
  5210
    print_usage ();
michael@7849
  5211
michael@7849
  5212
  return retval;
michael@7849
  5213
}
michael@7849
  5214
dbateman@8299
  5215
DEFUN (dellistener, args, ,
dbateman@8299
  5216
   "-*- texinfo -*-\n\
dbateman@8299
  5217
@deftypefn {Built-in Function} {} dellistener (@var{h}, @var{prop}, @var{fcn})\n\
dbateman@8299
  5218
Remove the registration of @var{fcn} as a listener for the property\n\
rdrider0-list@9040
  5219
@var{prop} of the graphics object @var{h}.  The function @var{fcn} must\n\
dbateman@8299
  5220
be the same variable (not just the same value), as was passed to the\n\
dbateman@8299
  5221
original call to @code{addlistener}.\n\
dbateman@8299
  5222
\n\
dbateman@8299
  5223
If @var{fcn} is not defined then all listener functions of @var{prop}\n\
dbateman@8299
  5224
are removed.\n\
dbateman@8299
  5225
\n\
dbateman@8299
  5226
Example:\n\
dbateman@8299
  5227
\n\
dbateman@8299
  5228
@example\n\
rdrider0-list@9064
  5229
@group\n\
dbateman@8299
  5230
function my_listener (h, dummy, p1)\n\
dbateman@8299
  5231
  fprintf (\"my_listener called with p1=%s\\n\", p1);\n\
dbateman@8299
  5232
endfunction\n\
dbateman@8299
  5233
\n\
dbateman@8299
  5234
c = @{@@my_listener, \"my string\"@};\n\
dbateman@8299
  5235
addlistener (gcf, \"position\", c);\n\
dbateman@8299
  5236
dellistener (gcf, \"position\", c);\n\
rdrider0-list@9064
  5237
@end group\n\
dbateman@8299
  5238
@end example\n\
dbateman@8299
  5239
\n\
dbateman@8299
  5240
@end deftypefn")
dbateman@8299
  5241
{
dbateman@8299
  5242
  gh_manager::autolock guard;
dbateman@8299
  5243
dbateman@8299
  5244
  octave_value retval;
dbateman@8299
  5245
dbateman@8299
  5246
  if (args.length () == 3 || args.length () == 2)
dbateman@8299
  5247
    {
dbateman@8299
  5248
      double h = args(0).double_value ();
dbateman@8299
  5249
dbateman@8299
  5250
      if (! error_state)
dbateman@8299
  5251
	{
dbateman@8299
  5252
	  std::string pname = args(1).string_value ();
dbateman@8299
  5253
dbateman@8299
  5254
	  if (! error_state)
dbateman@8299
  5255
	    {
dbateman@8299
  5256
	      graphics_handle gh = gh_manager::lookup (h);
dbateman@8299
  5257
dbateman@8299
  5258
	      if (gh.ok ())
dbateman@8299
  5259
		{
dbateman@8299
  5260
		  graphics_object go = gh_manager::get_object (gh);
dbateman@8299
  5261
dbateman@8299
  5262
		  if (args.length () == 2)
dbateman@8299
  5263
		    go.delete_property_listener (pname, octave_value (), POSTSET);
dbateman@8299
  5264
		  else
dbateman@8299
  5265
		    go.delete_property_listener (pname, args(2), POSTSET);
dbateman@8299
  5266
		}
dbateman@8299
  5267
	      else
dbateman@8299
  5268
		error ("dellistener: invalid graphics object (= %g)",
dbateman@8299
  5269
		       h);
dbateman@8299
  5270
	    }
dbateman@8299
  5271
	  else
dbateman@8299
  5272
	    error ("dellistener: invalid property name, expected a string value");
dbateman@8299
  5273
	}
dbateman@8299
  5274
      else
dbateman@8299
  5275
	error ("dellistener: invalid handle");
dbateman@8299
  5276
    }
dbateman@8299
  5277
  else
dbateman@8299
  5278
    print_usage ();
dbateman@8299
  5279
dbateman@8299
  5280
  return retval;
dbateman@8299
  5281
}
dbateman@8299
  5282
michael@7864
  5283
DEFUN (addproperty, args, ,
jwe@7869
  5284
  "-*- texinfo -*-\n\
jwe@7869
  5285
@deftypefn {Built-in Function} {} addproperty (@var{name}, @var{h}, @var{type}, [@var{arg}, @dots{}])\n\
michael@7864
  5286
Create a new property named @var{name} in graphics object @var{h}.\n\
rdrider0-list@9040
  5287
@var{type} determines the type of the property to create.  @var{args}\n\
michael@7864
  5288
usually contains the default value of the property, but additional\n\
michael@7864
  5289
arguments might be given, depending on the type of the property.\n\
michael@7864
  5290
\n\
michael@7864
  5291
The supported property types are:\n\
michael@7864
  5292
\n\
michael@7864
  5293
@table @code\n\
michael@7864
  5294
@item string\n\
rdrider0-list@9040
  5295
A string property.  @var{arg} contains the default string value.\n\
michael@7864
  5296
@item any\n\
rdrider0-list@9040
  5297
An un-typed property.  This kind of property can hold any octave\n\
rdrider0-list@9040
  5298
value.  @var{args} contains the default value.\n\
michael@7864
  5299
@item radio\n\
rdrider0-list@9040
  5300
A string property with a limited set of accepted values.  The first\n\
michael@7864
  5301
argument must be a string with all accepted values separated by\n\
rdrider0-list@9040
  5302
a vertical bar ('|').  The default value can be marked by enclosing\n\
rdrider0-list@9040
  5303
it with a '@{' '@}' pair.  The default value may also be given as\n\
michael@7864
  5304
an optional second string argument.\n\
michael@7864
  5305
@item boolean\n\
rdrider0-list@9040
  5306
A boolean property.  This property type is equivalent to a radio\n\
rdrider0-list@9040
  5307
property with \"on|off\" as accepted values.  @var{arg} contains\n\
michael@7864
  5308
the default property value.\n\
michael@7864
  5309
@item double\n\
rdrider0-list@9040
  5310
A scalar double property.  @var{arg} contains the default value.\n\
michael@7864
  5311
@item handle\n\
rdrider0-list@9040
  5312
A handle property.  This kind of property holds the handle of a\n\
rdrider0-list@9040
  5313
graphics object.  @var{arg} contains the default handle value.\n\
michael@7864
  5314
When no default value is given, the property is initialized to\n\
michael@7864
  5315
the empty matrix.\n\
michael@7864
  5316
@item data\n\
rdrider0-list@9040
  5317
A data (matrix) property.  @var{arg} contains the default data\n\
rdrider0-list@9040
  5318
value.  When no default value is given, the data is initialized to\n\
michael@7864
  5319
the empty matrix.\n\
michael@7864
  5320
@item color\n\
rdrider0-list@9040
  5321
A color property.  @var{arg} contains the default color value.\n\
michael@7864
  5322
When no default color is given, the property is set to black.\n\
michael@7864
  5323
An optional second string argument may be given to specify an\n\
michael@7864
  5324
additional set of accepted string values (like a radio property).\n\
michael@7864
  5325
@end table\n\
michael@7864
  5326
\n\
michael@7864
  5327
@var{type} may also be the concatenation of a core object type and\n\
rdrider0-list@9040
  5328
a valid property name for that object type.  The property created\n\
michael@7864
  5329
then has the same characteristics as the referenced property (type,\n\
rdrider0-list@9040
  5330
possible values, hidden state@dots{}).  This allows to clone an existing\n\
michael@7864
  5331
property into the graphics object @var{h}.\n\
michael@7864
  5332
\n\
michael@7864
  5333
Examples:\n\
michael@7864
  5334
\n\
michael@7864
  5335
@example\n\
rdrider0-list@9064
  5336
@group\n\
michael@7864
  5337
addproperty (\"my_property\", gcf, \"string\", \"a string value\");\n\
michael@7864
  5338
addproperty (\"my_radio\", gcf, \"radio\", \"val_1|val_2|@{val_3@}\");\n\
michael@7864
  5339
addproperty (\"my_style\", gcf, \"linelinestyle\", \"--\");\n\
rdrider0-list@9064
  5340
@end group\n\
michael@7864
  5341
@end example\n\
michael@7864
  5342
\n\
michael@7864
  5343
@end deftypefn")
michael@7864
  5344
{
jwe@7936
  5345
  gh_manager::autolock guard;
jwe@7936
  5346
michael@7864
  5347
  octave_value retval;
michael@7864
  5348
michael@7864
  5349
  if (args.length () >= 3)
michael@7864
  5350
    {
michael@7864
  5351
      std::string name = args(0).string_value ();
michael@7864
  5352
michael@7864
  5353
      if (! error_state)
michael@7864
  5354
	{
michael@7864
  5355
	  double h = args(1).double_value ();
michael@7864
  5356
michael@7864
  5357
	  if (! error_state)
michael@7864
  5358
	    {
michael@7864
  5359
	      graphics_handle gh = gh_manager::lookup (h);
michael@7864
  5360
michael@7864
  5361
	      if (gh.ok ())
michael@7864
  5362
		{
michael@7864
  5363
		  graphics_object go = gh_manager::get_object (gh);
michael@7864
  5364
michael@7864
  5365
		  std::string type = args(2).string_value ();
michael@7864
  5366
michael@7864
  5367
		  if (! error_state)
michael@7864
  5368
		    {
michael@7864
  5369
		      if (! go.get_properties ().has_property (name))
michael@7864
  5370
			{
michael@7864
  5371
			  property p = property::create (name, gh, type,
michael@7864
  5372
							 args.splice (0, 3));
michael@7864
  5373
michael@7864
  5374
			  if (! error_state)
michael@7864
  5375
			    go.get_properties ().insert_property (name, p);
michael@7864
  5376
			}
michael@7864
  5377
		      else
michael@7864
  5378
			error ("addproperty: a `%s' property already exists in the graphics object",
michael@7864
  5379
			       name.c_str ());
michael@7864
  5380
		    }
michael@7864
  5381
		  else
michael@7864
  5382
		    error ("addproperty: invalid property type, expected a string value");
michael@7864
  5383
		}
michael@7864
  5384
	      else
michael@7864
  5385
		error ("addproperty: invalid graphics object (= %g)", h);
michael@7864
  5386
	    }
michael@7864
  5387
	  else
michael@7864
  5388
	    error ("addproperty: invalid handle value");
michael@7864
  5389
	}
michael@7864
  5390
      else
michael@7864
  5391
	error ("addproperty: invalid property name, expected a string value");
michael@7864
  5392
    }
michael@7864
  5393
  else
michael@7864
  5394
    print_usage ();
michael@7864
  5395
michael@7864
  5396
  return retval;
michael@7864
  5397
}
michael@7864
  5398
dbateman@6595
  5399
octave_value
jwe@7447
  5400
get_property_from_handle (double handle, const std::string& property,
jwe@7447
  5401
			  const std::string& func)
dbateman@6595
  5402
{
jwe@7936
  5403
  gh_manager::autolock guard;
jwe@7936
  5404
dbateman@6595
  5405
  graphics_object obj = gh_manager::get_object (handle);
dbateman@6595
  5406
  octave_value retval;
dbateman@6595
  5407
dbateman@6595
  5408
  if (obj)
dbateman@6595
  5409
    {
dbateman@7189
  5410
      caseless_str p = std::string (property);
dbateman@6595
  5411
      retval = obj.get (p);
dbateman@6595
  5412
    }
dbateman@6595
  5413
  else
dbateman@6595
  5414
    error ("%s: invalid handle (= %g)", func.c_str(), handle);
dbateman@6595
  5415
dbateman@6595
  5416
  return retval;
dbateman@6595
  5417
}
dbateman@6595
  5418
dbateman@6595
  5419
bool
jwe@7447
  5420
set_property_in_handle (double handle, const std::string& property,
jwe@7447
  5421
			const octave_value& arg, const std::string& func)
dbateman@6595
  5422
{
jwe@7936
  5423
  gh_manager::autolock guard;
jwe@7936
  5424
dbateman@6595
  5425
  graphics_object obj = gh_manager::get_object (handle);
dbateman@6595
  5426
  int ret = false;
dbateman@6595
  5427
dbateman@6595
  5428
  if (obj)
dbateman@6595
  5429
    {
dbateman@7189
  5430
      caseless_str p = std::string (property);
dbateman@6595
  5431
      obj.set (p, arg);
dbateman@6595
  5432
      if (!error_state)
dbateman@6595
  5433
	ret = true;
dbateman@6595
  5434
    }
dbateman@6595
  5435
  else
dbateman@6595
  5436
    error ("%s: invalid handle (= %g)", func.c_str(), handle);
dbateman@6595
  5437
dbateman@6595
  5438
  return ret;
dbateman@6595
  5439
}
dbateman@6595
  5440
jwe@6406
  5441
/*
jwe@6406
  5442
;;; Local Variables: ***
jwe@6406
  5443
;;; mode: C++ ***
jwe@6406
  5444
;;; End: ***
jwe@6406
  5445
*/