GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
graphics.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2007-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <cctype>
28 #include <cfloat>
29 #include <cstdlib>
30 
31 #include <algorithm>
32 #include <list>
33 #include <map>
34 #include <set>
35 #include <string>
36 #include <sstream>
37 
38 #include "cmd-edit.h"
39 #include "file-ops.h"
40 #include "file-stat.h"
41 #include "oct-locbuf.h"
42 #include "oct-time.h"
43 #include "singleton-cleanup.h"
44 
45 #include "builtin-defun-decls.h"
46 #include "defun.h"
47 #include "display.h"
48 #include "error.h"
49 #include "graphics.h"
50 #include "input.h"
51 #include "interpreter.h"
52 #include "ov.h"
53 #include "ovl.h"
54 #include "oct-map.h"
55 #include "ov-fcn-handle.h"
56 #include "pager.h"
57 #include "parse.h"
58 #include "text-renderer.h"
59 #include "unwind-prot.h"
60 #include "utils.h"
61 #include "octave-default-image.h"
62 
63 // forward declarations
64 static octave_value xget (const graphics_handle& h, const caseless_str& name);
65 
66 OCTAVE_NORETURN static
67 void
69 {
70  error ("set: invalid value for %s property", pname.c_str ());
71 }
72 
73 // Check to see that PNAME matches just one of PNAMES uniquely.
74 // Return the full name of the match, or an empty caseless_str object
75 // if there is no match, or the match is ambiguous.
76 
77 static caseless_str
79  const std::set<std::string>& pnames,
80  const caseless_str& pname)
81 {
82  size_t len = pname.length ();
83  std::set<std::string> matches;
84 
85  // Find exact or partial matches to property name
86  for (const auto& propnm : pnames)
87  {
88  if (pname.compare (propnm, len))
89  {
90  if (len == propnm.length ())
91  return pname; // Exact match.
92 
93  matches.insert (propnm);
94  }
95  }
96 
97  size_t num_matches = matches.size ();
98 
99  if (num_matches == 0)
100  error ("%s: unknown %s property %s",
101  who.c_str (), what.c_str (), pname.c_str ());
102  else if (num_matches > 1)
103  {
104  string_vector sv (matches);
105 
106  std::ostringstream os;
107 
108  sv.list_in_columns (os);
109 
110  std::string match_list = os.str ();
111 
112  error ("%s: ambiguous %s property name %s; possible matches:\n\n%s",
113  who.c_str (), what.c_str (), pname.c_str (), match_list.c_str ());
114  }
115  else if (num_matches == 1)
116  {
117  // Exact match was handled above.
118  std::string possible_match = *(matches.begin ());
119 
120  warning_with_id ("Octave:abbreviated-property-match",
121  "%s: allowing %s to match %s property %s",
122  who.c_str (), pname.c_str (), what.c_str (),
123  possible_match.c_str ());
124 
125  return possible_match;
126  }
127 
128  return caseless_str ();
129 }
130 
131 static Matrix
133 {
134  // The values below have been produced by viridis (64)(:)
135  // It would be nice to be able to feval the
136  // viridis function but since there is a static property object that includes
137  // a colormap_property object, we need to initialize this before main is
138  // even called, so calling an interpreted function is not possible.
139 
140  const double cmapv[] =
141  {
142  2.67004010000000e-01, 2.72651720952381e-01, 2.77106307619048e-01,
143  2.80356151428571e-01, 2.82390045238095e-01, 2.83204606666667e-01,
144  2.82809341428571e-01, 2.81230763333333e-01, 2.78516153333333e-01,
145  2.74735528571429e-01, 2.69981791904762e-01, 2.64368580952381e-01,
146  2.58026184285714e-01, 2.51098684761905e-01, 2.43732853333333e-01,
147  2.36073294285714e-01, 2.28263191428571e-01, 2.20424955714286e-01,
148  2.12666598571429e-01, 2.05079113809524e-01, 1.97721880952381e-01,
149  1.90631350000000e-01, 1.83819438571429e-01, 1.77272360952381e-01,
150  1.70957518571429e-01, 1.64832915714286e-01, 1.58845368095238e-01,
151  1.52951235714286e-01, 1.47131626666667e-01, 1.41402210952381e-01,
152  1.35832975714286e-01, 1.30582113809524e-01, 1.25898377619048e-01,
153  1.22163105714286e-01, 1.19872409523810e-01, 1.19626570000000e-01,
154  1.22045948571429e-01, 1.27667691904762e-01, 1.36834947142857e-01,
155  1.49643331428571e-01, 1.65967274285714e-01, 1.85538397142857e-01,
156  2.08030450000000e-01, 2.33127309523809e-01, 2.60531475238095e-01,
157  2.90000730000000e-01, 3.21329971428571e-01, 3.54355250000000e-01,
158  3.88930322857143e-01, 4.24933143333333e-01, 4.62246770476190e-01,
159  5.00753620000000e-01, 5.40336957142857e-01, 5.80861172380952e-01,
160  6.22170772857143e-01, 6.64087320476191e-01, 7.06403823333333e-01,
161  7.48885251428571e-01, 7.91273132857143e-01, 8.33302102380952e-01,
162  8.74717527142857e-01, 9.15296319047619e-01, 9.54839555238095e-01,
163  9.93247890000000e-01, 4.87433000000000e-03, 2.58456800000000e-02,
164  5.09139004761905e-02, 7.42014957142857e-02, 9.59536042857143e-02,
165  1.16893314761905e-01, 1.37350195714286e-01, 1.57479940000000e-01,
166  1.77347967619048e-01, 1.96969168571429e-01, 2.16330337619048e-01,
167  2.35404660952381e-01, 2.54161735714286e-01, 2.72573219047619e-01,
168  2.90619516666667e-01, 3.08291041428571e-01, 3.25586450952381e-01,
169  3.42517215238095e-01, 3.59102207142857e-01, 3.75366067142857e-01,
170  3.91340913333333e-01, 4.07061480000000e-01, 4.22563764285714e-01,
171  4.37885543809524e-01, 4.53062984285714e-01, 4.68129543809524e-01,
172  4.83117059523810e-01, 4.98052961428571e-01, 5.12959473333333e-01,
173  5.27854311428571e-01, 5.42750087142857e-01, 5.57652481904762e-01,
174  5.72563073333333e-01, 5.87476284285714e-01, 6.02382410952381e-01,
175  6.17265840000000e-01, 6.32106955714286e-01, 6.46881817142857e-01,
176  6.61562926190476e-01, 6.76119717142857e-01, 6.90518987142857e-01,
177  7.04725181904762e-01, 7.18700950000000e-01, 7.32406441904762e-01,
178  7.45802021904762e-01, 7.58846480000000e-01, 7.71497934761905e-01,
179  7.83714033809524e-01, 7.95453081428571e-01, 8.06673890000000e-01,
180  8.17337565714286e-01, 8.27409135714286e-01, 8.36858167619048e-01,
181  8.45663399523809e-01, 8.53815582857143e-01, 8.61321019047619e-01,
182  8.68206316666667e-01, 8.74522215714286e-01, 8.80346158571429e-01,
183  8.85780083333333e-01, 8.90945338571429e-01, 8.95973498571429e-01,
184  9.01005800000000e-01, 9.06156570000000e-01, 3.29415190000000e-01,
185  3.53367293333333e-01, 3.76236064761905e-01, 3.97901482857143e-01,
186  4.18250757142857e-01, 4.37178920000000e-01, 4.54595888571429e-01,
187  4.70433883333333e-01, 4.84653865714286e-01, 4.97250492857143e-01,
188  5.08254501428571e-01, 5.17731949047619e-01, 5.25780221428571e-01,
189  5.32522206190476e-01, 5.38097133333333e-01, 5.42651800000000e-01,
190  5.46335411904762e-01, 5.49287148571429e-01, 5.51635008571429e-01,
191  5.53493173333333e-01, 5.54953478571429e-01, 5.56089070000000e-01,
192  5.56952166666667e-01, 5.57576145714286e-01, 5.57974025714286e-01,
193  5.58142745238095e-01, 5.58058673809524e-01, 5.57684744285714e-01,
194  5.56973310000000e-01, 5.55864478571429e-01, 5.54288677142857e-01,
195  5.52175699047619e-01, 5.49445382857143e-01, 5.46023368571429e-01,
196  5.41830633809524e-01, 5.36795616666667e-01, 5.30847985714286e-01,
197  5.23924198571429e-01, 5.15966779523810e-01, 5.06924262857143e-01,
198  4.96751861428571e-01, 4.85412122857143e-01, 4.72873300000000e-01,
199  4.59105875238095e-01, 4.44095883333333e-01, 4.27825852857143e-01,
200  4.10292713809524e-01, 3.91487632857143e-01, 3.71420688571429e-01,
201  3.50098750000000e-01, 3.27544678571429e-01, 3.03798967142857e-01,
202  2.78916748571429e-01, 2.53000856190476e-01, 2.26223670000000e-01,
203  1.98879439523810e-01, 1.71494930000000e-01, 1.45037631428572e-01,
204  1.21291048571429e-01, 1.03326155238095e-01, 9.53507900000000e-02,
205  1.00469958095238e-01, 1.17876387142857e-01, 1.43936200000000e-01
206  };
207 
208  // It would be nice if Matrix had a ctor allowing to do the
209  // following without a copy
210  Matrix cmap (64, 3, 0.0);
211  std::copy (cmapv, cmapv + (64*3), cmap.fortran_vec ());
212  return cmap;
213 }
214 
215 static double
217 {
218  return display_info::depth ();
219 }
220 
221 static Matrix
223 {
224  Matrix retval (1, 4);
225 
226  retval(0) = 1.0;
227  retval(1) = 1.0;
228  retval(2) = display_info::width ();
230 
231  return retval;
232 }
233 
234 static double
236 {
237  return (display_info::x_dpi () + display_info::y_dpi ()) / 2;
238 }
239 
240 static Matrix
242 {
243  Matrix retval (7, 3, 0.0);
244 
245  retval(0,1) = 0.447;
246  retval(0,2) = 0.741;
247 
248  retval(1,0) = 0.850;
249  retval(1,1) = 0.325;
250  retval(1,2) = 0.098;
251 
252  retval(2,0) = 0.929;
253  retval(2,1) = 0.694;
254  retval(2,2) = 0.125;
255 
256  retval(3,0) = 0.494;
257  retval(3,1) = 0.184;
258  retval(3,2) = 0.556;
259 
260  retval(4,0) = 0.466;
261  retval(4,1) = 0.674;
262  retval(4,2) = 0.188;
263 
264  retval(5,0) = 0.301;
265  retval(5,1) = 0.745;
266  retval(5,2) = 0.933;
267 
268  retval(6,0) = 0.635;
269  retval(6,1) = 0.078;
270  retval(6,2) = 0.184;
271 
272  return retval;
273 }
274 
275 static Matrix
276 default_lim (bool logscale = false)
277 {
278  Matrix m (1, 2);
279 
280  if (logscale)
281  {
282  m(0) = 0.1;
283  m(1) = 1.0;
284  }
285  else
286  {
287  m(0) = 0.0;
288  m(1) = 1.0;
289  }
290 
291  return m;
292 }
293 
294 static Matrix
296 {
297  Matrix retval (1, 2);
298 
299  retval(0) = 0;
300  retval(1) = 1;
301 
302  return retval;
303 }
304 
305 static Matrix
307 {
308  Matrix m (64, 64);
309 
310  int i = 0;
311  for (int col = 0; col < 64; col++)
312  for (int row = 0; row < 64; row++)
313  {
314  m(col,row) = static_cast<double> (default_im_data[i]);
315  i++;
316  }
317 
318  return m;
319 }
320 
321 static Matrix
323 {
324  Matrix m (3, 3);
325 
326  for (int col = 0; col < 3; col++)
327  for (int row = 0; row < 3; row++)
328  m(row,col) = col+1;
329 
330  return m;
331 }
332 
333 static Matrix
335 {
336  Matrix m (3, 3);
337 
338  for (int row = 0; row < 3; row++)
339  for (int col = 0; col < 3; col++)
340  m(row,col) = row+1;
341 
342  return m;
343 }
344 
345 static Matrix
347 {
348  Matrix m (3, 3, 0.0);
349 
350  for (int row = 0; row < 3; row++)
351  m(row,row) = 1.0;
352 
353  return m;
354 }
355 
356 static Matrix
358 {
359  return default_surface_zdata ();
360 }
361 
362 static Matrix
364 {
365  Matrix m (1, 3);
366 
367  m(0) = 1.0;
368  m(1) = 2.0;
369  m(2) = 3.0;
370 
371  return m;
372 }
373 
374 static Matrix
376 {
377  Matrix m (3, 2, 0.0);
378 
379  m(1) = 1.0;
380  m(3) = 1.0;
381  m(4) = 1.0;
382 
383  return m;
384 }
385 
386 static Matrix
388 {
389  Matrix m (3, 1, 0.0);
390 
391  m(1) = 1.0;
392 
393  return m;
394 }
395 
396 static Matrix
398 {
399  Matrix m (3, 1, 1.0);
400 
401  m(2) = 0.0;
402 
403  return m;
404 }
405 
406 static Matrix
408 {
409  Matrix m (1, 4);
410 
411  m(0) = 0.13;
412  m(1) = 0.11;
413  m(2) = 0.775;
414  m(3) = 0.815;
415 
416  return m;
417 }
418 
419 static Matrix
421 {
422  Matrix m (1, 4);
423 
424  m(0) = 0.0;
425  m(1) = 0.0;
426  m(2) = 1.0;
427  m(3) = 1.0;
428 
429  return m;
430 }
431 
432 static Matrix
434 {
435  Matrix m (1, 2);
436 
437  m(0) = 0.0;
438  m(1) = 90.0;
439 
440  return m;
441 }
442 
443 static Matrix
445 {
446  Matrix m (1, 6);
447 
448  m(0) = 0.0;
449  m(1) = 0.2;
450  m(2) = 0.4;
451  m(3) = 0.6;
452  m(4) = 0.8;
453  m(5) = 1.0;
454 
455  return m;
456 }
457 
458 static Matrix
460 {
461  Matrix m (1, 2);
462 
463  m(0) = 0.01;
464  m(1) = 0.025;
465 
466  return m;
467 }
468 
469 static Matrix
471 {
472  Matrix m (1, 4);
473 
474  m(0) = 300;
475  m(1) = 200;
476  m(2) = 560;
477  m(3) = 420;
478 
479  return m;
480 }
481 
482 static Matrix
484 {
485  Matrix m (1, 2);
486 
487  m(0) = 8.5;
488  m(1) = 11.0;
489 
490  return m;
491 }
492 
493 static Matrix
495 {
496  Matrix m (1, 4);
497 
498  m(0) = 0.25;
499  m(1) = 2.50;
500  m(2) = 8.00;
501  m(3) = 6.00;
502 
503  return m;
504 }
505 
506 static Matrix
508 {
509  Matrix retval (1, 4);
510 
511  retval(0) = 0;
512  retval(1) = 0;
513  retval(2) = 80;
514  retval(3) = 30;
515 
516  return retval;
517 }
518 
519 static Matrix
521 {
522  Matrix retval (1, 2);
523 
524  retval(0) = 0.01;
525  retval(1) = 0.1;
526 
527  return retval;
528 }
529 
530 static Matrix
532 {
533  Matrix retval (1, 4);
534 
535  retval(0) = 0;
536  retval(1) = 0;
537  retval(2) = 1;
538  retval(3) = 1;
539 
540  return retval;
541 }
542 
543 static Matrix
545 {
546  Matrix m (1, 3);
547 
548  m(0) = 1.0;
549  m(1) = 0.0;
550  m(2) = 1.0;
551 
552  return m;
553 }
554 
555 static double
556 convert_font_size (double font_size, const caseless_str& from_units,
557  const caseless_str& to_units, double parent_height = 0)
558 {
559  // Simple case where from_units == to_units
560 
561  if (from_units.compare (to_units))
562  return font_size;
563 
564  // Converts the given fontsize using the following transformation:
565  // <old_font_size> => points => <new_font_size>
566 
567  double points_size = 0;
568  double res = 0;
569 
570  if (from_units.compare ("points"))
571  points_size = font_size;
572  else
573  {
574  res = xget (0, "screenpixelsperinch").double_value ();
575 
576  if (from_units.compare ("pixels"))
577  points_size = font_size * 72.0 / res;
578  else if (from_units.compare ("inches"))
579  points_size = font_size * 72.0;
580  else if (from_units.compare ("centimeters"))
581  points_size = font_size * 72.0 / 2.54;
582  else if (from_units.compare ("normalized"))
583  points_size = font_size * parent_height * 72.0 / res;
584  }
585 
586  double new_font_size = 0;
587 
588  if (to_units.compare ("points"))
589  new_font_size = points_size;
590  else
591  {
592  if (res <= 0)
593  res = xget (0, "screenpixelsperinch").double_value ();
594 
595  if (to_units.compare ("pixels"))
596  new_font_size = points_size * res / 72.0;
597  else if (to_units.compare ("inches"))
598  new_font_size = points_size / 72.0;
599  else if (to_units.compare ("centimeters"))
600  new_font_size = points_size * 2.54 / 72.0;
601  else if (to_units.compare ("normalized"))
602  {
603  // Avoid setting font size to (0/0) = NaN
604 
605  if (parent_height > 0)
606  new_font_size = points_size * res / (parent_height * 72.0);
607  }
608  }
609 
610  return new_font_size;
611 }
612 
613 static Matrix
614 convert_position (const Matrix& pos, const caseless_str& from_units,
615  const caseless_str& to_units, const Matrix& parent_dim)
616 {
617  Matrix retval (1, pos.numel ());
618  double res = 0;
619  bool is_rectangle = (pos.numel () == 4);
620  bool is_2d = (pos.numel () == 2);
621 
622  if (from_units.compare ("pixels"))
623  retval = pos;
624  else if (from_units.compare ("normalized"))
625  {
626  retval(0) = pos(0) * parent_dim(0) + 1;
627  retval(1) = pos(1) * parent_dim(1) + 1;
628  if (is_rectangle)
629  {
630  retval(2) = pos(2) * parent_dim(0);
631  retval(3) = pos(3) * parent_dim(1);
632  }
633  else if (! is_2d)
634  retval(2) = 0;
635  }
636  else if (from_units.compare ("characters"))
637  {
638  if (res <= 0)
639  res = xget (0, "screenpixelsperinch").double_value ();
640 
641  double f = 0.0;
642 
643  // FIXME: this assumes the system font is Helvetica 10pt
644  // (for which "x" requires 6x12 pixels at 74.951 pixels/inch)
645  f = 12.0 * res / 74.951;
646 
647  if (f > 0)
648  {
649  retval(0) = 0.5 * pos(0) * f;
650  retval(1) = pos(1) * f;
651  if (is_rectangle)
652  {
653  retval(2) = 0.5 * pos(2) * f;
654  retval(3) = pos(3) * f;
655  }
656  else if (! is_2d)
657  retval(2) = 0;
658  }
659  }
660  else
661  {
662  if (res <= 0)
663  res = xget (0, "screenpixelsperinch").double_value ();
664 
665  double f = 0.0;
666 
667  if (from_units.compare ("points"))
668  f = res / 72.0;
669  else if (from_units.compare ("inches"))
670  f = res;
671  else if (from_units.compare ("centimeters"))
672  f = res / 2.54;
673 
674  if (f > 0)
675  {
676  retval(0) = pos(0) * f + 1;
677  retval(1) = pos(1) * f + 1;
678  if (is_rectangle)
679  {
680  retval(2) = pos(2) * f;
681  retval(3) = pos(3) * f;
682  }
683  else if (! is_2d)
684  retval(2) = 0;
685  }
686  }
687 
688  if (! to_units.compare ("pixels"))
689  {
690  if (to_units.compare ("normalized"))
691  {
692  retval(0) = (retval(0) - 1) / parent_dim(0);
693  retval(1) = (retval(1) - 1) / parent_dim(1);
694  if (is_rectangle)
695  {
696  retval(2) /= parent_dim(0);
697  retval(3) /= parent_dim(1);
698  }
699  else if (! is_2d)
700  retval(2) = 0;
701  }
702  else if (to_units.compare ("characters"))
703  {
704  if (res <= 0)
705  res = xget (0, "screenpixelsperinch").double_value ();
706 
707  double f = 0.0;
708 
709  f = 12.0 * res / 74.951;
710 
711  if (f > 0)
712  {
713  retval(0) = 2 * retval(0) / f;
714  retval(1) = retval(1) / f;
715  if (is_rectangle)
716  {
717  retval(2) = 2 * retval(2) / f;
718  retval(3) = retval(3) / f;
719  }
720  else if (! is_2d)
721  retval(2) = 0;
722  }
723  }
724  else
725  {
726  if (res <= 0)
727  res = xget (0, "screenpixelsperinch").double_value ();
728 
729  double f = 0.0;
730 
731  if (to_units.compare ("points"))
732  f = res / 72.0;
733  else if (to_units.compare ("inches"))
734  f = res;
735  else if (to_units.compare ("centimeters"))
736  f = res / 2.54;
737 
738  if (f > 0)
739  {
740  retval(0) = (retval(0) - 1) / f;
741  retval(1) = (retval(1) - 1) / f;
742  if (is_rectangle)
743  {
744  retval(2) /= f;
745  retval(3) /= f;
746  }
747  else if (! is_2d)
748  retval(2) = 0;
749  }
750  }
751  }
752  else if (! is_rectangle && ! is_2d)
753  retval(2) = 0;
754 
755  return retval;
756 }
757 
758 static Matrix
760  const caseless_str& from_units,
761  const caseless_str& to_units)
762 {
764  graphics_object ax = go.get_ancestor ("axes");
765 
766  Matrix retval;
767 
768  if (ax.valid_object ())
769  {
770  const axes::properties& ax_props =
771  dynamic_cast<const axes::properties&> (ax.get_properties ());
772  graphics_xform ax_xform = ax_props.get_transform ();
773  bool is_rectangle = (pos.numel () == 4);
774  Matrix ax_bbox = ax_props.get_boundingbox (true),
775  ax_size = ax_bbox.extract_n (0, 2, 1, 2);
776 
777  if (from_units.compare ("data"))
778  {
779  if (is_rectangle)
780  {
781  ColumnVector v1 = ax_xform.transform (pos(0), pos(1), 0),
782  v2 = ax_xform.transform (pos(0) + pos(2),
783  pos(1) + pos(3), 0);
784 
785  retval.resize (1, 4);
786 
787  retval(0) = v1(0) - ax_bbox(0) + 1;
788  retval(1) = ax_bbox(1) + ax_bbox(3) - v1(1) + 1;
789  retval(2) = v2(0) - v1(0);
790  retval(3) = v1(1) - v2(1);
791  }
792  else
793  {
794  ColumnVector v = ax_xform.transform (pos(0), pos(1), pos(2));
795 
796  retval.resize (1, 3);
797 
798  retval(0) = v(0) - ax_bbox(0) + 1;
799  retval(1) = ax_bbox(1) + ax_bbox(3) - v(1) + 1;
800  retval(2) = 0;
801  }
802  }
803  else
804  retval = convert_position (pos, from_units, "pixels", ax_size);
805 
806  if (! to_units.compare ("pixels"))
807  {
808  if (to_units.compare ("data"))
809  {
810  if (is_rectangle)
811  {
812  ColumnVector v1, v2;
813  v1 = ax_xform.untransform (
814  retval(0) + ax_bbox(0) - 1,
815  ax_bbox(1) + ax_bbox(3) - retval(1) + 1);
816  v2 = ax_xform.untransform (
817  retval(0) + retval(2) + ax_bbox(0) - 1,
818  ax_bbox(1) + ax_bbox(3) - (retval(1) + retval(3)) + 1);
819 
820  retval.resize (1, 4);
821 
822  retval(0) = v1(0);
823  retval(1) = v1(1);
824  retval(2) = v2(0) - v1(0);
825  retval(3) = v2(1) - v1(1);
826  }
827  else
828  {
829  ColumnVector v;
830  v = ax_xform.untransform (
831  retval(0) + ax_bbox(0) - 1,
832  ax_bbox(1) + ax_bbox(3) - retval(1) + 1);
833 
834  retval.resize (1, 3);
835 
836  retval(0) = v(0);
837  retval(1) = v(1);
838  retval(2) = v(2);
839  }
840  }
841  else
842  retval = convert_position (retval, "pixels", to_units, ax_size);
843  }
844  }
845 
846  return retval;
847 }
848 
849 // This function always returns the screensize in pixels
850 static Matrix
852 {
854  Matrix sz = obj.get ("screensize").matrix_value ();
855  return convert_position (sz, obj.get ("units").string_value (), "pixels",
856  sz.extract_n (0, 2, 1, 2)).extract_n (0, 2, 1, 2);
857 }
858 
859 static void
860 convert_cdata_2 (bool is_scaled, bool is_real, double clim_0, double clim_1,
861  const double *cmapv, double x, octave_idx_type lda,
862  octave_idx_type nc, octave_idx_type i, double *av)
863 {
864  if (is_scaled)
865  x = octave::math::fix (nc * (x - clim_0) / (clim_1 - clim_0));
866  else if (is_real)
867  x = octave::math::fix (x - 1);
868 
869  if (octave::math::isnan (x))
870  {
871  av[i] = x;
872  av[i+lda] = x;
873  av[i+2*lda] = x;
874  }
875  else
876  {
877  if (x < 0)
878  x = 0;
879  else if (x >= nc)
880  x = (nc - 1);
881 
882  octave_idx_type idx = static_cast<octave_idx_type> (x);
883 
884  av[i] = cmapv[idx];
885  av[i+lda] = cmapv[idx+nc];
886  av[i+2*lda] = cmapv[idx+2*nc];
887  }
888 }
889 
890 template <typename T>
891 void
892 convert_cdata_1 (bool is_scaled, bool is_real, double clim_0, double clim_1,
893  const double *cmapv, const T *cv, octave_idx_type lda,
894  octave_idx_type nc, double *av)
895 {
896  for (octave_idx_type i = 0; i < lda; i++)
897  convert_cdata_2 (is_scaled, is_real,
898  clim_0, clim_1, cmapv, cv[i], lda, nc, i, av);
899 }
900 
901 static octave_value
902 convert_cdata (const base_properties& props, const octave_value& cdata,
903  bool is_scaled, int cdim)
904 {
905  dim_vector dv (cdata.dims ());
906 
907  // TrueColor data doesn't require conversion
908  if (dv.ndims () == cdim && dv(cdim-1) == 3)
909  return cdata;
910 
911  Matrix cmap (1, 3, 0.0);
912  Matrix clim (1, 2, 0.0);
913 
915  graphics_object fig = go.get_ancestor ("figure");
916 
917  if (fig.valid_object ())
918  {
919  Matrix _cmap = fig.get (caseless_str ("colormap")).matrix_value ();
920 
921  cmap = _cmap;
922  }
923 
924  if (is_scaled)
925  {
926  graphics_object ax = go.get_ancestor ("axes");
927 
928  if (ax.valid_object ())
929  {
930  Matrix _clim = ax.get (caseless_str ("clim")).matrix_value ();
931 
932  clim = _clim;
933  }
934  }
935 
936  dv.resize (cdim);
937  dv(cdim-1) = 3;
938 
939  NDArray a (dv);
940 
941  octave_idx_type lda = a.numel () / static_cast<octave_idx_type> (3);
942  octave_idx_type nc = cmap.rows ();
943 
944  double *av = a.fortran_vec ();
945  const double *cmapv = cmap.data ();
946 
947  double clim_0 = clim(0);
948  double clim_1 = clim(1);
949 
950  // FIXME: There is a lot of processing time spent just on data conversion
951  // both here in graphics.cc and again in gl-render.cc. There must
952  // be room for improvement! Here a macro expands to a templated
953  // function which in turn calls another function (covert_cdata_2).
954  // And in gl-render.cc (opengl_renderer::draw_image), only GLfloat
955  // is supported anyways so there is another double for loop across
956  // height and width to convert all of the input data to GLfloat.
957 
958 #define CONVERT_CDATA_1(ARRAY_T, VAL_FN, IS_REAL) \
959  do \
960  { \
961  ARRAY_T tmp = cdata. VAL_FN ## array_value (); \
962  \
963  convert_cdata_1 (is_scaled, IS_REAL, clim_0, clim_1, cmapv, \
964  tmp.data (), lda, nc, av); \
965  } \
966  while (0)
967 
968  if (cdata.is_uint8_type ())
969  CONVERT_CDATA_1 (uint8NDArray, uint8_, false);
970  else if (cdata.is_uint16_type ())
971  CONVERT_CDATA_1 (uint16NDArray, uint16_, false);
972  else if (cdata.is_double_type ())
973  CONVERT_CDATA_1 (NDArray, , true);
974  else if (cdata.is_single_type ())
975  CONVERT_CDATA_1 (FloatNDArray, float_, true);
976  else if (cdata.is_bool_type ())
977  CONVERT_CDATA_1 (boolNDArray, bool_, false);
978  else
979  {
980  // Don't throw an error; leads to an incomplete FLTK object (bug #46933).
981  warning ("unsupported type for cdata (= %s). "
982  "Valid types are uint8, uint16, double, single, and bool.",
983  cdata.type_name ().c_str ());
984  a = NDArray (dv, 0); // return 0 instead
985  }
986 
987 #undef CONVERT_CDATA_1
988 
989  return octave_value (a);
990 }
991 
992 template <typename T>
993 static void
994 get_array_limits (const Array<T>& m, double& emin, double& emax,
995  double& eminp, double& emaxp)
996 {
997  const T *data = m.data ();
998  octave_idx_type n = m.numel ();
999 
1000  for (octave_idx_type i = 0; i < n; i++)
1001  {
1002  double e = double (data[i]);
1003 
1004  // Don't need to test for NaN here as NaN>x and NaN<x is always false
1005  if (! octave::math::isinf (e))
1006  {
1007  if (e < emin)
1008  emin = e;
1009 
1010  if (e > emax)
1011  emax = e;
1012 
1013  if (e > 0 && e < eminp)
1014  eminp = e;
1015 
1016  if (e < 0 && e > emaxp)
1017  emaxp = e;
1018  }
1019  }
1020 }
1021 
1022 static bool
1024  caseless_str& rest)
1025 {
1026  int len = name.length ();
1027  int offset = 0;
1028  bool result = false;
1029 
1030  if (len >= 4)
1031  {
1032  caseless_str pfx = name.substr (0, 4);
1033 
1034  if (pfx.compare ("axes") || pfx.compare ("line")
1035  || pfx.compare ("text"))
1036  offset = 4;
1037  else if (len >= 5)
1038  {
1039  pfx = name.substr (0, 5);
1040 
1041  if (pfx.compare ("image") || pfx.compare ("patch"))
1042  offset = 5;
1043  else if (len >= 6)
1044  {
1045  pfx = name.substr (0, 6);
1046 
1047  if (pfx.compare ("figure") || pfx.compare ("uimenu"))
1048  offset = 6;
1049  else if (len >= 7)
1050  {
1051  pfx = name.substr (0, 7);
1052 
1053  if (pfx.compare ("surface") || pfx.compare ("hggroup")
1054  || pfx.compare ("uipanel"))
1055  offset = 7;
1056  else if (len >= 9)
1057  {
1058  pfx = name.substr (0, 9);
1059 
1060  if (pfx.compare ("uicontrol")
1061  || pfx.compare ("uitoolbar"))
1062  offset = 9;
1063  else if (len >= 10)
1064  {
1065  pfx = name.substr (0, 10);
1066 
1067  if (pfx.compare ("uipushtool"))
1068  offset = 10;
1069  else if (len >= 12)
1070  {
1071  pfx = name.substr (0, 12);
1072 
1073  if (pfx.compare ("uitoggletool"))
1074  offset = 12;
1075  else if (len >= 13)
1076  {
1077  pfx = name.substr (0, 13);
1078 
1079  if (pfx.compare ("uicontextmenu") ||
1080  pfx.compare ("uibuttongroup"))
1081  offset = 13;
1082  }
1083  }
1084  }
1085  }
1086  }
1087  }
1088  }
1089 
1090  if (offset > 0)
1091  {
1092  go_name = pfx;
1093  rest = name.substr (offset);
1094  result = true;
1095  }
1096  }
1097 
1098  return result;
1099 }
1100 
1101 static base_graphics_object*
1103  const graphics_handle& h = graphics_handle (),
1104  const graphics_handle& p = graphics_handle ())
1105 {
1106  base_graphics_object *go = 0;
1107 
1108  if (type.compare ("figure"))
1109  go = new figure (h, p);
1110  else if (type.compare ("axes"))
1111  go = new axes (h, p);
1112  else if (type.compare ("line"))
1113  go = new line (h, p);
1114  else if (type.compare ("text"))
1115  go = new text (h, p);
1116  else if (type.compare ("image"))
1117  go = new image (h, p);
1118  else if (type.compare ("light"))
1119  go = new light (h, p);
1120  else if (type.compare ("patch"))
1121  go = new patch (h, p);
1122  else if (type.compare ("surface"))
1123  go = new surface (h, p);
1124  else if (type.compare ("hggroup"))
1125  go = new hggroup (h, p);
1126  else if (type.compare ("uimenu"))
1127  go = new uimenu (h, p);
1128  else if (type.compare ("uicontrol"))
1129  go = new uicontrol (h, p);
1130  else if (type.compare ("uipanel"))
1131  go = new uipanel (h, p);
1132  else if (type.compare ("uibuttongroup"))
1133  go = new uibuttongroup (h, p);
1134  else if (type.compare ("uicontextmenu"))
1135  go = new uicontextmenu (h, p);
1136  else if (type.compare ("uitoolbar"))
1137  go = new uitoolbar (h, p);
1138  else if (type.compare ("uipushtool"))
1139  go = new uipushtool (h, p);
1140  else if (type.compare ("uitoggletool"))
1141  go = new uitoggletool (h, p);
1142  return go;
1143 }
1144 
1145 // ---------------------------------------------------------------------
1146 
1147 bool
1148 base_property::set (const octave_value& v, bool do_run, bool do_notify_toolkit)
1149 {
1150  if (do_set (v))
1151  {
1152  // Notify graphics toolkit.
1153  if (id >= 0 && do_notify_toolkit)
1154  {
1156  if (go)
1157  go.update (id);
1158  }
1159 
1160  // run listeners
1161  if (do_run)
1163 
1164  return true;
1165  }
1166 
1167  return false;
1168 }
1169 
1170 void
1172 {
1173  const octave_value_list& l = listeners[mode];
1174 
1175  for (int i = 0; i < l.length (); i++)
1177 }
1178 
1180  : default_val (), possible_vals ()
1181 {
1182  size_t beg = 0;
1183  size_t len = opt_string.length ();
1184  bool done = len == 0;
1185 
1186  while (! done)
1187  {
1188  size_t end = opt_string.find ('|', beg);
1189 
1190  if (end == std::string::npos)
1191  {
1192  end = len;
1193  done = true;
1194  }
1195 
1196  std::string t = opt_string.substr (beg, end-beg);
1197 
1198  // Might want more error checking here...
1199  if (t[0] == '{')
1200  {
1201  t = t.substr (1, t.length () - 2);
1202  default_val = t;
1203  }
1204  else if (beg == 0) // ensure default value
1205  default_val = t;
1206 
1207  possible_vals.insert (t);
1208 
1209  beg = end + 1;
1210  }
1211 }
1212 
1215 {
1217  for (std::set<caseless_str>::const_iterator it = possible_vals.begin ();
1218  it != possible_vals.end (); it++)
1219  {
1220  if (retval.empty ())
1221  {
1222  if (*it == default_value ())
1223  retval = "{" + *it + "}";
1224  else
1225  retval = *it;
1226  }
1227  else
1228  {
1229  if (*it == default_value ())
1230  retval += " | {" + *it + "}";
1231  else
1232  retval += " | " + *it;
1233  }
1234  }
1235 
1236  if (! retval.empty ())
1237  retval = "[ " + retval + " ]";
1238 
1239  return retval;
1240 }
1241 
1242 Cell
1244 {
1245  octave_idx_type i = 0;
1246  Cell retval (nelem (), 1);
1247  for (std::set<caseless_str>::const_iterator it = possible_vals.begin ();
1248  it != possible_vals.end (); it++)
1249  retval(i++) = std::string (*it);
1250  return retval;
1251 }
1252 
1253 bool
1255 {
1256  bool retval = true;
1257 
1258  double tmp_rgb[3] = {0, 0, 0};
1259 
1260  std::string str = str_arg;
1261  unsigned int len = str.length ();
1262 
1263  std::transform (str.begin (), str.end (), str.begin (), tolower);
1264 
1265  if (str.compare (0, len, "blue", 0, len) == 0)
1266  tmp_rgb[2] = 1;
1267  else if (str.compare (0, len, "black", 0, len) == 0
1268  || str.compare (0, len, "k", 0, len) == 0)
1269  tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 0;
1270  else if (str.compare (0, len, "red", 0, len) == 0)
1271  tmp_rgb[0] = 1;
1272  else if (str.compare (0, len, "green", 0, len) == 0)
1273  tmp_rgb[1] = 1;
1274  else if (str.compare (0, len, "yellow", 0, len) == 0)
1275  tmp_rgb[0] = tmp_rgb[1] = 1;
1276  else if (str.compare (0, len, "magenta", 0, len) == 0)
1277  tmp_rgb[0] = tmp_rgb[2] = 1;
1278  else if (str.compare (0, len, "cyan", 0, len) == 0)
1279  tmp_rgb[1] = tmp_rgb[2] = 1;
1280  else if (str.compare (0, len, "white", 0, len) == 0
1281  || str.compare (0, len, "w", 0, len) == 0)
1282  tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 1;
1283  else
1284  retval = false;
1285 
1286  if (retval)
1287  {
1288  for (int i = 0; i < 3; i++)
1289  xrgb(i) = tmp_rgb[i];
1290  }
1291 
1292  return retval;
1293 }
1294 
1295 bool
1297 {
1298  if (val.is_string ())
1299  {
1300  std::string s = val.string_value ();
1301 
1302  if (s.empty ())
1303  error ("invalid value for color property \"%s\"",
1304  get_name ().c_str ());
1305 
1306  std::string match;
1307 
1308  if (radio_val.contains (s, match))
1309  {
1310  if (current_type != radio_t || match != current_val)
1311  {
1312  if (s.length () != match.length ())
1313  warning_with_id ("Octave:abbreviated-property-match",
1314  "%s: allowing %s to match %s value %s",
1315  "set", s.c_str (), get_name ().c_str (),
1316  match.c_str ());
1317  current_val = match;
1319  return true;
1320  }
1321  }
1322  else
1323  {
1324  try
1325  {
1326  color_values col (s);
1327 
1328  if (current_type != color_t || col != color_val)
1329  {
1330  color_val = col;
1332  return true;
1333  }
1334  }
1335  catch (octave::execution_exception& e)
1336  {
1337  error (e, "invalid value for color property \"%s\" (value = %s)",
1338  get_name ().c_str (), s.c_str ());
1339  }
1340  }
1341  }
1342  else if (val.is_numeric_type ())
1343  {
1344  Matrix m = val.matrix_value ();
1345 
1346  if (m.numel () != 3)
1347  error ("invalid value for color property \"%s\"",
1348  get_name ().c_str ());
1349 
1350  color_values col (m(0), m(1), m(2));
1351 
1352  if (current_type != color_t || col != color_val)
1353  {
1354  color_val = col;
1356  return true;
1357  }
1358  }
1359  else
1360  error ("invalid value for color property \"%s\"",
1361  get_name ().c_str ());
1362 
1363  return false;
1364 }
1365 
1366 bool
1368 {
1369  if (val.is_string ())
1370  {
1371  std::string s = val.string_value ();
1372  std::string match;
1373 
1374  if (s.empty () || ! radio_val.contains (s, match))
1375  error ("invalid value for double_radio property \"%s\"",
1376  get_name ().c_str ());
1377 
1378  if (current_type != radio_t || match != current_val)
1379  {
1380  if (s.length () != match.length ())
1381  warning_with_id ("Octave:abbreviated-property-match",
1382  "%s: allowing %s to match %s value %s",
1383  "set", s.c_str (), get_name ().c_str (),
1384  match.c_str ());
1385  current_val = match;
1387  return true;
1388  }
1389  }
1390  else if (val.is_scalar_type () && val.is_real_type ())
1391  {
1392  double new_dval = val.double_value ();
1393 
1394  if (current_type != double_t || new_dval != dval)
1395  {
1396  dval = new_dval;
1398  return true;
1399  }
1400  }
1401  else
1402  error ("invalid value for double_radio property \"%s\"",
1403  get_name ().c_str ());
1404 
1405  return false;
1406 }
1407 
1408 bool
1410 {
1411  bool xok = false;
1412 
1413  // check value type
1414  if (type_constraints.size () > 0)
1415  {
1416  if (type_constraints.find (v.class_name ()) != type_constraints.end ())
1417  xok = true;
1418 
1419  // check if complex is allowed (it's also of class "double", so
1420  // checking that alone is not enough to ensure real type)
1421  if (type_constraints.find ("real") != type_constraints.end ()
1422  && v.is_complex_type ())
1423  xok = false;
1424  }
1425  else
1426  xok = v.is_numeric_type () || v.is_bool_scalar ();
1427 
1428  if (xok)
1429  {
1430  if (size_constraints.size () == 0)
1431  return true;
1432 
1433  dim_vector vdims = v.dims ();
1434  int vlen = vdims.ndims ();
1435 
1436  xok = false;
1437 
1438  // check dimensional size constraints until a match is found
1439  for (auto it = size_constraints.cbegin ();
1440  ! xok && it != size_constraints.cend ();
1441  ++it)
1442  {
1443  dim_vector itdims = (*it);
1444 
1445  if (itdims.ndims () == vlen)
1446  {
1447  xok = true;
1448 
1449  for (int i = 0; xok && i < vlen; i++)
1450  {
1451  if (itdims(i) > 0)
1452  {
1453  if (itdims(i) != vdims(i))
1454  xok = false;
1455  }
1456  else if (v.is_empty ())
1457  break;
1458  }
1459  }
1460  }
1461  }
1462 
1463  return xok;
1464 }
1465 
1466 bool
1468 {
1469  if (data.type_name () == v.type_name ())
1470  {
1471  if (data.dims () == v.dims ())
1472  {
1473 
1474 #define CHECK_ARRAY_EQUAL(T, F, A) \
1475  { \
1476  if (data.numel () == 1) \
1477  return data.F ## scalar_value () == \
1478  v.F ## scalar_value (); \
1479  else \
1480  { \
1481  /* Keep copy of array_value to allow */ \
1482  /* sparse/bool arrays that are converted, to */ \
1483  /* not be deallocated early */ \
1484  const A m1 = data.F ## array_value (); \
1485  const T* d1 = m1.data (); \
1486  const A m2 = v.F ## array_value (); \
1487  const T* d2 = m2.data (); \
1488  \
1489  bool flag = true; \
1490  \
1491  for (int i = 0; flag && i < data.numel (); i++) \
1492  if (d1[i] != d2[i]) \
1493  flag = false; \
1494  \
1495  return flag; \
1496  } \
1497  }
1498 
1499  if (data.is_double_type () || data.is_bool_type ())
1500  CHECK_ARRAY_EQUAL (double, , NDArray)
1501  else if (data.is_single_type ())
1502  CHECK_ARRAY_EQUAL (float, float_, FloatNDArray)
1503  else if (data.is_int8_type ())
1505  else if (data.is_int16_type ())
1507  else if (data.is_int32_type ())
1509  else if (data.is_int64_type ())
1511  else if (data.is_uint8_type ())
1513  else if (data.is_uint16_type ())
1515  else if (data.is_uint32_type ())
1517  else if (data.is_uint64_type ())
1519  }
1520  }
1521 
1522  return false;
1523 }
1524 
1525 void
1527 {
1530 
1531  if (! data.is_empty ())
1532  {
1533  if (data.is_integer_type ())
1534  {
1535  if (data.is_int8_type ())
1537  xmin, xmax, xminp, xmaxp);
1538  else if (data.is_uint8_type ())
1540  xmin, xmax, xminp, xmaxp);
1541  else if (data.is_int16_type ())
1543  xmin, xmax, xminp, xmaxp);
1544  else if (data.is_uint16_type ())
1546  xmin, xmax, xminp, xmaxp);
1547  else if (data.is_int32_type ())
1549  xmin, xmax, xminp, xmaxp);
1550  else if (data.is_uint32_type ())
1552  xmin, xmax, xminp, xmaxp);
1553  else if (data.is_int64_type ())
1555  xmin, xmax, xminp, xmaxp);
1556  else if (data.is_uint64_type ())
1558  xmin, xmax, xminp, xmaxp);
1559  }
1560  else
1562  }
1563 }
1564 
1565 bool
1567 {
1568  // Users may want to use empty matrix to reset a handle property
1569  if (v.is_empty ())
1570  {
1571  if (! get ().is_empty ())
1572  {
1574  return true;
1575  }
1576  else
1577  return false;
1578  }
1579 
1580  double dv = v.xdouble_value ("set: invalid graphics handle for property \"%s\"",
1581  get_name ().c_str ());
1582 
1584 
1585  if (! (octave::math::isnan (gh.value ()) || gh.ok ()))
1586  error ("set: invalid graphics handle (= %g) for property \"%s\"",
1587  dv, get_name ().c_str ());
1588 
1589  if (current_val != gh)
1590  {
1591  current_val = gh;
1592  return true;
1593  }
1594 
1595  return false;
1596 }
1597 
1598 Matrix
1599 children_property::do_get_children (bool return_hidden) const
1600 {
1601  Matrix retval (children_list.size (), 1);
1602  octave_idx_type k = 0;
1603 
1605 
1606  root_figure::properties& props =
1607  dynamic_cast<root_figure::properties&> (go.get_properties ());
1608 
1609  if (! props.is_showhiddenhandles ())
1610  {
1611  for (const auto& hchild : children_list)
1612  {
1613  graphics_handle kid = hchild;
1614 
1616  {
1617  if (! return_hidden)
1618  retval(k++) = hchild;
1619  }
1620  else if (return_hidden)
1621  retval(k++) = hchild;
1622  }
1623 
1624  retval.resize (k, 1);
1625  }
1626  else
1627  {
1628  for (const auto& hchild : children_list)
1629  retval(k++) = hchild;
1630  }
1631 
1632  return retval;
1633 }
1634 
1635 void
1637 {
1638  for (auto& hchild : children_list)
1639  {
1641 
1642  if (go.valid_object ())
1643  gh_manager::free (hchild);
1644  }
1645 
1646  if (clear)
1647  children_list.clear ();
1648 }
1649 
1650 bool
1652 {
1653  // case 1: empty matrix
1654  // case 2: function handle
1655  // case 3: string corresponding to known function name
1656  // case 4: string that can be eval()'ed
1657  // case 5: cell array with first element being a function handle
1658 
1659  if (v.is_empty ())
1660  return true;
1661  else if (v.is_function_handle ())
1662  return true;
1663  else if (v.is_string ())
1664  // complete validation will be done at execution-time
1665  return true;
1666  else if (v.is_cell () && (v.rows () == 1 || v.columns () == 1)
1667  && v.cell_value ()(0).is_function_handle ())
1668  return true;
1669 
1670  return false;
1671 }
1672 
1673 // If TRUE, we are executing any callback function, or the functions it calls.
1674 // Used to determine handle visibility inside callback functions.
1675 static bool executing_callback = false;
1676 
1677 void
1679 {
1681 
1682  // We are executing the callback function associated with this
1683  // callback property. When set to true, we avoid recursive calls to
1684  // callback routines.
1685  frame.protect_var (executing);
1686 
1687  // We are executing a callback function, so allow handles that have
1688  // their handlevisibility property set to "callback" to be visible.
1689  frame.protect_var (executing_callback);
1690 
1691  if (! executing)
1692  {
1693  executing = true;
1694  executing_callback = true;
1695 
1696  if (callback.is_defined () && ! callback.is_empty ())
1698  }
1699 }
1700 
1701 // Used to cache dummy graphics objects from which dynamic properties can be
1702 // cloned.
1703 static std::map<caseless_str, graphics_object> dprop_obj_map;
1704 
1705 property
1707  const caseless_str& type, const octave_value_list& args)
1708 {
1709  property retval;
1710 
1711  if (type.compare ("string"))
1712  {
1713  std::string sv = (args.length () > 0 ? args(0).string_value () : "");
1714 
1715  retval = property (new string_property (name, h, sv));
1716  }
1717  else if (type.compare ("any"))
1718  {
1719  octave_value ov = (args.length () > 0 ? args(0)
1720  : octave_value (Matrix ()));
1721 
1722  retval = property (new any_property (name, h, ov));
1723  }
1724  else if (type.compare ("radio"))
1725  {
1726  if (args.length () < 1)
1727  error ("addproperty: missing possible values for radio property");
1728 
1729  std::string sv = args(0).xstring_value ("addproperty: argument for radio property must be a string");
1730 
1731  retval = property (new radio_property (name, h, sv));
1732 
1733  if (args.length () > 1)
1734  retval.set (args(1));
1735  }
1736  else if (type.compare ("double"))
1737  {
1738  double dv = (args.length () > 0 ? args(0).double_value () : 0.0);
1739 
1740  retval = property (new double_property (name, h, dv));
1741  }
1742  else if (type.compare ("handle"))
1743  {
1744  double hv = args.length () > 0 ? args(0).double_value ()
1746 
1747  graphics_handle gh (hv);
1748 
1749  retval = property (new handle_property (name, h, gh));
1750  }
1751  else if (type.compare ("boolean"))
1752  {
1753  retval = property (new bool_property (name, h, false));
1754 
1755  if (args.length () > 0)
1756  retval.set (args(0));
1757  }
1758  else if (type.compare ("data"))
1759  {
1760  retval = property (new array_property (name, h, Matrix ()));
1761 
1762  if (args.length () > 0)
1763  {
1764  retval.set (args(0));
1765  // FIXME: additional argument could define constraints,
1766  // but is this really useful?
1767  }
1768  }
1769  else if (type.compare ("color"))
1770  {
1771  color_values cv (0, 0, 0);
1772  radio_values rv;
1773 
1774  if (args.length () > 1)
1775  rv = radio_values (args(1).string_value ());
1776 
1777  retval = property (new color_property (name, h, cv, rv));
1778 
1779  if (args.length () > 0 && ! args(0).is_empty ())
1780  retval.set (args(0));
1781  else
1782  retval.set (rv.default_value ());
1783  }
1784  else
1785  {
1786  caseless_str go_name, go_rest;
1787 
1788  if (! lookup_object_name (type, go_name, go_rest))
1789  error ("addproperty: unsupported type for dynamic property (= %s)",
1790  type.c_str ());
1791 
1792  graphics_object go;
1793 
1794  std::map<caseless_str, graphics_object>::const_iterator it =
1795  dprop_obj_map.find (go_name);
1796 
1797  if (it == dprop_obj_map.end ())
1798  {
1799  base_graphics_object *bgo =
1801 
1802  if (bgo)
1803  {
1804  go = graphics_object (bgo);
1805 
1806  dprop_obj_map[go_name] = go;
1807  }
1808  }
1809  else
1810  go = it->second;
1811 
1812  if (! go.valid_object ())
1813  error ("addproperty: invalid object type (= %s)",
1814  go_name.c_str ());
1815 
1816  property prop = go.get_properties ().get_property (go_rest);
1817 
1818  retval = prop.clone ();
1819 
1820  retval.set_parent (h);
1821  retval.set_name (name);
1822 
1823  if (args.length () > 0)
1824  retval.set (args(0));
1825  }
1826 
1827  return retval;
1828 }
1829 
1830 static void
1832 {
1834 
1835  if (go)
1836  {
1837  Matrix children = go.get_properties ().get_all_children ();
1838 
1839  for (int k = 0; k < children.numel (); k++)
1840  finalize_r (children(k));
1841 
1842  go.finalize ();
1843  }
1844 }
1845 
1846 static void
1848 {
1850 
1851  if (go)
1852  {
1853  Matrix children = go.get_properties ().get_all_children ();
1854 
1855  go.initialize ();
1856 
1857  for (int k = 0; k < children.numel (); k++)
1858  initialize_r (children(k));
1859  }
1860 }
1861 
1862 void
1864 {
1865  if (toolkit)
1867 
1868  toolkit = b;
1870  __plot_stream__ = Matrix ();
1871 
1872  if (toolkit)
1874 
1875  mark_modified ();
1876 }
1877 
1878 void
1880 {
1881  std::string direction = "in";
1882 
1883  octave_value val = val_arg;
1884 
1885  if (val.is_string ())
1886  {
1887  std::string modestr = val.string_value ();
1888 
1889  if (modestr == "zoom in")
1890  {
1891  val = modestr = "zoom";
1892  direction = "in";
1893  }
1894  else if (modestr == "zoom out")
1895  {
1896  val = modestr = "zoom";
1897  direction = "out";
1898  }
1899 
1900  if (__mouse_mode__.set (val, true))
1901  {
1902  std::string mode = __mouse_mode__.current_value ();
1903 
1904  octave_scalar_map pm = get___pan_mode__ ().scalar_map_value ();
1905  pm.setfield ("Enable", mode == "pan" ? "on" : "off");
1906  set___pan_mode__ (pm);
1907 
1908  octave_scalar_map rm = get___rotate_mode__ ().scalar_map_value ();
1909  rm.setfield ("Enable", mode == "rotate" ? "on" : "off");
1910  set___rotate_mode__ (rm);
1911 
1912  octave_scalar_map zm = get___zoom_mode__ ().scalar_map_value ();
1913  zm.setfield ("Enable", mode == "zoom" ? "on" : "off");
1914  zm.setfield ("Direction", direction);
1915  set___zoom_mode__ (zm);
1916 
1917  mark_modified ();
1918  }
1919  else if (modestr == "zoom")
1920  {
1921  octave_scalar_map zm = get___zoom_mode__ ().scalar_map_value ();
1922  std::string curr_direction
1923  = zm.getfield ("Direction").string_value ();
1924 
1925  if (direction != curr_direction)
1926  {
1927  zm.setfield ("Direction", direction);
1928  set___zoom_mode__ (zm);
1929 
1930  mark_modified ();
1931  }
1932  }
1933  }
1934 }
1935 
1936 // ---------------------------------------------------------------------
1937 
1938 void
1940 {
1941  size_t offset = 0;
1942 
1943  size_t len = name.length ();
1944 
1945  if (len > 4)
1946  {
1947  caseless_str pfx = name.substr (0, 4);
1948 
1949  if (pfx.compare ("axes") || pfx.compare ("line")
1950  || pfx.compare ("text"))
1951  offset = 4;
1952  else if (len > 5)
1953  {
1954  pfx = name.substr (0, 5);
1955 
1956  if (pfx.compare ("image") || pfx.compare ("patch"))
1957  offset = 5;
1958  else if (len > 6)
1959  {
1960  pfx = name.substr (0, 6);
1961 
1962  if (pfx.compare ("figure") || pfx.compare ("uimenu"))
1963  offset = 6;
1964  else if (len > 7)
1965  {
1966  pfx = name.substr (0, 7);
1967 
1968  if (pfx.compare ("surface") || pfx.compare ("hggroup")
1969  || pfx.compare ("uipanel"))
1970  offset = 7;
1971  else if (len > 9)
1972  {
1973  pfx = name.substr (0, 9);
1974 
1975  if (pfx.compare ("uicontrol")
1976  || pfx.compare ("uitoolbar"))
1977  offset = 9;
1978  else if (len > 10)
1979  {
1980  pfx = name.substr (0, 10);
1981 
1982  if (pfx.compare ("uipushtool"))
1983  offset = 10;
1984  else if (len > 12)
1985  {
1986  pfx = name.substr (0, 12);
1987 
1988  if (pfx.compare ("uitoogletool"))
1989  offset = 12;
1990  else if (len > 13)
1991  {
1992  pfx = name.substr (0, 13);
1993 
1994  if (pfx.compare ("uicontextmenu")
1995  || pfx.compare ("uibuttongroup"))
1996  offset = 13;
1997  }
1998  }
1999  }
2000  }
2001  }
2002  }
2003  }
2004 
2005  if (offset > 0)
2006  {
2007  // FIXME: should we validate property names and values here?
2008 
2009  std::string pname = name.substr (offset);
2010 
2011  std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
2012  std::transform (pname.begin (), pname.end (), pname.begin (),
2013  tolower);
2014 
2015  bool has_property = false;
2016  if (pfx == "axes")
2017  has_property = axes::properties::has_core_property (pname);
2018  else if (pfx == "figure")
2019  has_property = figure::properties::has_core_property (pname);
2020  else if (pfx == "line")
2021  has_property = line::properties::has_core_property (pname);
2022  else if (pfx == "text")
2023  has_property = text::properties::has_core_property (pname);
2024  else if (pfx == "image")
2025  has_property = image::properties::has_core_property (pname);
2026  else if (pfx == "patch")
2027  has_property = patch::properties::has_core_property (pname);
2028  else if (pfx == "surface")
2029  has_property = surface::properties::has_core_property (pname);
2030  else if (pfx == "hggroup")
2031  has_property = hggroup::properties::has_core_property (pname);
2032  else if (pfx == "uimenu")
2033  has_property = uimenu::properties::has_core_property (pname);
2034  else if (pfx == "uicontrol")
2035  has_property = uicontrol::properties::has_core_property (pname);
2036  else if (pfx == "uibuttongroup")
2037  has_property = uibuttongroup::properties::has_core_property (pname);
2038  else if (pfx == "uipanel")
2039  has_property = uipanel::properties::has_core_property (pname);
2040  else if (pfx == "uicontextmenu")
2041  has_property = uicontextmenu::properties::has_core_property (pname);
2042  else if (pfx == "uitoolbar")
2043  has_property = uitoolbar::properties::has_core_property (pname);
2044  else if (pfx == "uipushtool")
2045  has_property = uipushtool::properties::has_core_property (pname);
2046 
2047  if (! has_property)
2048  error ("invalid %s property '%s'", pfx.c_str (), pname.c_str ());
2049 
2050  bool remove = false;
2051  if (val.is_string ())
2052  {
2053  std::string sval = val.string_value ();
2054 
2055  remove = (sval == "remove");
2056  }
2057 
2058  pval_map_type& pval_map = plist_map[pfx];
2059 
2060  if (remove)
2061  {
2062  pval_map_iterator p = pval_map.find (pname);
2063 
2064  if (p != pval_map.end ())
2065  pval_map.erase (p);
2066  }
2067  else
2068  pval_map[pname] = val;
2069  }
2070  }
2071 
2072  if (offset == 0)
2073  error ("invalid default property specification");
2074 }
2075 
2078 {
2080 
2081  size_t offset = 0;
2082 
2083  size_t len = name.length ();
2084 
2085  if (len > 4)
2086  {
2087  caseless_str pfx = name.substr (0, 4);
2088 
2089  if (pfx.compare ("axes") || pfx.compare ("line")
2090  || pfx.compare ("text"))
2091  offset = 4;
2092  else if (len > 5)
2093  {
2094  pfx = name.substr (0, 5);
2095 
2096  if (pfx.compare ("image") || pfx.compare ("patch"))
2097  offset = 5;
2098  else if (len > 6)
2099  {
2100  pfx = name.substr (0, 6);
2101 
2102  if (pfx.compare ("figure") || pfx.compare ("uimenu"))
2103  offset = 6;
2104  else if (len > 7)
2105  {
2106  pfx = name.substr (0, 7);
2107 
2108  if (pfx.compare ("surface") || pfx.compare ("hggroup")
2109  || pfx.compare ("uipanel"))
2110  offset = 7;
2111  else if (len > 9)
2112  {
2113  pfx = name.substr (0, 9);
2114 
2115  if (pfx.compare ("uicontrol")
2116  || pfx.compare ("uitoolbar"))
2117  offset = 9;
2118  else if (len > 10)
2119  {
2120  pfx = name.substr (0, 10);
2121 
2122  if (pfx.compare ("uipushtool"))
2123  offset = 10;
2124  else if (len > 12)
2125  {
2126  pfx = name.substr (0, 12);
2127 
2128  if (pfx.compare ("uitoggletool"))
2129  offset = 12;
2130  else if (len > 13)
2131  {
2132  pfx = name.substr (0, 13);
2133 
2134  if (pfx.compare ("uicontextmenu")
2135  || pfx.compare ("uibuttongroup"))
2136  offset = 13;
2137  }
2138  }
2139  }
2140  }
2141  }
2142  }
2143  }
2144 
2145  if (offset > 0)
2146  {
2147  std::string pname = name.substr (offset);
2148 
2149  std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
2150  std::transform (pname.begin (), pname.end (), pname.begin (),
2151  tolower);
2152 
2154 
2155  if (p != end ())
2156  {
2157  const pval_map_type& pval_map = p->second;
2158 
2159  pval_map_const_iterator q = pval_map.find (pname);
2160 
2161  if (q != pval_map.end ())
2162  retval = q->second;
2163  }
2164  }
2165  }
2166 
2167  return retval;
2168 }
2169 
2171 property_list::as_struct (const std::string& prefix_arg) const
2172 {
2174 
2175  for (plist_map_const_iterator p = begin (); p != end (); p++)
2176  {
2177  std::string prefix = prefix_arg + p->first;
2178 
2179  const pval_map_type pval_map = p->second;
2180 
2181  for (const auto& prop_val_p : pval_map)
2182  m.assign (prefix + prop_val_p.first, prop_val_p.second);
2183  }
2184 
2185  return m;
2186 }
2187 
2188 // Set properties given as a cs-list of name, value pairs.
2189 
2190 void
2192 {
2193  int nargin = args.length ();
2194 
2195  if (nargin == 0)
2196  error ("graphics_object::set: Nothing to set");
2197 
2198  for (int i = 0; i < nargin; )
2199  {
2200  if (args(i).is_map () )
2201  {
2202  set (args(i).map_value ());
2203  i++;
2204  }
2205  else if (i < nargin - 1)
2206  {
2207  caseless_str pname = args(i).xstring_value ("set: argument %d must be a property name", i);
2208  octave_value val = args(i+1);
2209  set_value_or_default (pname, val);
2210  i += 2;
2211  }
2212  else
2213  error ("set: invalid number of arguments");
2214  }
2215 }
2216 
2217 /*
2218 ## test set with name, value pairs
2219 %!test
2220 %! hf = figure ("visible", "off");
2221 %! h = plot (1:10, 10:-1:1);
2222 %! set (h, "linewidth", 10, "marker", "x");
2223 %! lw = get (h, "linewidth");
2224 %! mk = get (h, "marker");
2225 %! close (hf);
2226 %! assert (lw, 10);
2227 %! assert (mk, "x");
2228 */
2229 
2230 // Set properties given in two cell arrays containing names and values.
2231 void
2233  const Cell& values, octave_idx_type row)
2234 {
2235  if (pnames.numel () != values.columns ())
2236  error ("set: number of names must match number of value columns (%d != %d)",
2237  pnames.numel (), values.columns ());
2238 
2239  octave_idx_type k = pnames.columns ();
2240 
2241  for (octave_idx_type column = 0; column < k; column++)
2242  {
2243  caseless_str pname = pnames(column);
2244  octave_value val = values(row, column);
2245 
2246  set_value_or_default (pname, val);
2247  }
2248 }
2249 
2250 /*
2251 ## test set with cell array arguments
2252 %!test
2253 %! hf = figure ("visible", "off");
2254 %! h = plot (1:10, 10:-1:1);
2255 %! set (h, {"linewidth", "marker"}, {10, "x"});
2256 %! lw = get (h, "linewidth");
2257 %! mk = get (h, "marker");
2258 %! close (hf);
2259 %! assert (lw, 10);
2260 %! assert (mk, "x");
2261 
2262 ## test set with multiple handles and cell array arguments
2263 %!test
2264 %! hf = figure ("visible", "off");
2265 %! unwind_protect
2266 %! h = plot (1:10, 10:-1:1, 1:10, 1:10);
2267 %! set (h, {"linewidth", "marker"}, {10, "x"; 5, "o"});
2268 %! assert (get (h, "linewidth"), {10; 5});
2269 %! assert (get (h, "marker"), {"x"; "o"});
2270 %! set (h, {"linewidth", "marker"}, {10, "x"});
2271 %! assert (get (h, "linewidth"), {10; 10});
2272 %! assert (get (h, "marker"), {"x"; "x"});
2273 %! unwind_protect_cleanup
2274 %! close (hf);
2275 %! end_unwind_protect;
2276 
2277 %!error <set: number of graphics handles must match number of value rows>
2278 %! hf = figure ("visible", "off");
2279 %! unwind_protect
2280 %! h = plot (1:10, 10:-1:1, 1:10, 1:10);
2281 %! set (h, {"linewidth", "marker"}, {10, "x"; 5, "o"; 7, "."});
2282 %! unwind_protect_cleanup
2283 %! close (hf);
2284 %! end_unwind_protect
2285 
2286 %!error <set: number of names must match number of value columns>
2287 %! hf = figure ("visible", "off");
2288 %! unwind_protect
2289 %! h = plot (1:10, 10:-1:1, 1:10, 1:10);
2290 %! set (h, {"linewidth"}, {10, "x"; 5, "o"});
2291 %! unwind_protect_cleanup
2292 %! close (hf);
2293 %! end_unwind_protect
2294 */
2295 
2296 // Set properties given in a struct array
2297 void
2299 {
2300  for (octave_idx_type p = 0; p < m.nfields (); p++)
2301  {
2302  // FIXME: Would it be better to extract all the keys at once rather than
2303  // repeatedly call keys() inside a for loop?
2304  caseless_str pname = m.keys ()[p];
2305 
2306  octave_value val = octave_value (m.contents (pname).elem (m.numel () - 1));
2307 
2308  set_value_or_default (pname, val);
2309  }
2310 }
2311 
2312 /*
2313 ## test set ticklabels for compatibility
2314 %!test
2315 %! hf = figure ("visible", "off");
2316 %! set (gca (), "xticklabel", [0, 0.2, 0.4, 0.6, 0.8, 1]);
2317 %! xticklabel = get (gca (), "xticklabel");
2318 %! close (hf);
2319 %! assert (class (xticklabel), "char");
2320 %! assert (size (xticklabel), [6, 3]);
2321 
2322 %!test
2323 %! hf = figure ("visible", "off");
2324 %! set (gca (), "xticklabel", "0|0.2|0.4|0.6|0.8|1");
2325 %! xticklabel = get (gca (), "xticklabel");
2326 %! close (hf);
2327 %! assert (class (xticklabel), "char");
2328 %! assert (size (xticklabel), [6, 3]);
2329 
2330 %!test
2331 %! hf = figure ("visible", "off");
2332 %! set (gca (), "xticklabel", ["0 "; "0.2"; "0.4"; "0.6"; "0.8"; "1 "]);
2333 %! xticklabel = get (gca (), "xticklabel");
2334 %! close (hf);
2335 %! assert (class (xticklabel), "char");
2336 %! assert (size (xticklabel), [6, 3]);
2337 
2338 %!test
2339 %! hf = figure ("visible", "off");
2340 %! set (gca (), "xticklabel", {"0", "0.2", "0.4", "0.6", "0.8", "1"});
2341 %! xticklabel = get (gca (), "xticklabel");
2342 %! close (hf);
2343 %! assert (class (xticklabel), "cell");
2344 %! assert (size (xticklabel), [6, 1]);
2345 */
2346 
2347 /*
2348 ## test set with struct arguments
2349 %!test
2350 %! hf = figure ("visible", "off");
2351 %! unwind_protect
2352 %! h = plot (1:10, 10:-1:1);
2353 %! set (h, struct ("linewidth", 10, "marker", "x"));
2354 %! assert (get (h, "linewidth"), 10);
2355 %! assert (get (h, "marker"), "x");
2356 %! h = plot (1:10, 10:-1:1, 1:10, 1:10);
2357 %! set (h, struct ("linewidth", {5, 10}));
2358 %! assert (get (h, "linewidth"), {10; 10});
2359 %! unwind_protect_cleanup
2360 %! close (hf);
2361 %! end_unwind_protect
2362 
2363 ## test ordering
2364 %!test
2365 %! markchanged = @(h, foobar, name) set (h, "userdata", [get(h,"userdata"); {name}]);
2366 %! hf = figure ("visible", "off");
2367 %! unwind_protect
2368 %! h = line ();
2369 %! set (h, "userdata", {});
2370 %! addlistener (h, "color", {markchanged, "color"});
2371 %! addlistener (h, "linewidth", {markchanged, "linewidth"});
2372 %! ## "linewidth" first
2373 %! props.linewidth = 2;
2374 %! props.color = "r";
2375 %! set (h, props);
2376 %! assert (get (h, "userdata"), fieldnames (props));
2377 %! clear props;
2378 %! clf ();
2379 %! h = line ();
2380 %! set (h, "userdata", {});
2381 %! addlistener (h, "color", {markchanged, "color"});
2382 %! addlistener (h, "linewidth", {markchanged, "linewidth"});
2383 %! ## "color" first
2384 %! props.color = "r";
2385 %! props.linewidth = 2;
2386 %! set (h, props);
2387 %! assert (get (h, "userdata"), fieldnames (props));
2388 %! unwind_protect_cleanup
2389 %! close (hf);
2390 %! end_unwind_protect
2391 */
2392 
2393 // Set a property to a value or to its (factory) default value.
2394 
2395 void
2397  const octave_value& val)
2398 {
2399  if (val.is_string ())
2400  {
2401  std::string sval = val.string_value ();
2402 
2403  octave_value default_val;
2404 
2405  if (sval == "default")
2406  {
2407  default_val = get_default (pname);
2408 
2409  rep->set (pname, default_val);
2410  }
2411  else if (sval == "factory")
2412  {
2413  default_val = get_factory_default (pname);
2414 
2415  rep->set (pname, default_val);
2416  }
2417  else
2418  {
2419  // Matlab specifically uses "\default" to escape string setting
2420  if (sval == "\\default")
2421  rep->set (pname, "default");
2422  else if (sval == "\\factory")
2423  rep->set (pname, "factory");
2424  else
2425  rep->set (pname, val);
2426  }
2427  }
2428  else
2429  rep->set (pname, val);
2430 }
2431 
2432 /*
2433 ## test setting of default values
2434 %!test
2435 %! old_lw = get (0, "defaultlinelinewidth");
2436 %! unwind_protect
2437 %! hf = figure ("visible", "off");
2438 %! h = plot (1:10, 10:-1:1);
2439 %! set (0, "defaultlinelinewidth", 20);
2440 %! set (h, "linewidth", "default");
2441 %! assert (get (h, "linewidth"), 20);
2442 %! set (h, "linewidth", "factory");
2443 %! assert (get (h, "linewidth"), 0.5);
2444 %! unwind_protect_cleanup
2445 %! close (hf);
2446 %! set (0, "defaultlinelinewidth", old_lw);
2447 %! end_unwind_protect
2448 */
2449 
2450 static double
2452 {
2453  static double maxrand = RAND_MAX + 2.0;
2454 
2455  return (rand () + 1.0) / maxrand;
2456 }
2457 
2459 gh_manager::do_get_handle (bool integer_figure_handle)
2460 {
2462 
2463  if (integer_figure_handle)
2464  {
2465  // Figure handles are positive integers corresponding
2466  // to the figure number.
2467 
2468  // We always want the lowest unused figure number.
2469 
2470  retval = 1;
2471 
2472  while (handle_map.find (retval) != handle_map.end ())
2473  retval++;
2474  }
2475  else
2476  {
2477  // Other graphics handles are negative integers plus some random
2478  // fractional part. To avoid running out of integers, we recycle the
2479  // integer part but tack on a new random part each time.
2480 
2481  free_list_iterator p = handle_free_list.begin ();
2482 
2483  if (p != handle_free_list.end ())
2484  {
2485  retval = *p;
2486  handle_free_list.erase (p);
2487  }
2488  else
2489  {
2490  retval = graphics_handle (next_handle);
2491 
2492  next_handle = std::ceil (next_handle) - 1.0 - make_handle_fraction ();
2493  }
2494  }
2495 
2496  return retval;
2497 }
2498 
2499 void
2501 {
2502  if (h.ok ())
2503  {
2504  if (h.value () == 0)
2505  error ("graphics_handle::free: can't delete root figure");
2506 
2507  iterator p = handle_map.find (h);
2508 
2509  if (p == handle_map.end ())
2510  error ("graphics_handle::free: invalid object %g", h.value ());
2511 
2512  base_properties& bp = p->second.get_properties ();
2513 
2514  bp.set_beingdeleted (true);
2515 
2516  bp.delete_children ();
2517 
2518  octave_value val = bp.get_deletefcn ();
2519 
2520  bp.execute_deletefcn ();
2521 
2522  // Notify graphics toolkit.
2523  p->second.finalize ();
2524 
2525  // Note: this will be valid only for first explicitly deleted
2526  // object. All its children will then have an
2527  // unknown graphics toolkit.
2528 
2529  // Graphics handles for non-figure objects are negative
2530  // integers plus some random fractional part. To avoid
2531  // running out of integers, we recycle the integer part
2532  // but tack on a new random part each time.
2533 
2534  handle_map.erase (p);
2535 
2536  if (h.value () < 0)
2537  handle_free_list.insert
2538  (std::ceil (h.value ()) - make_handle_fraction ());
2539  }
2540 }
2541 
2542 void
2544  const graphics_handle& new_gh)
2545 {
2546  iterator p = handle_map.find (old_gh);
2547 
2548  if (p == handle_map.end ())
2549  error ("graphics_handle::free: invalid object %g", old_gh.value ());
2550 
2551  graphics_object go = p->second;
2552 
2553  handle_map.erase (p);
2554 
2555  handle_map[new_gh] = go;
2556 
2557  if (old_gh.value () < 0)
2558  handle_free_list.insert (std::ceil (old_gh.value ())
2559  - make_handle_fraction ());
2560 
2561  for (auto& hfig : figure_list)
2562  {
2563  if (hfig == old_gh)
2564  {
2565  hfig = new_gh;
2566  break;
2567  }
2568  }
2569 }
2570 
2572 
2573 static void
2575  const octave_value& val)
2576 {
2578  go.set (pname, val);
2579 }
2580 
2581 static void
2583 {
2584  if (args.length () > 0)
2585  {
2587  go.set (args);
2588  }
2589 }
2590 
2591 static octave_value
2593 {
2595  return go.get (pname);
2596 }
2597 
2598 static graphics_handle
2599 reparent (const octave_value& ov, const std::string& who,
2600  const std::string& pname, const graphics_handle& new_parent,
2601  bool adopt = true)
2602 {
2604 
2605  double hv = ov.xdouble_value ("%s: %s must be a graphics handle",
2606  who.c_str (), pname.c_str ());
2607 
2608  h = gh_manager::lookup (hv);
2609 
2610  if (! h.ok ())
2611  error ("%s: invalid graphics handle (= %g) for %s",
2612  who.c_str (), hv, pname.c_str ());
2613 
2615 
2616  graphics_handle parent_h = go.get_parent ();
2617 
2618  graphics_object parent_go = gh_manager::get_object (parent_h);
2619 
2620  parent_go.remove_child (h);
2621 
2622  if (adopt)
2623  go.set ("parent", new_parent.value ());
2624  else
2625  go.reparent (new_parent);
2626 
2627  return h;
2628 }
2629 
2630 // This function is NOT equivalent to the scripting language function gcf.
2632 gcf (void)
2633 {
2634  octave_value val = xget (0, "currentfigure");
2635 
2637  : val.double_value ();
2638 }
2639 
2640 // This function is NOT equivalent to the scripting language function gca.
2642 gca (void)
2643 {
2644  octave_value val = xget (gcf (), "currentaxes");
2645 
2647  : val.double_value ();
2648 }
2649 
2650 static void
2652 {
2653  if (h.ok ())
2654  {
2656 
2657  // Don't do recursive deleting, due to callbacks
2658  if (! go.get_properties ().is_beingdeleted ())
2659  {
2660  graphics_handle parent_h = go.get_parent ();
2661 
2662  graphics_object parent_go = gh_manager::get_object (parent_h);
2663 
2664  // NOTE: free the handle before removing it from its parent's
2665  // children, such that the object's state is correct when the
2666  // deletefcn callback is executed
2667 
2668  gh_manager::free (h);
2669 
2670  // A callback function might have already deleted the parent
2671  if (parent_go.valid_object ())
2672  parent_go.remove_child (h);
2673 
2674  Vdrawnow_requested = true;
2675  }
2676  }
2677 }
2678 
2679 static void
2681 {
2683 }
2684 
2685 // Flag to stop redraws due to callbacks while deletion is in progress.
2686 static bool delete_executing = false;
2687 
2688 static void
2690 {
2691  // Prevent redraw of partially deleted objects.
2693  frame.protect_var (delete_executing);
2694  delete_executing = true;
2695 
2696  for (octave_idx_type i = 0; i < vals.numel (); i++)
2697  delete_graphics_object (vals.elem (i));
2698 }
2699 
2700 static void
2702 {
2703  octave_value closerequestfcn = xget (h, "closerequestfcn");
2704 
2705  OCTAVE_SAFE_CALL (gh_manager::execute_callback, (h, closerequestfcn));
2706 }
2707 
2708 static void
2710 {
2711  // Remove the deletefcn and closerequestfcn callbacks
2712  // and delete the object directly.
2713 
2714  xset (h, "deletefcn", Matrix ());
2715  xset (h, "closerequestfcn", Matrix ());
2716 
2718 }
2719 
2720 void
2722 {
2723  // FIXME: should we process or discard pending events?
2724 
2725  event_queue.clear ();
2726 
2727  // Don't use figure_list_iterator because we'll be removing elements
2728  // from the list elsewhere.
2729 
2730  Matrix hlist = do_figure_handle_list (true);
2731 
2732  for (octave_idx_type i = 0; i < hlist.numel (); i++)
2733  {
2735 
2736  if (h.ok ())
2737  close_figure (h);
2738  }
2739 
2740  // They should all be closed now. If not, force them to close.
2741 
2742  hlist = do_figure_handle_list (true);
2743 
2744  for (octave_idx_type i = 0; i < hlist.numel (); i++)
2745  {
2747 
2748  if (h.ok ())
2749  force_close_figure (h);
2750  }
2751 
2752  // None left now, right?
2753 
2754  hlist = do_figure_handle_list (true);
2755 
2756  if (hlist.numel () != 0)
2757  warning ("gh_manager::do_close_all_figures: some graphics elements failed to close.");
2758 
2759  // Clear all callback objects from our list.
2760 
2761  callback_objects.clear ();
2762 }
2763 
2764 static void
2765 adopt (const graphics_handle& parent_h, const graphics_handle& h)
2766 {
2767  graphics_object parent_go = gh_manager::get_object (parent_h);
2768  parent_go.adopt (h);
2769 }
2770 
2771 static bool
2773 {
2774  return h.ok ();
2775 }
2776 
2777 static bool
2778 is_handle (double val)
2779 {
2781 
2782  return h.ok ();
2783 }
2784 
2785 static octave_value
2787 {
2788  octave_value retval = false;
2789 
2790  if (val.is_real_scalar () && is_handle (val.double_value ()))
2791  retval = true;
2792  else if (val.is_numeric_type () && val.is_real_type ())
2793  {
2794  const NDArray handles = val.array_value ();
2795 
2796  boolNDArray result (handles.dims ());
2797 
2798  for (octave_idx_type i = 0; i < handles.numel (); i++)
2799  result.xelem (i) = is_handle (handles(i));
2800 
2801  retval = result;
2802  }
2803 
2804  return retval;
2805 }
2806 
2807 static bool
2808 is_figure (double val)
2809 {
2811 
2812  return go && go.isa ("figure");
2813 }
2814 
2815 static void
2817 {
2820 }
2821 
2822 static void
2824 {
2826 
2827  if (go)
2828  go.initialize ();
2829 }
2830 
2831 // ---------------------------------------------------------------------
2832 
2833 void
2835 {
2837 
2838  update (go, id);
2839 }
2840 
2841 bool
2843 {
2845 
2846  return initialize (go);
2847 }
2848 
2849 void
2851 {
2853 
2854  finalize (go);
2855 }
2856 
2857 static void
2859  property_list::pval_map_type factory_pval)
2860 {
2862 
2863  // Replace factory defaults by user defined ones
2864  std::string go_name = go.get_properties ().graphics_object_name ();
2866  go.build_user_defaults_map (pval, go_name);
2867 
2868  for (property_list::pval_map_const_iterator p = pval.begin ();
2869  p != pval.end (); p++)
2870  {
2871  factory_pval[p->first] = p->second;
2872  }
2873 
2874  // Reset defaults
2875  for (property_list::pval_map_const_iterator it = factory_pval.begin ();
2876  it != factory_pval.end (); it++)
2877  {
2878  std::string pname = it->first;
2879 
2880  // Don't reset internal properties and handle_properties
2881  if (! go.has_readonly_property (pname)
2882  && pname.find ("__") != 0 && pname.find ("current") != 0
2883  && pname != "uicontextmenu" && pname != "parent")
2884  {
2885  // Store *mode prop/val in order to set them last
2886  if (pname.find ("mode") == (pname.length () - 4))
2887  pval[pname] = it->second;
2888  else
2889  go.set (pname, it->second);
2890  }
2891  }
2892 
2893  // set *mode properties
2894  for (property_list::pval_map_const_iterator it = pval.begin ();
2895  it != pval.end (); it++)
2896  go.set (it->first, it->second);
2897 }
2898 
2899 // ---------------------------------------------------------------------
2900 
2901 void
2904 {
2905  std::string go_name = graphics_object_name ();
2906 
2907  property_list::plist_map_const_iterator plist = defaults.find (go_name);
2908 
2909  if (plist != defaults.end ())
2910  {
2911  const property_list::pval_map_type pval_map = plist->second;
2912 
2913  for (const auto& prop_val_p : pval_map)
2914  {
2915  std::string pname = prop_val_p.first;
2916 
2917  try
2918  {
2919  bgo.set (pname, prop_val_p.second);
2920  }
2921  catch (octave::execution_exception& e)
2922  {
2923  error (e, "error setting default property %s", pname.c_str ());
2924  }
2925  }
2926  }
2927 }
2928 
2929 /*
2930 ## test defaults are set in the order they were stored
2931 %!test
2932 %! set(0, "defaultfigureunits", "normalized");
2933 %! set(0, "defaultfigureposition", [0.7 0 0.3 0.3]);
2934 %! hf = figure ("visible", "off");
2935 %! tol = 20 * eps;
2936 %! unwind_protect
2937 %! assert (get (hf, "position"), [0.7 0 0.3 0.3], tol);
2938 %! unwind_protect_cleanup
2939 %! close (hf);
2940 %! set(0, "defaultfigureunits", "remove");
2941 %! set(0, "defaultfigureposition", "remove");
2942 %! end_unwind_protect
2943 */
2944 
2947 {
2948  std::map<caseless_str, property, cmp_caseless_str>::const_iterator it =
2949  all_props.find (pname);
2950 
2951  if (it == all_props.end ())
2952  error ("get: unknown property \"%s\"", pname.c_str ());
2953 
2954  return it->second.get ();
2955 }
2956 
2959 {
2961 
2962  for (std::map<caseless_str, property, cmp_caseless_str>::const_iterator
2963  it = all_props.begin (); it != all_props.end (); ++it)
2964  if (all || ! it->second.is_hidden ())
2965  m.assign (it->second.get_name (), it->second.get ());
2966 
2967  return m;
2968 }
2969 
2970 std::set<std::string>
2972 {
2973  return dynamic_properties;
2974 }
2975 
2976 bool
2978 {
2979  const std::set<std::string>& dynprops = dynamic_property_names ();
2980 
2981  if (dynprops.find (pname) != dynprops.end ())
2982  return true;
2983  else
2984  return all_props.find (pname) != all_props.end ();
2985 }
2986 
2987 void
2989  const octave_value& val)
2990 {
2991  std::map<caseless_str, property, cmp_caseless_str>::iterator it =
2992  all_props.find (pname);
2993 
2994  if (it == all_props.end ())
2995  error ("set: unknown property \"%s\"", pname.c_str ());
2996 
2997  it->second.set (val);
2998 
2999  dynamic_properties.insert (pname);
3000 
3001  mark_modified ();
3002 }
3003 
3004 property
3006 {
3007  std::map<caseless_str, property, cmp_caseless_str>::const_iterator it =
3008  all_props.find (pname);
3009 
3010  if (it == all_props.end ())
3011  error ("get_property: unknown property \"%s\"", pname.c_str ());
3012 
3013  return it->second;
3014 }
3015 
3016 void
3018 {
3019  double hp = val.xdouble_value ("set: parent must be a graphics handle");
3020 
3022 
3023  if (hp == __myhandle__)
3024  error ("set: can not set object parent to be object itself");
3025 
3026  new_parent = gh_manager::lookup (hp);
3027 
3028  if (! new_parent.ok ())
3029  error ("set: invalid graphics handle (= %g) for parent", hp);
3030 
3031  // Remove child from current parent
3032  graphics_object old_parent_go;
3033  old_parent_go = gh_manager::get_object (get_parent ());
3034 
3035  if (old_parent_go.get_handle () != hp)
3036  old_parent_go.remove_child (__myhandle__);
3037  else
3038  return; // Do nothing more
3039 
3040  // Check new parent's parent is not this child to avoid recursion
3041  graphics_object new_parent_go;
3042  new_parent_go = gh_manager::get_object (new_parent);
3043  if (new_parent_go.get_parent () == __myhandle__)
3044  {
3045  // new parent's parent gets child's original parent
3046  new_parent_go.get_properties ().set_parent (get_parent ().as_octave_value ());
3047  }
3048 
3049  // Set parent property to new_parent and do adoption
3050  parent = new_parent.as_octave_value ();
3051  ::adopt (parent.handle_value (), __myhandle__);
3052 }
3053 
3054 /*
3055 %!test
3056 %! hf = figure ("visible", "off");
3057 %! unwind_protect
3058 %! hax = gca ();
3059 %! set (hax, "parent", gcf ());
3060 %! assert (gca (), hax);
3061 %! unwind_protect_cleanup
3062 %! close (hf);
3063 %! end_unwind_protect
3064 */
3065 
3066 void
3068 {
3069  // Mark existing object as modified
3070  __modified__ = "on";
3071  // Attempt to mark parent object as modified if it exists
3073  if (parent_go)
3074  parent_go.mark_modified ();
3075 }
3076 
3077 void
3079 {
3081 
3082  if (parent_go)
3083  parent_go.override_defaults (obj);
3084 }
3085 
3086 void
3088 {
3089  graphics_object go = gh_manager::get_object (__myhandle__);
3090 
3091  if (go)
3092  go.update_axis_limits (axis_type);
3093 }
3094 
3095 void
3097  const graphics_handle& h) const
3098 {
3099  graphics_object go = gh_manager::get_object (__myhandle__);
3100 
3101  if (go)
3102  go.update_axis_limits (axis_type, h);
3103 }
3104 
3105 void
3107 {
3108  if (uicontextmenu.get ().is_empty ())
3109  return;
3110 
3112  if (go && go.isa ("uicontextmenu"))
3113  {
3114  uicontextmenu::properties& props =
3115  reinterpret_cast<uicontextmenu::properties&> (go.get_properties ());
3116  props.add_dependent_obj (__myhandle__);
3117  }
3118 }
3119 
3120 bool
3122 {
3123  return (handlevisibility.is ("on")
3124  || (executing_callback && ! handlevisibility.is ("off")));
3125 }
3126 
3129 {
3131 
3132  if (go)
3133  return go.get_toolkit ();
3134  else
3135  return graphics_toolkit ();
3136 }
3137 
3138 void
3140 {
3141  Matrix kids = get_children ();
3142 
3143  for (int i = 0; i < kids.numel (); i++)
3144  {
3146 
3147  if (go.valid_object ())
3149  }
3150 }
3151 
3152 void
3154 {
3156 
3157  if (parent_go.valid_object ())
3158  parent_go.get_properties ().update_autopos (elem_type);
3159 }
3160 
3161 void
3163  const octave_value& val,
3165 {
3166  property p = get_property (pname);
3167 
3168  if (p.ok ())
3169  p.add_listener (val, mode);
3170 }
3171 
3172 void
3174  const octave_value& val,
3176 {
3177  property p = get_property (pname);
3178 
3179  if (p.ok ())
3180  p.delete_listener (val, mode);
3181 }
3182 
3183 // ---------------------------------------------------------------------
3184 
3185 void
3187 {
3188  if (! valid_object ())
3189  error ("base_graphics_object::update_axis_limits: invalid graphics object");
3190 
3192 
3193  if (parent_go)
3194  parent_go.update_axis_limits (axis_type);
3195 }
3196 
3197 void
3199  const graphics_handle& h)
3200 {
3201  if (! valid_object ())
3202  error ("base_graphics_object::update_axis_limits: invalid graphics object");
3203 
3205 
3206  if (parent_go)
3207  parent_go.update_axis_limits (axis_type, h);
3208 }
3209 
3210 void
3212 {
3213  octave_map m = get (true).map_value ();
3214 
3215  for (octave_map::const_iterator pa = m.begin (); pa != m.end (); pa++)
3216  {
3217  // FIXME: there has to be a better way. I think we want to
3218  // ask whether it is OK to delete the listener for the given
3219  // property. How can we know in advance that it will be OK?
3220 
3222 
3224  frame.protect_var (Vdebug_on_error);
3226 
3227  discard_error_messages = true;
3228  Vdebug_on_error = false;
3229  Vdebug_on_warning = false;
3230 
3231  try
3232  {
3233  property p = get_properties ().get_property (pa->first);
3234 
3235  if (p.ok ())
3236  p.delete_listener ();
3237  }
3238  catch (const octave::execution_exception&)
3239  {
3241  }
3242  }
3243 }
3244 
3245 void
3247 {
3248  property_list local_defaults = get_defaults_list ();
3249  const auto it = local_defaults.find (go_name);
3250 
3251  if (it != local_defaults.end ())
3252  {
3253  property_list::pval_map_type pval = it->second;
3254  for (const auto& prop_val_p : pval)
3255  {
3256  std::string pname = prop_val_p.first;
3257  if (def.find (pname) == def.end ())
3258  def[pname] = prop_val_p.second;
3259  }
3260  }
3261 
3263 
3264  if (parent_go)
3265  parent_go.build_user_defaults_map (def, go_name);
3266 }
3267 
3268 void
3270 {
3271  if (valid_object ())
3272  {
3273  property_list::pval_map_type factory_pval =
3275  .find (type ())->second;
3276 
3277  // save warning state of "Octave:deprecated-property"
3278  int old_dep_prop = warning_enabled ("Octave:deprecated-property");
3279  disable_warning ("Octave:deprecated-property");
3280 
3281  xreset_default_properties (get_handle (), factory_pval);
3282 
3283  // re-enable warning state of "Octave:deprecated-property"
3284  if (old_dep_prop == 1)
3285  set_warning_state ("Octave:deprecated-property", "on");
3286  else if (old_dep_prop == 2)
3287  set_warning_state ("Octave:deprecated-property", "error");
3288 
3289  }
3290 }
3291 
3294 {
3296 
3297  if (! valid_object ())
3298  error ("base_graphics_object::values_as_string: invalid graphics object");
3299 
3300  octave_map m = get ().map_value ();
3302 
3303  for (octave_map::const_iterator pa = m.begin (); pa != m.end (); pa++)
3304  {
3305  if (pa->first != "children" && ! go.has_readonly_property (pa->first))
3306  {
3307  property p = get_properties ().get_property (pa->first);
3308 
3309  if (p.ok () && ! p.is_hidden ())
3310  {
3311  retval += "\n\t" + std::string (pa->first) + ": ";
3312  if (p.is_radio ())
3313  retval += p.values_as_string ();
3314  }
3315  }
3316  }
3317 
3318  if (! retval.empty ())
3319  retval += "\n";
3320 
3321  return retval;
3322 }
3323 
3326 {
3328 
3329  if (! valid_object ())
3330  error ("base_graphics_object::value_as_string: invalid graphics object");
3331 
3333 
3334  if (prop != "children" && ! go.has_readonly_property (prop))
3335  {
3336  property p = get_properties ().get_property (prop);
3337 
3338  if (p.ok () && ! p.is_hidden ())
3339  {
3340  if (p.is_radio ())
3341  retval += p.values_as_string ();
3342  }
3343  }
3344 
3345  if (! retval.empty ())
3346  retval += "\n";
3347 
3348  return retval;
3349 }
3350 
3353 {
3355 
3356  if (! valid_object ())
3357  error ("base_graphics_object::values_as_struct: invalid graphics object");
3358 
3359  octave_scalar_map m = get ().scalar_map_value ();
3361 
3363  pa != m.end (); pa++)
3364  {
3365  if (pa->first != "children"
3366  && ! go.has_readonly_property (pa->first))
3367  {
3368  property p = get_properties ().get_property (pa->first);
3369 
3370  if (p.ok () && ! p.is_hidden ())
3371  {
3372  if (p.is_radio ())
3373  retval.assign (p.get_name (), p.values_as_cell ());
3374  else
3375  retval.assign (p.get_name (), Cell ());
3376  }
3377  }
3378  }
3379 
3380  return retval;
3381 }
3382 
3383 /*
3384 %!test
3385 %! hfig = figure ("visible", "off");
3386 %! unwind_protect
3387 %! hax = axes ();
3388 %! ret = set (hax, "tightinset");
3389 %! assert (isempty (ret));
3390 %! ret = set (hax, "type");
3391 %! assert (isempty (ret));
3392 %! ret = set (hfig, "tag");
3393 %! assert (isempty (ret));
3394 %! ret = set (0, "commandwindowsize");
3395 %! assert (isempty (ret));
3396 %! ret = set (0);
3397 %! assert (! isfield (ret, "commandwindowsize"));
3398 %! unwind_protect_cleanup
3399 %! close (hfig);
3400 %! end_unwind_protect
3401 */
3402 
3405 {
3406  if (valid_object ())
3407  {
3408  if (isa (obj_type))
3409  return *this;
3410  else
3411  return gh_manager::get_object (get_parent ()).get_ancestor (obj_type);
3412  }
3413  else
3414  return graphics_object ();
3415 }
3416 
3417 // ---------------------------------------------------------------------
3418 
3419 #include "graphics-props.cc"
3420 
3421 // ---------------------------------------------------------------------
3422 
3423 void
3425 {
3426  graphics_handle val (v);
3427 
3428  if (octave::math::isnan (val.value ()))
3429  {
3430  if (! cbo_stack.empty ())
3431  {
3432  val = cbo_stack.front ();
3433 
3434  cbo_stack.pop_front ();
3435  }
3436 
3437  callbackobject = val;
3438  }
3439  else if (is_handle (val))
3440  {
3441  if (get_callbackobject ().ok ())
3442  cbo_stack.push_front (get_callbackobject ());
3443 
3444  callbackobject = val;
3445  }
3446  else
3447  err_set_invalid ("callbackobject");
3448 }
3449 
3450 void
3452 {
3453  graphics_handle val (v);
3454 
3455  if (octave::math::isnan (val.value ()) || is_handle (val))
3456  {
3457  currentfigure = val;
3458 
3459  if (val.ok ())
3461  }
3462  else
3463  err_set_invalid ("currentfigure");
3464 }
3465 
3466 void
3468 {
3469  if (integerhandle.set (val, true))
3470  {
3471  bool int_fig_handle = integerhandle.is_on ();
3472 
3473  graphics_object this_go = gh_manager::get_object (__myhandle__);
3474 
3475  graphics_handle old_myhandle = __myhandle__;
3476 
3477  __myhandle__ = gh_manager::get_handle (int_fig_handle);
3478 
3479  gh_manager::renumber_figure (old_myhandle, __myhandle__);
3480 
3482 
3483  base_properties& props = parent_go.get_properties ();
3484 
3485  props.renumber_child (old_myhandle, __myhandle__);
3486 
3487  Matrix kids = get_children ();
3488 
3489  for (octave_idx_type i = 0; i < kids.numel (); i++)
3490  {
3492 
3493  kid.get_properties ().renumber_parent (__myhandle__);
3494  }
3495 
3497 
3498  if (__myhandle__ == cf)
3499  xset (0, "currentfigure", __myhandle__.value ());
3500 
3501  this_go.update (integerhandle.get_id ());
3502 
3503  mark_modified ();
3504  }
3505 }
3506 
3507 // FIXME: This should update monitorpositions and pointerlocation, but as these
3508 // properties aren't yet used, it doesn't matter that they aren't set either.
3509 void
3511 {
3512  std::string xunits = get_units ();
3513 
3514  Matrix scrn_sz = default_screensize ();
3515 
3516  double dpi = get_screenpixelsperinch ();
3517 
3518  if (xunits == "inches")
3519  {
3520  scrn_sz(0) = 0;
3521  scrn_sz(1) = 0;
3522  scrn_sz(2) /= dpi;
3523  scrn_sz(3) /= dpi;
3524  }
3525  else if (xunits == "centimeters")
3526  {
3527  scrn_sz(0) = 0;
3528  scrn_sz(1) = 0;
3529  scrn_sz(2) *= 2.54 / dpi;
3530  scrn_sz(3) *= 2.54 / dpi;
3531  }
3532  else if (xunits == "normalized")
3533  {
3534  scrn_sz = Matrix (1, 4, 1.0);
3535  scrn_sz(0) = 0;
3536  scrn_sz(1) = 0;
3537  }
3538  else if (xunits == "points")
3539  {
3540  scrn_sz(0) = 0;
3541  scrn_sz(1) = 0;
3542  scrn_sz(2) *= 72 / dpi;
3543  scrn_sz(3) *= 72 / dpi;
3544  }
3545 
3546  set_screensize (scrn_sz);
3547 }
3548 
3549 Matrix
3551 {
3552  Matrix screen_size = screen_size_pixels ();
3553  Matrix pos = Matrix (1, 4, 0.0);
3554 
3555  pos(2) = screen_size(0);
3556  pos(3) = screen_size(1);
3557 
3558  return pos;
3559 }
3560 
3561 /*
3562 %!test
3563 %! old_units = get (0, "units");
3564 %! unwind_protect
3565 %! set (0, "units", "pixels");
3566 %! sz = get (0, "screensize") - [1, 1, 0, 0];
3567 %! dpi = get (0, "screenpixelsperinch");
3568 %! set (0, "units", "inches");
3569 %! assert (get (0, "screensize"), sz / dpi, 0.5 / dpi);
3570 %! set (0, "units", "centimeters");
3571 %! assert (get (0, "screensize"), sz / dpi * 2.54, 0.5 / dpi * 2.54);
3572 %! set (0, "units", "points");
3573 %! assert (get (0, "screensize"), sz / dpi * 72, 0.5 / dpi * 72);
3574 %! set (0, "units", "normalized");
3575 %! assert (get (0, "screensize"), [0.0, 0.0, 1.0, 1.0]);
3576 %! set (0, "units", "pixels");
3577 %! assert (get (0, "screensize"), sz + [1, 1, 0, 0]);
3578 %! unwind_protect_cleanup
3579 %! set (0, "units", old_units);
3580 %! end_unwind_protect
3581 */
3582 
3583 void
3585 {
3587 
3589 
3590  xset (0, "currentfigure", cf.value ());
3591 
3593 }
3594 
3597 
3598 void
3600 {
3601  // empty list of local defaults
3603 
3606 }
3607 
3608 // ---------------------------------------------------------------------
3609 
3610 void
3612 {
3613  graphics_handle hax (val);
3614 
3615  if (octave::math::isnan (hax.value ()) || is_handle (hax))
3616  currentaxes = hax;
3617  else
3618  err_set_invalid ("currentaxes");
3619 }
3620 
3621 void
3623 {
3625 
3626  if (h == currentaxes.handle_value ())
3627  {
3628  graphics_handle new_currentaxes;
3629 
3630  Matrix kids = get_children ();
3631 
3632  for (octave_idx_type i = 0; i < kids.numel (); i++)
3633  {
3634  graphics_handle kid = kids(i);
3635 
3637 
3638  if (go.isa ("axes"))
3639  {
3640  new_currentaxes = kid;
3641  break;
3642  }
3643  }
3644 
3645  currentaxes = new_currentaxes;
3646  }
3647 }
3648 
3649 void
3651 {
3653 
3654  if (! get_currentaxes ().ok ())
3655  {
3657 
3658  if (go.type () == "axes")
3659  set_currentaxes (h.as_octave_value ());
3660  }
3661 }
3662 
3663 /*
3664 %!test
3665 %! hf1 = figure ("visible", "off");
3666 %! ax1 = subplot (1,2,1);
3667 %! ax2 = subplot (1,2,2);
3668 %! hf2 = figure ("visible", "off");
3669 %! unwind_protect
3670 %! set (ax2, "parent", hf2);
3671 %! assert (get (hf2, "currentaxes"), ax2);
3672 %! assert (get (hf1, "currentaxes"), ax1);
3673 %! set (ax1, "parent", hf2);
3674 %! assert (get (hf2, "currentaxes"), ax2);
3675 %! unwind_protect_cleanup
3676 %! close (hf1);
3677 %! close (hf2);
3678 %! end_unwind_protect
3679 */
3680 
3681 void
3683 {
3684  std::string sval = val.string_value ();
3685 
3686  if (sval == "on")
3687  xset (0, "currentfigure", __myhandle__.value ());
3688 
3689  visible = val;
3690 }
3691 
3692 Matrix
3693 figure::properties::get_boundingbox (bool internal, const Matrix&) const
3694 {
3695  Matrix screen_size = screen_size_pixels ();
3696  Matrix pos = (internal ?
3697  get_position ().matrix_value () :
3698  get_outerposition ().matrix_value ());
3699 
3700  pos = convert_position (pos, get_units (), "pixels", screen_size);
3701 
3702  pos(0)--;
3703  pos(1)--;
3704  pos(1) = screen_size(1) - pos(1) - pos(3);
3705 
3706  return pos;
3707 }
3708 
3709 void
3711  bool do_notify_toolkit)
3712 {
3713  Matrix screen_size = screen_size_pixels ();
3714  Matrix pos = bb;
3715 
3716  pos(1) = screen_size(1) - pos(1) - pos(3);
3717  pos(1)++;
3718  pos(0)++;
3719  pos = convert_position (pos, "pixels", get_units (), screen_size);
3720 
3721  if (internal)
3722  set_position (pos, do_notify_toolkit);
3723  else
3724  set_outerposition (pos, do_notify_toolkit);
3725 }
3726 
3727 Matrix
3729 {
3730  Matrix bb = get_boundingbox (true);
3731  Matrix pos (1, 2, 0.0);
3732 
3733  pos(0) = x;
3734  pos(1) = y;
3735 
3736  pos(1) = bb(3) - pos(1);
3737  pos(0)++;
3738  pos = convert_position (pos, "pixels", get_units (),
3739  bb.extract_n (0, 2, 1, 2));
3740 
3741  return pos;
3742 }
3743 
3744 Matrix
3746 {
3747  Matrix bb = get_boundingbox (true);
3748  Matrix pos (1, 2, 0.0);
3749 
3750  pos(0) = x;
3751  pos(1) = y;
3752 
3753  pos = convert_position (pos, get_units (), "pixels",
3754  bb.extract_n (0, 2, 1, 2));
3755  pos(0)--;
3756  pos(1) = bb(3) - pos(1);
3757 
3758  return pos;
3759 }
3760 
3761 void
3763  bool do_notify_toolkit)
3764 {
3765  Matrix old_bb, new_bb;
3766  bool modified = false;
3767 
3768  old_bb = get_boundingbox (true);
3769  modified = position.set (v, false, do_notify_toolkit);
3770  new_bb = get_boundingbox (true);
3771 
3772  if (old_bb != new_bb)
3773  {
3774  if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
3775  {
3776  execute_resizefcn ();
3777  update_boundingbox ();
3778  }
3779  }
3780 
3781  if (modified)
3782  {
3783  position.run_listeners (POSTSET);
3784  mark_modified ();
3785  }
3786 
3787  if (paperpositionmode.is ("auto"))
3788  paperposition.set (get_auto_paperposition ());
3789 }
3790 
3791 void
3793  bool do_notify_toolkit)
3794 {
3795  if (outerposition.set (v, true, do_notify_toolkit))
3796  mark_modified ();
3797 }
3798 
3799 void
3801 {
3802  caseless_str punits = val.string_value ();
3803  caseless_str ptype = get_papertype ();
3804 
3805  if (punits.compare ("normalized") && ptype.compare ("<custom>"))
3806  error ("set: can't set paperunits to normalized when papertype is custom");
3807 
3808  caseless_str old_paperunits = get_paperunits ();
3809  if (paperunits.set (val, true))
3810  {
3811  update_paperunits (old_paperunits);
3812  mark_modified ();
3813  }
3814 }
3815 
3816 void
3818 {
3819  caseless_str ptype = val.string_value ();
3820  caseless_str punits = get_paperunits ();
3821 
3822  if (punits.compare ("normalized") && ptype.compare ("<custom>"))
3823  error ("set: can't set paperunits to normalized when papertype is custom");
3824 
3825  if (papertype.set (val, true))
3826  {
3827  update_papertype ();
3828  mark_modified ();
3829  }
3830 }
3831 
3832 static Matrix
3833 papersize_from_type (const caseless_str punits, const caseless_str ptype)
3834 {
3835  Matrix retval (1, 2, 1.0);
3836 
3837  if (! punits.compare ("normalized"))
3838  {
3839  double in2units;
3840  double mm2units;
3841 
3842  if (punits.compare ("inches"))
3843  {
3844  in2units = 1.0;
3845  mm2units = 1 / 25.4;
3846  }
3847  else if (punits.compare ("centimeters"))
3848  {
3849  in2units = 2.54;
3850  mm2units = 1 / 10.0;
3851  }
3852  else // points
3853  {
3854  in2units = 72.0;
3855  mm2units = 72.0 / 25.4;
3856  }
3857 
3858  if (ptype.compare ("usletter"))
3859  {
3860  retval(0) = 8.5 * in2units;
3861  retval(1) = 11.0 * in2units;
3862  }
3863  else if (ptype.compare ("uslegal"))
3864  {
3865  retval(0) = 8.5 * in2units;
3866  retval(1) = 14.0 * in2units;
3867  }
3868  else if (ptype.compare ("tabloid"))
3869  {
3870  retval(0) = 11.0 * in2units;
3871  retval(1) = 17.0 * in2units;
3872  }
3873  else if (ptype.compare ("a0"))
3874  {
3875  retval(0) = 841.0 * mm2units;
3876  retval(1) = 1189.0 * mm2units;
3877  }
3878  else if (ptype.compare ("a1"))
3879  {
3880  retval(0) = 594.0 * mm2units;
3881  retval(1) = 841.0 * mm2units;
3882  }
3883  else if (ptype.compare ("a2"))
3884  {
3885  retval(0) = 420.0 * mm2units;
3886  retval(1) = 594.0 * mm2units;
3887  }
3888  else if (ptype.compare ("a3"))
3889  {
3890  retval(0) = 297.0 * mm2units;
3891  retval(1) = 420.0 * mm2units;
3892  }
3893  else if (ptype.compare ("a4"))
3894  {
3895  retval(0) = 210.0 * mm2units;
3896  retval(1) = 297.0 * mm2units;
3897  }
3898  else if (ptype.compare ("a5"))
3899  {
3900  retval(0) = 148.0 * mm2units;
3901  retval(1) = 210.0 * mm2units;
3902  }
3903  else if (ptype.compare ("b0"))
3904  {
3905  retval(0) = 1029.0 * mm2units;
3906  retval(1) = 1456.0 * mm2units;
3907  }
3908  else if (ptype.compare ("b1"))
3909  {
3910  retval(0) = 728.0 * mm2units;
3911  retval(1) = 1028.0 * mm2units;
3912  }
3913  else if (ptype.compare ("b2"))
3914  {
3915  retval(0) = 514.0 * mm2units;
3916  retval(1) = 728.0 * mm2units;
3917  }
3918  else if (ptype.compare ("b3"))
3919  {
3920  retval(0) = 364.0 * mm2units;
3921  retval(1) = 514.0 * mm2units;
3922  }
3923  else if (ptype.compare ("b4"))
3924  {
3925  retval(0) = 257.0 * mm2units;
3926  retval(1) = 364.0 * mm2units;
3927  }
3928  else if (ptype.compare ("b5"))
3929  {
3930  retval(0) = 182.0 * mm2units;
3931  retval(1) = 257.0 * mm2units;
3932  }
3933  else if (ptype.compare ("arch-a"))
3934  {
3935  retval(0) = 9.0 * in2units;
3936  retval(1) = 12.0 * in2units;
3937  }
3938  else if (ptype.compare ("arch-b"))
3939  {
3940  retval(0) = 12.0 * in2units;
3941  retval(1) = 18.0 * in2units;
3942  }
3943  else if (ptype.compare ("arch-c"))
3944  {
3945  retval(0) = 18.0 * in2units;
3946  retval(1) = 24.0 * in2units;
3947  }
3948  else if (ptype.compare ("arch-d"))
3949  {
3950  retval(0) = 24.0 * in2units;
3951  retval(1) = 36.0 * in2units;
3952  }
3953  else if (ptype.compare ("arch-e"))
3954  {
3955  retval(0) = 36.0 * in2units;
3956  retval(1) = 48.0 * in2units;
3957  }
3958  else if (ptype.compare ("a"))
3959  {
3960  retval(0) = 8.5 * in2units;
3961  retval(1) = 11.0 * in2units;
3962  }
3963  else if (ptype.compare ("b"))
3964  {
3965  retval(0) = 11.0 * in2units;
3966  retval(1) = 17.0 * in2units;
3967  }
3968  else if (ptype.compare ("c"))
3969  {
3970  retval(0) = 17.0 * in2units;
3971  retval(1) = 22.0 * in2units;
3972  }
3973  else if (ptype.compare ("d"))
3974  {
3975  retval(0) = 22.0 * in2units;
3976  retval(1) = 34.0 * in2units;
3977  }
3978  else if (ptype.compare ("e"))
3979  {
3980  retval(0) = 34.0 * in2units;
3981  retval(1) = 43.0 * in2units;
3982  }
3983  }
3984 
3985  return retval;
3986 }
3987 
3988 Matrix
3990 {
3991  Matrix pos = get_position ().matrix_value ();
3992  Matrix sz;
3993 
3994  caseless_str funits = get_units ();
3995  caseless_str punits = get_paperunits ();
3996 
3997  // Convert position from figure units to paperunits
3998  if (funits == "normalized" || punits == "normalized")
3999  {
4000  sz = screen_size_pixels ();
4001  pos = convert_position (pos, funits, "inches", sz);
4002 
4003  if (punits == "normalized")
4004  sz = papersize_from_type ("points", get_papertype ());
4005 
4006  pos = convert_position (pos, "inches", punits, sz);
4007  }
4008  else
4009  pos = convert_position (pos, funits, punits, sz);
4010 
4011  // Center the figure on the page
4012  sz = get_papersize ().matrix_value ();
4013 
4014  pos(0) = sz(0)/2 - pos(2)/2;
4015  pos(1) = sz(1)/2 - pos(3)/2;
4016 
4017  return pos;
4018 }
4019 
4020 /*
4021 %!test
4022 %! hf = figure ("visible", "off", "paperpositionmode", "auto");
4023 %! in_pos = [0 0 4 5];
4024 %! tol = 20 * eps ();
4025 %! unwind_protect
4026 %! ## paperpositionmode "auto" converts figure size to paper units
4027 %! set (hf, "units", "inches");
4028 %! set (hf, "position", in_pos);
4029 %! set (hf, "paperunits", "centimeters");
4030 %! psz = get (hf, "papersize");
4031 %! fsz = in_pos(3:4) * 2.54;
4032 %! pos = [(psz/2 .- fsz/2) fsz];
4033 %! set (hf, "paperpositionmode", "auto");
4034 %! assert (get (hf, "paperposition"), pos, tol);
4035 %! unwind_protect_cleanup
4036 %! close (hf);
4037 %! end_unwind_protect
4038 
4039 %!test
4040 %! hf = figure ("visible", "off", "paperpositionmode", "auto");
4041 %! in_pos = [0 0 4 5];
4042 %! tol = 20 * eps ();
4043 %! unwind_protect
4044 %! ## likewise with normalized units
4045 %! set (hf, "units", "inches");
4046 %! set (hf, "position", in_pos);
4047 %! psz = get (hf, "papersize");
4048 %! set (hf, "paperunits", "normalized");
4049 %! fsz = in_pos(3:4) ./ psz;
4050 %! pos = [([0.5 0.5] .- fsz/2) fsz];
4051 %! assert (get (hf, "paperposition"), pos, tol);
4052 %! unwind_protect_cleanup
4053 %! close (hf);
4054 %! end_unwind_protect
4055 
4056 %!test
4057 %! hf = figure ("visible", "off", "paperpositionmode", "auto");
4058 %! in_pos = [0 0 4 5];
4059 %! tol = 20 * eps ();
4060 %! unwind_protect
4061 %! ## changing papertype updates paperposition
4062 %! set (hf, "units", "inches");
4063 %! set (hf, "position", in_pos);
4064 %! set (hf, "papertype", "a4");
4065 %! psz = get (hf, "papersize");
4066 %! fsz = in_pos(3:4);
4067 %! pos = [(psz/2 .- fsz/2) fsz];
4068 %! assert (get (hf, "paperposition"), pos, tol);
4069 %! unwind_protect_cleanup
4070 %! close (hf);
4071 %! end_unwind_protect
4072 
4073 %!test
4074 %! hf = figure ("visible", "off", "paperpositionmode", "auto");
4075 %! in_pos = [0 0 4 5];
4076 %! tol = 20 * eps ();
4077 %! unwind_protect
4078 %! ## lanscape updates paperposition
4079 %! set (hf, "units", "inches");
4080 %! set (hf, "position", in_pos);
4081 %! set (hf, "paperorientation", "landscape");
4082 %! psz = get (hf, "papersize");
4083 %! fsz = in_pos(3:4);
4084 %! pos = [(psz/2 .- fsz/2) fsz];
4085 %! assert (get (hf, "paperposition"), pos, tol);
4086 %! unwind_protect_cleanup
4087 %! close (hf);
4088 %! end_unwind_protect
4089 
4090 %!test
4091 %! hf = figure ("visible", "off", "paperpositionmode", "auto");
4092 %! in_pos = [0 0 4 5];
4093 %! unwind_protect
4094 %! ## back to manual mode
4095 %! set (hf, "paperposition", in_pos * 1.1);
4096 %! assert (get (hf, "paperpositionmode"), "manual");
4097 %! assert (get (hf, "paperposition"), in_pos * 1.1);
4098 %! unwind_protect_cleanup
4099 %! close (hf);
4100 %! end_unwind_protect
4101 */
4102 
4103 void
4105 {
4106  Matrix pos = get_paperposition ().matrix_value ();
4107  Matrix sz = get_papersize ().matrix_value ();
4108 
4109  pos(0) /= sz(0);
4110  pos(1) /= sz(1);
4111  pos(2) /= sz(0);
4112  pos(3) /= sz(1);
4113 
4114  std::string porient = get_paperorientation ();
4115  caseless_str punits = get_paperunits ();
4116  caseless_str ptype = get_papertype ();
4117 
4118  if (ptype.compare ("<custom>"))
4119  {
4120  if (old_paperunits.compare ("centimeters"))
4121  {
4122  sz(0) /= 2.54;
4123  sz(1) /= 2.54;
4124  }
4125  else if (old_paperunits.compare ("points"))
4126  {
4127  sz(0) /= 72.0;
4128  sz(1) /= 72.0;
4129  }
4130 
4131  if (punits.compare ("centimeters"))
4132  {
4133  sz(0) *= 2.54;
4134  sz(1) *= 2.54;
4135  }
4136  else if (punits.compare ("points"))
4137  {
4138  sz(0) *= 72.0;
4139  sz(1) *= 72.0;
4140  }
4141  }
4142  else
4143  {
4144  sz = papersize_from_type (punits, ptype);
4145  if (porient == "landscape")
4146  std::swap (sz(0), sz(1));
4147  }
4148 
4149  pos(0) *= sz(0);
4150  pos(1) *= sz(1);
4151  pos(2) *= sz(0);
4152  pos(3) *= sz(1);
4153 
4154  papersize.set (octave_value (sz));
4155  paperposition.set (octave_value (pos));
4156 }
4157 
4158 void
4160 {
4161  std::string typ = get_papertype ();
4162  if (typ != "<custom>")
4163  {
4164  Matrix sz = papersize_from_type (get_paperunits (), typ);
4165  if (get_paperorientation () == "landscape")
4166  std::swap (sz(0), sz(1));
4167  // Call papersize.set rather than set_papersize to avoid loops
4168  // between update_papersize and update_papertype.
4169  papersize.set (octave_value (sz));
4170  }
4171 
4172  if (paperpositionmode.is ("auto"))
4173  paperposition.set (get_auto_paperposition ());
4174 }
4175 
4176 void
4178 {
4179  Matrix sz = get_papersize ().matrix_value ();
4180  if (sz(0) > sz(1))
4181  {
4182  std::swap (sz(0), sz(1));
4183  papersize.set (octave_value (sz));
4184  paperorientation.set (octave_value ("landscape"));
4185  }
4186  else
4187  {
4188  paperorientation.set ("portrait");
4189  }
4190 
4191  std::string punits = get_paperunits ();
4192  if (punits == "centimeters")
4193  {
4194  sz(0) /= 2.54;
4195  sz(1) /= 2.54;
4196  }
4197  else if (punits == "points")
4198  {
4199  sz(0) /= 72.0;
4200  sz(1) /= 72.0;
4201  }
4202  if (punits == "normalized")
4203  {
4204  if (get_papertype () == "<custom>")
4205  error ("set: can't set the papertype to <custom> when the paperunits is normalized");
4206  }
4207  else
4208  {
4209  // FIXME: The papersizes info is also in papersize_from_type().
4210  // Both should be rewritten to avoid the duplication.
4211  // Don't Repeat Yourself (DRY) principle.
4212  std::string ptype = "<custom>";
4213  const double mm2in = 1.0 / 25.4;
4214  const double tol = 0.01;
4215 
4216  if (std::abs (sz(0) - 8.5) + std::abs (sz(1) - 11.0) < tol)
4217  ptype = "usletter";
4218  else if (std::abs (sz(0) - 8.5) + std::abs (sz(1) - 14.0) < tol)
4219  ptype = "uslegal";
4220  else if (std::abs (sz(0) - 11.0) + std::abs (sz(1) - 17.0) < tol)
4221  ptype = "tabloid";
4222  else if (std::abs (sz(0) - 841.0 * mm2in)
4223  + std::abs (sz(1) - 1198.0 * mm2in) < tol)
4224  ptype = "a0";
4225  else if (std::abs (sz(0) - 594.0 * mm2in)
4226  + std::abs (sz(1) - 841.0 * mm2in) < tol)
4227  ptype = "a1";
4228  else if (std::abs (sz(0) - 420.0 * mm2in)
4229  + std::abs (sz(1) - 594.0 * mm2in) < tol)
4230  ptype = "a2";
4231  else if (std::abs (sz(0) - 297.0 * mm2in)
4232  + std::abs (sz(1) - 420.0 * mm2in) < tol)
4233  ptype = "a3";
4234  else if (std::abs (sz(0) - 210.0 * mm2in)
4235  + std::abs (sz(1) - 297.0 * mm2in) < tol)
4236  ptype = "a4";
4237  else if (std::abs (sz(0) - 148.0 * mm2in)
4238  + std::abs (sz(1) - 210.0 * mm2in) < tol)
4239  ptype = "a5";
4240  else if (std::abs (sz(0) - 1029.0 * mm2in)
4241  + std::abs (sz(1) - 1456.0 * mm2in) < tol)
4242  ptype = "b0";
4243  else if (std::abs (sz(0) - 728.0 * mm2in)
4244  + std::abs (sz(1) - 1028.0 * mm2in) < tol)
4245  ptype = "b1";
4246  else if (std::abs (sz(0) - 514.0 * mm2in)
4247  + std::abs (sz(1) - 728.0 * mm2in) < tol)
4248  ptype = "b2";
4249  else if (std::abs (sz(0) - 364.0 * mm2in)
4250  + std::abs (sz(1) - 514.0 * mm2in) < tol)
4251  ptype = "b3";
4252  else if (std::abs (sz(0) - 257.0 * mm2in)
4253  + std::abs (sz(1) - 364.0 * mm2in) < tol)
4254  ptype = "b4";
4255  else if (std::abs (sz(0) - 182.0 * mm2in)
4256  + std::abs (sz(1) - 257.0 * mm2in) < tol)
4257  ptype = "b5";
4258  else if (std::abs (sz(0) - 9.0)
4259  + std::abs (sz(1) - 12.0) < tol)
4260  ptype = "arch-a";
4261  else if (std::abs (sz(0) - 12.0)
4262  + std::abs (sz(1) - 18.0) < tol)
4263  ptype = "arch-b";
4264  else if (std::abs (sz(0) - 18.0)
4265  + std::abs (sz(1) - 24.0) < tol)
4266  ptype = "arch-c";
4267  else if (std::abs (sz(0) - 24.0)
4268  + std::abs (sz(1) - 36.0) < tol)
4269  ptype = "arch-d";
4270  else if (std::abs (sz(0) - 36.0)
4271  + std::abs (sz(1) - 48.0) < tol)
4272  ptype = "arch-e";
4273  else if (std::abs (sz(0) - 8.5)
4274  + std::abs (sz(1) - 11.0) < tol)
4275  ptype = "a";
4276  else if (std::abs (sz(0) - 11.0)
4277  + std::abs (sz(1) - 17.0) < tol)
4278  ptype = "b";
4279  else if (std::abs (sz(0) - 17.0)
4280  + std::abs (sz(1) - 22.0) < tol)
4281  ptype = "c";
4282  else if (std::abs (sz(0) - 22.0)
4283  + std::abs (sz(1) - 34.0) < tol)
4284  ptype = "d";
4285  else if (std::abs (sz(0) - 34.0)
4286  + std::abs (sz(1) - 43.0) < tol)
4287  ptype = "e";
4288  // Call papertype.set rather than set_papertype to avoid loops between
4289  // update_papersize and update_papertype
4290  papertype.set (ptype);
4291  }
4292  if (punits == "centimeters")
4293  {
4294  sz(0) *= 2.54;
4295  sz(1) *= 2.54;
4296  }
4297  else if (punits == "points")
4298  {
4299  sz(0) *= 72.0;
4300  sz(1) *= 72.0;
4301  }
4302  if (get_paperorientation () == "landscape")
4303  {
4304  std::swap (sz(0), sz(1));
4305  papersize.set (octave_value (sz));
4306  }
4307 
4308  if (paperpositionmode.is ("auto"))
4309  paperposition.set (get_auto_paperposition ());
4310 }
4311 
4312 /*
4313 %!test
4314 %! hf = figure ("visible", "off");
4315 %! unwind_protect
4316 %! set (hf, "paperunits", "inches");
4317 %! set (hf, "papersize", [5, 4]);
4318 %! set (hf, "paperunits", "points");
4319 %! assert (get (hf, "papersize"), [5, 4] * 72, 1);
4320 %! papersize = get (hf, "papersize");
4321 %! set (hf, "papersize", papersize + 1);
4322 %! set (hf, "papersize", papersize);
4323 %! assert (get (hf, "papersize"), [5, 4] * 72, 1);
4324 %! unwind_protect_cleanup
4325 %! close (hf);
4326 %! end_unwind_protect
4327 
4328 %!test
4329 %! hf = figure ("visible", "off");
4330 %! unwind_protect
4331 %! set (hf, "paperunits", "inches");
4332 %! set (hf, "papersize", [5, 4]);
4333 %! set (hf, "paperunits", "centimeters");
4334 %! assert (get (hf, "papersize"), [5, 4] * 2.54, 2.54/72);
4335 %! papersize = get (hf, "papersize");
4336 %! set (hf, "papersize", papersize + 1);
4337 %! set (hf, "papersize", papersize);
4338 %! assert (get (hf, "papersize"), [5, 4] * 2.54, 2.54/72);
4339 %! unwind_protect_cleanup
4340 %! close (hf);
4341 %! end_unwind_protect
4342 */
4343 
4344 void
4346 {
4347  std::string porient = get_paperorientation ();
4348  Matrix sz = get_papersize ().matrix_value ();
4349  if ((sz(0) > sz(1) && porient == "portrait")
4350  || (sz(0) < sz(1) && porient == "landscape"))
4351  {
4352  std::swap (sz(0), sz(1));
4353  // Call papertype.set rather than set_papertype to avoid loops
4354  // between update_papersize and update_papertype
4355  papersize.set (octave_value (sz));
4356  }
4357 
4358  if (paperpositionmode.is ("auto"))
4359  paperposition.set (get_auto_paperposition ());
4360 }
4361 
4362 /*
4363 %!test
4364 %! hf = figure ("visible", "off");
4365 %! unwind_protect
4366 %! tol = 100 * eps ();
4367 %! ## UPPER case and MiXed case is part of test and should not be changed.
4368 %! set (hf, "paperorientation", "PORTRAIT");
4369 %! set (hf, "paperunits", "inches");
4370 %! set (hf, "papertype", "USletter");
4371 %! assert (get (hf, "papersize"), [8.5, 11.0], tol);
4372 %! set (hf, "paperorientation", "Landscape");
4373 %! assert (get (hf, "papersize"), [11.0, 8.5], tol);
4374 %! set (hf, "paperunits", "centimeters");
4375 %! assert (get (hf, "papersize"), [11.0, 8.5] * 2.54, tol);
4376 %! set (hf, "papertype", "a4");
4377 %! assert (get (hf, "papersize"), [29.7, 21.0], tol);
4378 %! set (hf, "paperunits", "inches", "papersize", [8.5, 11.0]);
4379 %! assert (get (hf, "papertype"), "usletter");
4380 %! assert (get (hf, "paperorientation"), "portrait");
4381 %! set (hf, "papersize", [11.0, 8.5]);
4382 %! assert (get (hf, "papertype"), "usletter");
4383 %! assert (get (hf, "paperorientation"), "landscape");
4384 %! unwind_protect_cleanup
4385 %! close (hf);
4386 %! end_unwind_protect
4387 */
4388 
4389 void
4391 {
4392  caseless_str old_units = get_units ();
4393 
4394  if (units.set (val, true))
4395  {
4396  update_units (old_units);
4397  mark_modified ();
4398  }
4399 }
4400 
4401 void
4403 {
4404  position.set (convert_position (get_position ().matrix_value (), old_units,
4405  get_units (), screen_size_pixels ()), false);
4406 }
4407 
4408 /*
4409 %!test
4410 %! hf = figure ("visible", "off");
4411 %! old_units = get (0, "units");
4412 %! unwind_protect
4413 %! set (0, "units", "pixels");
4414 %! rsz = get (0, "screensize");
4415 %! set (gcf (), "units", "pixels");
4416 %! fsz = get (gcf (), "position");
4417 %! set (gcf (), "units", "normalized");
4418 %! pos = get (gcf (), "position");
4419 %! assert (pos, (fsz - [1, 1, 0, 0]) ./ rsz([3, 4, 3, 4]));
4420 %! unwind_protect_cleanup
4421 %! close (hf);
4422 %! set (0, "units", old_units);
4423 %! end_unwind_protect
4424 */
4425 
4428 {
4429  if (is_numbertitle ())
4430  {
4431  std::ostringstream os;
4432  std::string nm = get_name ();
4433 
4434  os << "Figure " << __myhandle__.value ();
4435  if (! nm.empty ())
4436  os << ": " << get_name ();
4437 
4438  return os.str ();
4439  }
4440  else
4441  return get_name ();
4442 }
4443 
4446 {
4448 
4449  if (retval.is_undefined ())
4450  {
4451  graphics_handle parent_h = get_parent ();
4452  graphics_object parent_go = gh_manager::get_object (parent_h);
4453 
4454  retval = parent_go.get_default (name);
4455  }
4456 
4457  return retval;
4458 }
4459 
4460 void
4462 {
4463  // empty list of local defaults
4465 
4467  plist.erase ("units");
4468  plist.erase ("position");
4469  plist.erase ("outerposition");
4470  plist.erase ("paperunits");
4471  plist.erase ("paperposition");
4472  plist.erase ("windowstyle");
4473 
4475 }
4476 
4477 // ---------------------------------------------------------------------
4478 
4479 void
4481 {
4482  position.add_constraint (dim_vector (1, 4));
4483  outerposition.add_constraint (dim_vector (1, 4));
4484  tightinset.add_constraint (dim_vector (1, 4));
4485  looseinset.add_constraint (dim_vector (1, 4));
4486  colororder.add_constraint (dim_vector (-1, 3));
4487  dataaspectratio.add_constraint (dim_vector (1, 3));
4488  plotboxaspectratio.add_constraint (dim_vector (1, 3));
4489  // FIXME: Should these use dimension vectors? Currently can set 'xlim' to
4490  // any matrix size, but only first two elements are used.
4491  alim.add_constraint (2);
4492  clim.add_constraint (2);
4493  xlim.add_constraint (2);
4494  ylim.add_constraint (2);
4495  zlim.add_constraint (2);
4496  xtick.add_constraint (dim_vector (1, -1));
4497  ytick.add_constraint (dim_vector (1, -1));
4498  ztick.add_constraint (dim_vector (1, -1));
4499  ticklength.add_constraint (dim_vector (1, 2));
4500  Matrix vw (1, 2, 0);
4501  vw(1) = 90;
4502  view = vw;
4503  view.add_constraint (dim_vector (1, 2));
4504  cameraposition.add_constraint (dim_vector (1, 3));
4505  cameratarget.add_constraint (dim_vector (1, 3));
4506  Matrix upv (1, 3, 0.0);
4507  upv(2) = 1.0;
4508  cameraupvector = upv;
4509  cameraupvector.add_constraint (dim_vector (1, 3));
4510  currentpoint.add_constraint (dim_vector (2, 3));
4511  // No constraints for hidden transform properties
4512  update_font ();
4513 
4514  x_zlim.resize (1, 2);
4515 
4516  sx = "linear";
4517  sy = "linear";
4518  sz = "linear";
4519 
4520  calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
4521  calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
4522  calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
4523 
4524  xset (xlabel.handle_value (), "handlevisibility", "off");
4525  xset (ylabel.handle_value (), "handlevisibility", "off");
4526  xset (zlabel.handle_value (), "handlevisibility", "off");
4527  xset (title.handle_value (), "handlevisibility", "off");
4528 
4529  xset (xlabel.handle_value (), "horizontalalignment", "center");
4530  xset (xlabel.handle_value (), "horizontalalignmentmode", "auto");
4531  xset (ylabel.handle_value (), "horizontalalignment", "center");
4532  xset (ylabel.handle_value (), "horizontalalignmentmode", "auto");
4533  xset (zlabel.handle_value (), "horizontalalignment", "right");
4534  xset (zlabel.handle_value (), "horizontalalignmentmode", "auto");
4535  xset (title.handle_value (), "horizontalalignment", "center");
4536  xset (title.handle_value (), "horizontalalignmentmode", "auto");
4537 
4538  xset (xlabel.handle_value (), "verticalalignment", "top");
4539  xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
4540  xset (ylabel.handle_value (), "verticalalignment", "bottom");
4541  xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
4542  xset (title.handle_value (), "verticalalignment", "bottom");
4543  xset (title.handle_value (), "verticalalignmentmode", "auto");
4544 
4545  xset (ylabel.handle_value (), "rotation", 90.0);
4546  xset (ylabel.handle_value (), "rotationmode", "auto");
4547 
4548  xset (zlabel.handle_value (), "visible", "off");
4549 
4550  xset (xlabel.handle_value (), "clipping", "off");
4551  xset (ylabel.handle_value (), "clipping", "off");
4552  xset (zlabel.handle_value (), "clipping", "off");
4553  xset (title.handle_value (), "clipping", "off");
4554 
4555  xset (xlabel.handle_value (), "autopos_tag", "xlabel");
4556  xset (ylabel.handle_value (), "autopos_tag", "ylabel");
4557  xset (zlabel.handle_value (), "autopos_tag", "zlabel");
4558  xset (title.handle_value (), "autopos_tag", "title");
4559 
4560  adopt (xlabel.handle_value ());
4561  adopt (ylabel.handle_value ());
4562  adopt (zlabel.handle_value ());
4563  adopt (title.handle_value ());
4564 
4565  Matrix tlooseinset = default_axes_position ();
4566  tlooseinset(2) = 1-tlooseinset(0)-tlooseinset(2);
4567  tlooseinset(3) = 1-tlooseinset(1)-tlooseinset(3);
4568  looseinset = tlooseinset;
4569 }
4570 
4571 Matrix
4573 {
4574  Matrix pos = init_pos;
4576  Matrix parent_bb = go.get_properties ().get_boundingbox (true);
4577  Matrix ext = get_extent (true, true);
4578  ext(1) = parent_bb(3) - ext(1) - ext(3);
4579  ext(0)++;
4580  ext(1)++;
4581  ext = convert_position (ext, "pixels", get_units (),
4582  parent_bb.extract_n (0, 2, 1, 2));
4583  if (ext(0) < pos(0))
4584  {
4585  pos(2) += pos(0)-ext(0);
4586  pos(0) = ext(0);
4587  }
4588  if (ext(0)+ext(2) > pos(0)+pos(2))
4589  pos(2) = ext(0)+ext(2)-pos(0);
4590 
4591  if (ext(1) < pos(1))
4592  {
4593  pos(3) += pos(1)-ext(1);
4594  pos(1) = ext(1);
4595  }
4596  if (ext(1)+ext(3) > pos(1)+pos(3))
4597  pos(3) = ext(1)+ext(3)-pos(1);
4598 
4599  return pos;
4600 }
4601 
4602 void
4604 {
4605  // First part is equivalent to `update_tightinset ()'
4606  if (activepositionproperty.is ("position"))
4607  update_position ();
4608  else
4609  update_outerposition ();
4610  caseless_str old_units = get_units ();
4611  set_units ("normalized");
4612  Matrix pos = position.get ().matrix_value ();
4613  Matrix outpos = outerposition.get ().matrix_value ();
4614  Matrix tightpos = calc_tightbox (pos);
4615  Matrix tinset (1, 4, 1.0);
4616  tinset(0) = pos(0)-tightpos(0);
4617  tinset(1) = pos(1)-tightpos(1);
4618  tinset(2) = tightpos(0)+tightpos(2)-pos(0)-pos(2);
4619  tinset(3) = tightpos(1)+tightpos(3)-pos(1)-pos(3);
4620  tightinset = tinset;
4621  set_units (old_units);
4622  update_transform ();
4623  if (activepositionproperty.is ("position"))
4624  update_position ();
4625  else
4626  update_outerposition ();
4627 }
4628 
4629 /*
4630 %!testif HAVE_OPENGL, HAVE_FLTK
4631 %! if (! have_window_system)
4632 %! return;
4633 %! endif
4634 %! hf = figure ("visible", "off");
4635 %! graphics_toolkit (hf, "fltk");
4636 %! unwind_protect
4637 %! subplot(2,1,1); plot(rand(10,1)); subplot(2,1,2); plot(rand(10,1));
4638 %! hax = findall (gcf (), "type", "axes");
4639 %! positions = cell2mat (get (hax, "position"));
4640 %! outerpositions = cell2mat (get (hax, "outerposition"));
4641 %! looseinsets = cell2mat (get (hax, "looseinset"));
4642 %! tightinsets = cell2mat (get (hax, "tightinset"));
4643 %! subplot(2,1,1); plot(rand(10,1)); subplot(2,1,2); plot(rand(10,1));
4644 %! hax = findall (gcf (), "type", "axes");
4645 %! assert (cell2mat (get (hax, "position")), positions, 1e-4);
4646 %! assert (cell2mat (get (hax, "outerposition")), outerpositions, 1e-4);
4647 %! assert (cell2mat (get (hax, "looseinset")), looseinsets, 1e-4);
4648 %! assert (cell2mat (get (hax, "tightinset")), tightinsets, 1e-4);
4649 %! unwind_protect_cleanup
4650 %! close (hf);
4651 %! end_unwind_protect
4652 
4653 %!testif HAVE_OPENGL, HAVE_FLTK
4654 %! if (! have_window_system)
4655 %! return;
4656 %! endif
4657 %! hf = figure ("visible", "off");
4658 %! graphics_toolkit (hf, "fltk");
4659 %! fpos = get (hf, "position");
4660 %! unwind_protect
4661 %! plot (rand (3));
4662 %! position = get (gca, "position");
4663 %! outerposition = get (gca, "outerposition");
4664 %! looseinset = get (gca, "looseinset");
4665 %! tightinset = get (gca, "tightinset");
4666 %! set (hf, "position", [fpos(1:2), 2*fpos(3:4)]);
4667 %! set (hf, "position", fpos);
4668 %! assert (get (gca, "outerposition"), outerposition, 0.001);
4669 %! assert (get (gca, "position"), position, 0.001);
4670 %! assert (get (gca, "looseinset"), looseinset, 0.001);
4671 %! assert (get (gca, "tightinset"), tightinset, 0.001);
4672 %! unwind_protect_cleanup
4673 %! close (hf);
4674 %! end_unwind_protect
4675 
4676 %!testif HAVE_OPENGL, HAVE_FLTK
4677 %! if (! have_window_system)
4678 %! return;
4679 %! endif
4680 %! hf = figure ("visible", "off");
4681 %! graphics_toolkit (hf, "fltk");
4682 %! fpos = get (hf, "position");
4683 %! set (gca, "activepositionproperty", "position");
4684 %! unwind_protect
4685 %! plot (rand (3));
4686 %! position = get (gca, "position");
4687 %! outerposition = get (gca, "outerposition");
4688 %! looseinset = get (gca, "looseinset");
4689 %! tightinset = get (gca, "tightinset");
4690 %! set (hf, "position", [fpos(1:2), 2*fpos(3:4)]);
4691 %! set (hf, "position", fpos);
4692 %! assert (get (gca, "position"), position, 0.001);
4693 %! assert (get (gca, "outerposition"), outerposition, 0.001);
4694 %! assert (get (gca, "looseinset"), looseinset, 0.001);
4695 %! assert (get (gca, "tightinset"), tightinset, 0.001);
4696 %! unwind_protect_cleanup
4697 %! close (hf);
4698 %! end_unwind_protect
4699 */
4700 
4701 void
4703  const std::string& who,
4704  const octave_value& v)
4705 {
4706  if (v.is_string ())
4707  {
4708  xset (hp.handle_value (), "string", v);
4709  return;
4710  }
4711 
4714 
4715  if (go.isa ("text"))
4716  val = ::reparent (v, "set", who, __myhandle__, false);
4717  else
4718  {
4719  std::string cname = v.class_name ();
4720 
4721  error ("set: expecting text graphics object or character string for %s property, found %s",
4722  who.c_str (), cname.c_str ());
4723  }
4724 
4725  xset (val, "handlevisibility", "off");
4726 
4728 
4730 
4731  hp = val;
4732 
4733  adopt (hp.handle_value ());
4734 }
4735 
4736 void
4738 {
4739  set_text_child (xlabel, "xlabel", v);
4740  xset (xlabel.handle_value (), "positionmode", "auto");
4741  xset (xlabel.handle_value (), "rotationmode", "auto");
4742  xset (xlabel.handle_value (), "horizontalalignmentmode", "auto");
4743  xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
4744  xset (xlabel.handle_value (), "clipping", "off");
4745  xset (xlabel.handle_value (), "color", get_xcolor ());
4746  xset (xlabel.handle_value (), "autopos_tag", "xlabel");
4747  update_xlabel_position ();
4748 }
4749 
4750 void
4752 {
4753  set_text_child (ylabel, "ylabel", v);
4754  xset (ylabel.handle_value (), "positionmode", "auto");
4755  xset (ylabel.handle_value (), "rotationmode", "auto");
4756  xset (ylabel.handle_value (), "horizontalalignmentmode", "auto");
4757  xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
4758  xset (ylabel.handle_value (), "clipping", "off");
4759  xset (ylabel.handle_value (), "color", get_ycolor ());
4760  xset (ylabel.handle_value (), "autopos_tag", "ylabel");
4761  update_ylabel_position ();
4762 }
4763 
4764 void
4766 {
4767  set_text_child (zlabel, "zlabel", v);
4768  xset (zlabel.handle_value (), "positionmode", "auto");
4769  xset (zlabel.handle_value (), "rotationmode", "auto");
4770  xset (zlabel.handle_value (), "horizontalalignmentmode", "auto");
4771  xset (zlabel.handle_value (), "verticalalignmentmode", "auto");
4772  xset (zlabel.handle_value (), "clipping", "off");
4773  xset (zlabel.handle_value (), "color", get_zcolor ());
4774  xset (zlabel.handle_value (), "autopos_tag", "zlabel");
4775  update_zlabel_position ();
4776 }
4777 
4778 void
4780 {
4781  set_text_child (title, "title", v);
4782  xset (title.handle_value (), "positionmode", "auto");
4783  xset (title.handle_value (), "horizontalalignment", "center");
4784  xset (title.handle_value (), "horizontalalignmentmode", "auto");
4785  xset (title.handle_value (), "verticalalignment", "bottom");
4786  xset (title.handle_value (), "verticalalignmentmode", "auto");
4787  xset (title.handle_value (), "clipping", "off");
4788  xset (title.handle_value (), "autopos_tag", "title");
4789  update_title_position ();
4790 }
4791 
4792 void
4794  const std::string& mode)
4795 {
4796  // FIXME: Should this have all properties in it?
4797  // Including ones we do don't implement?
4798 
4799  Matrix tlim (1, 2, 0.0);
4800  tlim(1) = 1;
4801  alim = tlim;
4802  xlim = tlim;
4803  ylim = tlim;
4804  zlim = tlim;
4805 
4806  alimmode = "auto";
4807  climmode = "auto";
4808  xlimmode = "auto";
4809  ylimmode = "auto";
4810  zlimmode = "auto";
4811 
4812  ambientlightcolor = Matrix (1, 3, 1.0);
4813 
4814  box = "off";
4815  boxstyle = "back";
4816 
4817  // Note: camera properties (not mode) will be set in update_transform
4818  camerapositionmode = "auto";
4819  cameratargetmode = "auto";
4820  cameraupvectormode = "auto";
4821  cameraviewanglemode = "auto";
4822 
4823  Matrix cl (1, 2, 0.0);
4824  cl(1) = 1;
4825  clim = cl;
4826 
4827  clippingstyle = "3dbox";
4828 
4829  color = color_values ("white");
4830  colororder = default_colororder ();
4831  colororderindex = 1.0;
4832 
4833  // Note: dataspectratio (not mode) will be set through update_aspectratios
4834  dataaspectratiomode = "auto";
4835 
4836  drawmode = "normal";
4837 
4838  fontangle = "normal";
4839  fontname = OCTAVE_DEFAULT_FONTNAME;
4840  fontsize = 10;
4841  fontunits = "points";
4842  fontsmoothing = "on";
4843  fontweight = "normal";
4844 
4845  gridalpha = 0.15;
4846  gridalphamode = "auto";
4847  gridcolor = color_values (0.15, 0.15, 0.15);
4848  gridcolormode = "auto";
4849  gridlinestyle = "-";
4850 
4851  labelfontsizemultiplier = 1.1;
4852 
4853  layer = "bottom";
4854 
4855  linestyleorder = "-";
4856  linestyleorderindex = 1.0;
4857 
4858  linewidth = 0.5;
4859 
4860  minorgridalpha = 0.25;
4861  minorgridalphamode = "auto";
4862  minorgridcolor = color_values (0.1, 0.1, 0.1);
4863  minorgridcolormode = "auto";
4864  minorgridlinestyle = ":";
4865 
4866  nextplot = "replace";
4867 
4868  // Note: plotboxaspectratio will be set through update_aspectratios
4869  plotboxaspectratiomode = "auto";
4870  projection = "orthographic";
4871 
4872  sortmethod = "depth";
4873 
4874  tickdir = "in";
4875  tickdirmode = "auto";
4876  ticklabelinterpreter = "tex";
4877  ticklength = default_axes_ticklength ();
4878 
4879  tightinset = Matrix (1, 4, 0.0);
4880 
4881  titlefontsizemultiplier = 1.1;
4882  titlefontweight = "bold";
4883 
4884  Matrix tview (1, 2, 0.0);
4885  tview(1) = 90;
4886  view = tview;
4887 
4888  xaxislocation = "bottom";
4889 
4890  xcolor = color_values (0.15, 0.15, 0.15);
4891  xcolormode = "auto";
4892  xdir = "normal";
4893  xgrid = "off";
4894  xminorgrid = "off";
4895  xminortick = "off";
4896  xscale = "linear";
4897  xtick = Matrix ();
4898  xticklabel = "";
4899  xticklabelmode = "auto";
4900  xticklabelrotation = 0.0;
4901  xtickmode = "auto";
4902 
4903  yaxislocation = "left";
4904 
4905  ycolor = color_values (0.15, 0.15, 0.15);
4906  ycolormode = "auto";
4907  ydir = "normal";
4908  ygrid = "off";
4909  yminorgrid = "off";
4910  yminortick = "off";
4911  yscale = "linear";
4912  ytick = Matrix ();
4913  yticklabel = "";
4914  yticklabelmode = "auto";
4915  yticklabelrotation = 0.0;
4916  ytickmode = "auto";
4917 
4918  zcolor = color_values (0.15, 0.15, 0.15);
4919  zcolormode = "auto";
4920  zdir = "normal";
4921  zgrid = "off";
4922  zminorgrid = "off";
4923  zminortick = "off";
4924  zscale = "linear";
4925  ztick = Matrix ();
4926  zticklabel = "";
4927  zticklabelmode = "auto";
4928  zticklabelrotation = 0.0;
4929  ztickmode = "auto";
4930 
4931  sx = "linear";
4932  sy = "linear";
4933  sz = "linear";
4934 
4935  visible = "on";
4936 
4937  // Replace/Reset preserves Position and Units properties
4938  if (mode != "replace" && mode != "reset")
4939  {
4940  outerposition = default_axes_outerposition ();
4941  position = default_axes_position ();
4942  activepositionproperty = "outerposition";
4943  }
4944 
4945  if (mode != "reset")
4946  {
4947  delete_children (true);
4948 
4949  xlabel.invalidate ();
4950  ylabel.invalidate ();
4951  zlabel.invalidate ();
4952  title.invalidate ();
4953 
4954  xlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
4955  false, false, false);
4956  ylabel = gh_manager::make_graphics_handle ("text", __myhandle__,
4957  false, false, false);
4958  zlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
4959  false, false, false);
4960  title = gh_manager::make_graphics_handle ("text", __myhandle__,
4961  false, false, false);
4962 
4963  adopt (xlabel.handle_value ());
4964  adopt (ylabel.handle_value ());
4965  adopt (zlabel.handle_value ());
4966  adopt (title.handle_value ());
4967 
4968  update_xlabel_position ();
4969  update_ylabel_position ();
4970  update_zlabel_position ();
4971  update_title_position ();
4972  }
4973  else
4974  {
4975  graphics_object go = gh_manager::get_object (xlabel.handle_value ());
4977  go = gh_manager::get_object (ylabel.handle_value ());
4979  go = gh_manager::get_object (zlabel.handle_value ());
4981  go = gh_manager::get_object (title.handle_value ());
4983  }
4984 
4985  xset (xlabel.handle_value (), "handlevisibility", "off");
4986  xset (ylabel.handle_value (), "handlevisibility", "off");
4987  xset (zlabel.handle_value (), "handlevisibility", "off");
4988  xset (title.handle_value (), "handlevisibility", "off");
4989 
4990  xset (xlabel.handle_value (), "horizontalalignment", "center");
4991  xset (xlabel.handle_value (), "horizontalalignmentmode", "auto");
4992  xset (ylabel.handle_value (), "horizontalalignment", "center");
4993  xset (ylabel.handle_value (), "horizontalalignmentmode", "auto");
4994  xset (zlabel.handle_value (), "horizontalalignment", "right");
4995  xset (zlabel.handle_value (), "horizontalalignmentmode", "auto");
4996  xset (title.handle_value (), "horizontalalignment", "center");
4997  xset (title.handle_value (), "horizontalalignmentmode", "auto");
4998 
4999  xset (xlabel.handle_value (), "verticalalignment", "top");
5000  xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
5001  xset (ylabel.handle_value (), "verticalalignment", "bottom");
5002  xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
5003  xset (title.handle_value (), "verticalalignment", "bottom");
5004  xset (title.handle_value (), "verticalalignmentmode", "auto");
5005 
5006  xset (ylabel.handle_value (), "rotation", 90.0);
5007  xset (ylabel.handle_value (), "rotationmode", "auto");
5008 
5009  xset (zlabel.handle_value (), "visible", "off");
5010 
5011  xset (xlabel.handle_value (), "clipping", "off");
5012  xset (ylabel.handle_value (), "clipping", "off");
5013  xset (zlabel.handle_value (), "clipping", "off");
5014  xset (title.handle_value (), "clipping", "off");
5015 
5016  xset (xlabel.handle_value (), "autopos_tag", "xlabel");
5017  xset (ylabel.handle_value (), "autopos_tag", "ylabel");
5018  xset (zlabel.handle_value (), "autopos_tag", "zlabel");
5019  xset (title.handle_value (), "autopos_tag", "title");
5020 
5021  update_transform ();
5022  sync_positions ();
5023  override_defaults (bgo);
5024 }
5025 
5026 void
5028 {
5029  graphics_handle h = hp.handle_value ();
5030 
5031  if (h.ok ())
5032  {
5034 
5035  if (go.valid_object ())
5036  gh_manager::free (h);
5037 
5039  }
5040 
5041  // FIXME: is it necessary to check whether the axes object is
5042  // being deleted now? I think this function is only called when an
5043  // individual child object is delete and not when the parent axes
5044  // object is deleted.
5045 
5046  if (! is_beingdeleted ())
5047  {
5048  hp = gh_manager::make_graphics_handle ("text", __myhandle__,
5049  false, false);
5050 
5051  xset (hp.handle_value (), "handlevisibility", "off");
5052 
5053  adopt (hp.handle_value ());
5054  }
5055 }
5056 
5057 void
5059 {
5060  if (xlabel.handle_value ().ok () && h == xlabel.handle_value ())
5061  {
5062  delete_text_child (xlabel);
5063  update_xlabel_position ();
5064  }
5065  else if (ylabel.handle_value ().ok () && h == ylabel.handle_value ())
5066  {
5067  delete_text_child (ylabel);
5068  update_ylabel_position ();
5069  }
5070  else if (zlabel.handle_value ().ok () && h == zlabel.handle_value ())
5071  {
5072  delete_text_child (zlabel);
5073  update_zlabel_position ();
5074  }
5075  else if (title.handle_value ().ok () && h == title.handle_value ())
5076  {
5077  delete_text_child (title);
5078  update_title_position ();
5079  }
5080  else
5082 }
5083 
5084 inline Matrix
5086 {
5087  Matrix m (4, 4, 0.0);
5088 
5089  for (int i = 0; i < 4; i++)
5090  m(i,i) = 1;
5091 
5092  return m;
5093 }
5094 
5095 inline ColumnVector
5097 {
5098  ColumnVector v (4, 0.0);
5099 
5100  v(3) = 1;
5101 
5102  return v;
5103 }
5104 
5105 inline ColumnVector
5106 xform_vector (double x, double y, double z)
5107 {
5108  ColumnVector v (4, 1.0);
5109 
5110  v(0) = x;
5111  v(1) = y;
5112  v(2) = z;
5113 
5114  return v;
5115 }
5116 
5117 inline ColumnVector
5118 transform (const Matrix& m, double x, double y, double z)
5119 {
5120  return (m * xform_vector (x, y, z));
5121 }
5122 
5123 inline Matrix
5124 xform_scale (double x, double y, double z)
5125 {
5126  Matrix m (4, 4, 0.0);
5127 
5128  m(0,0) = x;
5129  m(1,1) = y;
5130  m(2,2) = z;
5131  m(3,3) = 1;
5132 
5133  return m;
5134 }
5135 
5136 inline Matrix
5137 xform_translate (double x, double y, double z)
5138 {
5139  Matrix m = xform_matrix ();
5140 
5141  m(0,3) = x;
5142  m(1,3) = y;
5143  m(2,3) = z;
5144  m(3,3) = 1;
5145 
5146  return m;
5147 }
5148 
5149 inline void
5150 scale (Matrix& m, double x, double y, double z)
5151 {
5152  m = m * xform_scale (x, y, z);
5153 }
5154 
5155 inline void
5156 translate (Matrix& m, double x, double y, double z)
5157 {
5158  m = m * xform_translate (x, y, z);
5159 }
5160 
5161 inline void
5163 {
5164  v = m * v;
5165 }
5166 
5167 inline void
5168 scale (ColumnVector& v, double x, double y, double z)
5169 {
5170  v(0) *= x;
5171  v(1) *= y;
5172  v(2) *= z;
5173 }
5174 
5175 inline void
5176 translate (ColumnVector& v, double x, double y, double z)
5177 {
5178  v(0) += x;
5179  v(1) += y;
5180  v(2) += z;
5181 }
5182 
5183 inline void
5185 {
5186  double fact = 1.0 / sqrt (v(0)*v(0)+v(1)*v(1)+v(2)*v(2));
5187  scale (v, fact, fact, fact);
5188 }
5189 
5190 inline double
5191 dot (const ColumnVector& v1, const ColumnVector& v2)
5192 {
5193  return (v1(0)*v2(0)+v1(1)*v2(1)+v1(2)*v2(2));
5194 }
5195 
5196 inline double
5197 norm (const ColumnVector& v)
5198 {
5199  return sqrt (dot (v, v));
5200 }
5201 
5202 inline ColumnVector
5203 cross (const ColumnVector& v1, const ColumnVector& v2)
5204 {
5205  ColumnVector r = xform_vector ();
5206 
5207  r(0) = v1(1)*v2(2) - v1(2)*v2(1);
5208  r(1) = v1(2)*v2(0) - v1(0)*v2(2);
5209  r(2) = v1(0)*v2(1) - v1(1)*v2(0);
5210 
5211  return r;
5212 }
5213 
5214 inline Matrix
5216 {
5217  static double data[32] =
5218  {
5219  0,0,0,1,
5220  1,0,0,1,
5221  0,1,0,1,
5222  0,0,1,1,
5223  1,1,0,1,
5224  1,0,1,1,
5225  0,1,1,1,
5226  1,1,1,1
5227  };
5228  Matrix m (4, 8);
5229 
5230  memcpy (m.fortran_vec (), data, sizeof (double)*32);
5231 
5232  return m;
5233 }
5234 
5235 inline ColumnVector
5237 {
5238  ColumnVector retval (4, 1.0);
5239 
5240  memcpy (retval.fortran_vec (), m.fortran_vec (), sizeof (double)*3);
5241 
5242  return retval;
5243 }
5244 
5245 inline RowVector
5247 {
5248  return v.extract_n (0, 3).transpose ();
5249 }
5250 
5251 void
5253 {
5254  double xd = (xdir_is ("normal") ? 1 : -1);
5255  double yd = (ydir_is ("normal") ? 1 : -1);
5256  double zd = (zdir_is ("normal") ? 1 : -1);
5257 
5258  Matrix xlimits = sx.scale (get_xlim ().matrix_value ());
5259  Matrix ylimits = sy.scale (get_ylim ().matrix_value ());
5260  Matrix zlimits = sz.scale (get_zlim ().matrix_value ());
5261 
5262  double xo = xlimits(xd > 0 ? 0 : 1);
5263  double yo = ylimits(yd > 0 ? 0 : 1);
5264  double zo = zlimits(zd > 0 ? 0 : 1);
5265 
5266  Matrix pb = get_plotboxaspectratio ().matrix_value ();
5267 
5268  bool autocam = (camerapositionmode_is ("auto")
5269  && cameratargetmode_is ("auto")
5270  && cameraupvectormode_is ("auto")
5271  && cameraviewanglemode_is ("auto"));
5272  bool dowarp = (autocam && dataaspectratiomode_is ("auto")
5273  && plotboxaspectratiomode_is ("auto"));
5274 
5275  ColumnVector c_eye (xform_vector ());
5276  ColumnVector c_center (xform_vector ());
5277  ColumnVector c_upv (xform_vector ());
5278 
5279  if (cameratargetmode_is ("auto"))
5280  {
5281  c_center(0) = (xlimits(0) + xlimits(1)) / 2;
5282  c_center(1) = (ylimits(0) + ylimits(1)) / 2;
5283  c_center(2) = (zlimits(0) + zlimits(1)) / 2;
5284 
5285  cameratarget = xform2cam (c_center);
5286  }
5287  else
5288  c_center = cam2xform (get_cameratarget ().matrix_value ());
5289 
5290  if (camerapositionmode_is ("auto"))
5291  {
5292  Matrix tview = get_view ().matrix_value ();
5293  double az = tview(0);
5294  double el = tview(1);
5295  double d = 5 * sqrt (pb(0)*pb(0) + pb(1)*pb(1) + pb(2)*pb(2));
5296 
5297  if (el == 90 || el == -90)
5298  c_eye(2) = d*octave::math::signum (el);
5299  else
5300  {
5301  az *= M_PI/180.0;
5302  el *= M_PI/180.0;
5303  c_eye(0) = d * cos (el) * sin (az);
5304  c_eye(1) = -d* cos (el) * cos (az);
5305  c_eye(2) = d * sin (el);
5306  }
5307  c_eye(0) = c_eye(0)*(xlimits(1)-xlimits(0))/(xd*pb(0))+c_center(0);
5308  c_eye(1) = c_eye(1)*(ylimits(1)-ylimits(0))/(yd*pb(1))+c_center(1);
5309  c_eye(2) = c_eye(2)*(zlimits(1)-zlimits(0))/(zd*pb(2))+c_center(2);
5310 
5311  cameraposition = xform2cam (c_eye);
5312  }
5313  else
5314  c_eye = cam2xform (get_cameraposition ().matrix_value ());
5315 
5316  if (cameraupvectormode_is ("auto"))
5317  {
5318  Matrix tview = get_view ().matrix_value ();
5319  double az = tview(0);
5320  double el = tview(1);
5321 
5322  if (el == 90 || el == -90)
5323  {
5324  c_upv(0) = -octave::math::signum (el)
5325  * sin (az*M_PI/180.0)*(xlimits(1)-xlimits(0))/pb(0);
5326  c_upv(1) = octave::math::signum (el)
5327  * cos (az*M_PI/180.0)*(ylimits(1)-ylimits(0))/pb(1);
5328  }
5329  else
5330  c_upv(2) = 1;
5331 
5332  cameraupvector = xform2cam (c_upv);
5333  }
5334  else
5335  c_upv = cam2xform (get_cameraupvector ().matrix_value ());
5336 
5337  Matrix x_view = xform_matrix ();
5338  Matrix x_projection = xform_matrix ();
5339  Matrix x_viewport = xform_matrix ();
5340  Matrix x_normrender = xform_matrix ();
5341  Matrix x_pre = xform_matrix ();
5342 
5343  x_render = xform_matrix ();
5344  x_render_inv = xform_matrix ();
5345 
5346  scale (x_pre, pb(0), pb(1), pb(2));
5347  translate (x_pre, -0.5, -0.5, -0.5);
5348  scale (x_pre, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
5349  zd/(zlimits(1)-zlimits(0)));
5350  translate (x_pre, -xo, -yo, -zo);
5351 
5352  xform (c_eye, x_pre);
5353  xform (c_center, x_pre);
5354  scale (c_upv, pb(0)/(xlimits(1)-xlimits(0)), pb(1)/(ylimits(1)-ylimits(0)),
5355  pb(2)/(zlimits(1)-zlimits(0)));
5356  translate (c_center, -c_eye(0), -c_eye(1), -c_eye(2));
5357 
5358  ColumnVector F (c_center), f (F), UP (c_upv);
5359  normalize (f);
5360  normalize (UP);
5361 
5362  if (std::abs (dot (f, UP)) > 1e-15)
5363  {
5364  double fa = 1 / sqrt (1 - f(2)*f(2));
5365  scale (UP, fa, fa, fa);
5366  }
5367 
5368  ColumnVector s = cross (f, UP);
5369  ColumnVector u = cross (s, f);
5370 
5371  scale (x_view, 1, 1, -1);
5372  Matrix l = xform_matrix ();
5373  l(0,0) = s(0); l(0,1) = s(1); l(0,2) = s(2);
5374  l(1,0) = u(0); l(1,1) = u(1); l(1,2) = u(2);
5375  l(2,0) = -f(0); l(2,1) = -f(1); l(2,2) = -f(2);
5376  x_view = x_view * l;
5377  translate (x_view, -c_eye(0), -c_eye(1), -c_eye(2));
5378  scale (x_view, pb(0), pb(1), pb(2));
5379  translate (x_view, -0.5, -0.5, -0.5);
5380 
5381  Matrix x_cube = x_view * unit_cube ();
5382  ColumnVector cmin = x_cube.row_min ();
5383  ColumnVector cmax = x_cube.row_max ();
5384  double xM = cmax(0) - cmin(0);
5385  double yM = cmax(1) - cmin(1);
5386 
5387  Matrix bb = get_boundingbox (true);
5388 
5389  double v_angle;
5390 
5391  if (cameraviewanglemode_is ("auto"))
5392  {
5393  double af;
5394 
5395  // FIXME: was this really needed? When compared to Matlab, it
5396  // does not seem to be required. Need investigation with concrete
5397  // graphics toolkit to see results visually.
5398  if (false && dowarp)
5399  af = 1.0 / (xM > yM ? xM : yM);
5400  else
5401  {
5402  if ((bb(2)/bb(3)) > (xM/yM))
5403  af = 1.0 / yM;
5404  else
5405  af = 1.0 / xM;
5406  }
5407  v_angle = 2 * (180.0 / M_PI) * atan (1 / (2 * af * norm (F)));
5408 
5409  cameraviewangle = v_angle;
5410  }
5411  else
5412  v_angle = get_cameraviewangle ();
5413 
5414  double pf = 1 / (2 * tan ((v_angle / 2) * M_PI / 180.0) * norm (F));
5415  scale (x_projection, pf, pf, 1);
5416 
5417  if (dowarp)
5418  {
5419  xM *= pf;
5420  yM *= pf;
5421  translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
5422  scale (x_viewport, bb(2)/xM, -bb(3)/yM, 1);
5423  }
5424  else
5425  {
5426  double pix = 1;
5427  if (autocam)
5428  {
5429  if ((bb(2)/bb(3)) > (xM/yM))
5430  pix = bb(3);
5431  else
5432  pix = bb(2);
5433  }
5434  else
5435  pix = (bb(2) < bb(3) ? bb(2) : bb(3));
5436  translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
5437  scale (x_viewport, pix, -pix, 1);
5438  }
5439 
5440  x_normrender = x_viewport * x_projection * x_view;
5441 
5442  x_cube = x_normrender * unit_cube ();
5443  cmin = x_cube.row_min ();
5444  cmax = x_cube.row_max ();
5445  x_zlim.resize (1, 2);
5446  x_zlim(0) = cmin(2);
5447  x_zlim(1) = cmax(2);
5448 
5449  x_render = x_normrender;
5450  scale (x_render, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
5451  zd/(zlimits(1)-zlimits(0)));
5452  translate (x_render, -xo, -yo, -zo);
5453 
5454  x_viewtransform = x_view;
5455  x_projectiontransform = x_projection;
5456  x_viewporttransform = x_viewport;
5457  x_normrendertransform = x_normrender;
5458  x_rendertransform = x_render;
5459 
5460  x_render_inv = x_render.inverse ();
5461 
5462  // Note: these matrices are a slight modified version of the regular matrices,
5463  // more suited for OpenGL rendering (x_gl_mat1 => light => x_gl_mat2)
5464  x_gl_mat1 = x_view;
5465  scale (x_gl_mat1, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
5466  zd/(zlimits(1)-zlimits(0)));
5467  translate (x_gl_mat1, -xo, -yo, -zo);
5468  x_gl_mat2 = x_viewport * x_projection;
5469 }
5470 
5471 static bool updating_axes_layout = false;
5472 
5473 void
5475 {
5476  if (updating_axes_layout)
5477  return;
5478 
5479  graphics_xform xform = get_transform ();
5480 
5481  double xd = (xdir_is ("normal") ? 1 : -1);
5482  double yd = (ydir_is ("normal") ? 1 : -1);
5483  double zd = (zdir_is ("normal") ? 1 : -1);
5484 
5485  const Matrix xlims = xform.xscale (get_xlim ().matrix_value ());
5486  const Matrix ylims = xform.yscale (get_ylim ().matrix_value ());
5487  const Matrix zlims = xform.zscale (get_zlim ().matrix_value ());
5488 
5489  double x_min, x_max, y_min, y_max, z_min, z_max;
5490  x_min = xlims(0), x_max = xlims(1);
5491  y_min = ylims(0), y_max = ylims(1);
5492  z_min = zlims(0), z_max = zlims(1);
5493 
5494  ColumnVector p1, p2, dir (3);
5495 
5496  xstate = ystate = zstate = AXE_ANY_DIR;
5497 
5498  p1 = xform.transform (x_min, (y_min+y_max)/2, (z_min+z_max)/2, false);
5499  p2 = xform.transform (x_max, (y_min+y_max)/2, (z_min+z_max)/2, false);
5500  dir(0) = octave::math::round (p2(0) - p1(0));
5501  dir(1) = octave::math::round (p2(1) - p1(1));
5502  dir(2) = (p2(2) - p1(2));
5503  if (dir(0) == 0 && dir(1) == 0)
5504  xstate = AXE_DEPTH_DIR;
5505  else if (dir(2) == 0)
5506  {
5507  if (dir(0) == 0)
5508  xstate = AXE_VERT_DIR;
5509  else if (dir(1) == 0)
5510  xstate = AXE_HORZ_DIR;
5511  }
5512 
5513  if (dir(2) == 0)
5514  {
5515  if (dir(1) == 0)
5516  xPlane = (dir(0) > 0 ? x_max : x_min);
5517  else
5518  xPlane = (dir(1) < 0 ? x_max : x_min);
5519  }
5520  else
5521  xPlane = (dir(2) < 0 ? x_min : x_max);
5522 
5523  xPlaneN = (xPlane == x_min ? x_max : x_min);
5524  fx = (x_max - x_min) / sqrt (dir(0)*dir(0) + dir(1)*dir(1));
5525 
5526  p1 = xform.transform ((x_min + x_max)/2, y_min, (z_min + z_max)/2, false);
5527  p2 = xform.transform ((x_min + x_max)/2, y_max, (z_min + z_max)/2, false);
5528  dir(0) = octave::math::round (p2(0) - p1(0));
5529  dir(1) = octave::math::round (p2(1) - p1(1));
5530  dir(2) = (p2(2) - p1(2));
5531  if (dir(0) == 0 && dir(1) == 0)
5532  ystate = AXE_DEPTH_DIR;
5533  else if (dir(2) == 0)
5534  {
5535  if (dir(0) == 0)
5536  ystate = AXE_VERT_DIR;
5537  else if (dir(1) == 0)
5538  ystate = AXE_HORZ_DIR;
5539  }
5540 
5541  if (dir(2) == 0)
5542  {
5543  if (dir(1) == 0)
5544  yPlane = (dir(0) > 0 ? y_max : y_min);
5545  else
5546  yPlane = (dir(1) < 0 ? y_max : y_min);
5547  }
5548  else
5549  yPlane = (dir(2) < 0 ? y_min : y_max);
5550 
5551  yPlaneN = (yPlane == y_min ? y_max : y_min);
5552  fy = (y_max - y_min) / sqrt (dir(0)*dir(0) + dir(1)*dir(1));
5553 
5554  p1 = xform.transform ((x_min + x_max)/2, (y_min + y_max)/2, z_min, false);
5555  p2 = xform.transform ((x_min + x_max)/2, (y_min + y_max)/2, z_max, false);
5556  dir(0) = octave::math::round (p2(0) - p1(0));
5557  dir(1) = octave::math::round (p2(1) - p1(1));
5558  dir(2) = (p2(2) - p1(2));
5559  if (dir(0) == 0 && dir(1) == 0)
5560  zstate = AXE_DEPTH_DIR;
5561  else if (dir(2) == 0)
5562  {
5563  if (dir(0) == 0)
5564  zstate = AXE_VERT_DIR;
5565  else if (dir(1) == 0)
5566  zstate = AXE_HORZ_DIR;
5567  }
5568 
5569  if (dir(2) == 0)
5570  {
5571  if (dir(1) == 0)
5572  zPlane = (dir(0) > 0 ? z_min : z_max);
5573  else
5574  zPlane = (dir(1) < 0 ? z_min : z_max);
5575  }
5576  else
5577  zPlane = (dir(2) < 0 ? z_min : z_max);
5578 
5579  zPlaneN = (zPlane == z_min ? z_max : z_min);
5580  fz = (z_max - z_min) / sqrt (dir(0)*dir(0) + dir(1)*dir(1));
5581 
5583  frame.protect_var (updating_axes_layout);
5584  updating_axes_layout = true;
5585 
5586  xySym = (xd*yd*(xPlane-xPlaneN)*(yPlane-yPlaneN) > 0);
5587  zSign = (zd*(zPlane-zPlaneN) <= 0);
5588  xyzSym = zSign ? xySym : ! xySym;
5589  xpTick = (zSign ? xPlaneN : xPlane);
5590  ypTick = (zSign ? yPlaneN : yPlane);
5591  zpTick = (zSign ? zPlane : zPlaneN);
5592  xpTickN = (zSign ? xPlane : xPlaneN);
5593  ypTickN = (zSign ? yPlane : yPlaneN);
5594  zpTickN = (zSign ? zPlaneN : zPlane);
5595 
5596  // 2D mode
5597  x2Dtop = false;
5598  y2Dright = false;
5599  layer2Dtop = false;
5600  if (xstate == AXE_HORZ_DIR && ystate == AXE_VERT_DIR)
5601  {
5602  if (xaxislocation_is ("top"))
5603  {
5604  std::swap (yPlane, yPlaneN);
5605  x2Dtop = true;
5606  }
5607  ypTick = yPlaneN;
5608  ypTickN = yPlane;
5609  if (yaxislocation_is ("right"))
5610  {
5611  std::swap (xPlane, xPlaneN);
5612  y2Dright = true;
5613  }
5614  xpTick = xPlaneN;
5615  xpTickN = xPlane;
5616  if (layer_is ("top"))
5617  {
5618  zpTick = zPlaneN;
5619  layer2Dtop = true;
5620  }
5621  else
5622  zpTick = zPlane;
5623  }
5624 
5625  Matrix viewmat = get_view ().matrix_value ();
5626  nearhoriz = std::abs (viewmat(1)) <= 5;
5627  is2D = viewmat(1) == 90;
5628 
5629  update_ticklength ();
5630 }
5631 
5632 void
5634 {
5635  bool mode2d = (((xstate > AXE_DEPTH_DIR ? 1 : 0) +
5636  (ystate > AXE_DEPTH_DIR ? 1 : 0) +
5637  (zstate > AXE_DEPTH_DIR ? 1 : 0)) == 2);
5638 
5639  if (tickdirmode_is ("auto"))
5640  tickdir.set (mode2d ? "in" : "out", true);
5641 
5642  double ticksign = (tickdir_is ("in") ? -1 : 1);
5643 
5644  Matrix bbox = get_boundingbox (true);
5645  Matrix ticklen = get_ticklength ().matrix_value ();
5646  ticklen(0) *= std::max (bbox(2), bbox(3));
5647  ticklen(1) *= std::max (bbox(2), bbox(3));
5648 
5649  xticklen = ticksign * (mode2d ? ticklen(0) : ticklen(1));
5650  yticklen = ticksign * (mode2d ? ticklen(0) : ticklen(1));
5651  zticklen = ticksign * (mode2d ? ticklen(0) : ticklen(1));
5652 
5653  xtickoffset = (mode2d ? std::max (0., xticklen) : std::abs (xticklen)) + 5;
5654  ytickoffset = (mode2d ? std::max (0., yticklen) : std::abs (yticklen)) + 5;
5655  ztickoffset = (mode2d ? std::max (0., zticklen) : std::abs (zticklen)) + 5;
5656 
5657  update_xlabel_position ();
5658  update_ylabel_position ();
5659  update_zlabel_position ();
5660  update_title_position ();
5661 }
5662 
5663 /*
5664 ## FIXME: A demo can't be called in a C++ file. This should be made a test
5665 ## or moved to a .m file where it can be called.
5666 %!demo
5667 %! clf;
5668 %! subplot (2,1,1);
5669 %! plot (rand (3));
5670 %! xlabel xlabel;
5671 %! ylabel ylabel;
5672 %! title title;
5673 %! subplot (2,1,2);
5674 %! plot (rand (3));
5675 %! set (gca, "ticklength", get (gca, "ticklength") * 2, "tickdir", "out");
5676 %! xlabel xlabel;
5677 %! ylabel ylabel;
5678 %! title title;
5679 */
5680 
5681 static ColumnVector
5683  const text::properties& props,
5684  const graphics_xform& xform,
5685  const Matrix& bbox)
5686 {
5688 
5689  std::string to_units = props.get_units ();
5690 
5691  if (to_units != "data")
5692  {
5693  ColumnVector v = xform.transform (p(0), p(1), p(2));
5694 
5695  retval.resize (3);
5696 
5697  retval(0) = v(0) - bbox(0) + 1;
5698  retval(1) = bbox(1) + bbox(3) - v(1) + 1;
5699  retval(2) = 0;
5700 
5701  retval = convert_position (retval, "pixels", to_units,
5702  bbox.extract_n (0, 2, 1, 2));
5703  }
5704  else
5705  retval = p;
5706 
5707  return retval;
5708 }
5709 
5710 static bool updating_xlabel_position = false;
5711 
5712 void
5714 {
5715  if (updating_xlabel_position)
5716  return;
5717 
5718  graphics_object go = gh_manager::get_object (get_xlabel ());
5719 
5720  if (! go.valid_object ())
5721  return;
5722 
5723  text::properties& xlabel_props
5724  = reinterpret_cast<text::properties&> (go.get_properties ());
5725 
5726  bool is_empty = xlabel_props.get_string ().is_empty ();
5727 
5729  frame.protect_var (updating_xlabel_position);
5730  updating_xlabel_position = true;
5731 
5732  if (! is_empty)
5733  {
5734  if (xlabel_props.horizontalalignmentmode_is ("auto"))
5735  {
5736  xlabel_props.set_horizontalalignment
5737  (xstate > AXE_DEPTH_DIR ? "center" : (xyzSym ? "left" : "right"));
5738 
5739  xlabel_props.set_horizontalalignmentmode ("auto");
5740  }
5741 
5742  if (xlabel_props.verticalalignmentmode_is ("auto"))
5743  {
5744  xlabel_props.set_verticalalignment
5745  (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
5746 
5747  xlabel_props.set_verticalalignmentmode ("auto");
5748  }
5749  }
5750 
5751  if (xlabel_props.positionmode_is ("auto")
5752  || xlabel_props.rotationmode_is ("auto"))
5753  {
5754  graphics_xform xform = get_transform ();
5755 
5756  Matrix ext (1, 2, 0.0);
5757  ext = get_ticklabel_extents (get_xtick ().matrix_value (),
5758  get_xticklabel ().string_vector_value (),
5759  get_xlim ().matrix_value ());
5760 
5761  double wmax = ext(0);
5762  double hmax = ext(1);
5763  double angle = 0.0;
5764  ColumnVector p =
5765  graphics_xform::xform_vector ((xpTickN + xpTick)/2, ypTick, zpTick);
5766 
5767  bool tick_along_z = nearhoriz || octave::math::isinf (fy);
5768  if (tick_along_z)
5769  p(2) += (octave::math::signum (zpTick - zpTickN) * fz * xtickoffset);
5770  else
5771  p(1) += (octave::math::signum (ypTick - ypTickN) * fy * xtickoffset);
5772 
5773  p = xform.transform (p(0), p(1), p(2), false);
5774 
5775  switch (xstate)
5776  {
5777  case AXE_ANY_DIR:
5778  p(0) += (xyzSym ? wmax : -wmax);
5779  p(1) += hmax;
5780  break;
5781 
5782  case AXE_VERT_DIR:
5783  p(0) -= wmax;
5784  angle = 90;
5785  break;
5786 
5787  case AXE_HORZ_DIR:
5788  p(1) += (x2Dtop ? -hmax : hmax);
5789  break;
5790  }
5791 
5792  if (xlabel_props.positionmode_is ("auto"))
5793  {
5794  p = xform.untransform (p(0), p(1), p(2), true);
5795 
5796  p = convert_label_position (p, xlabel_props, xform,
5797  get_extent (false));
5798 
5799  xlabel_props.set_position (p.extract_n (0, 3).transpose ());
5800  xlabel_props.set_positionmode ("auto");
5801  }
5802 
5803  if (! is_empty && xlabel_props.rotationmode_is ("auto"))
5804  {
5805  xlabel_props.set_rotation (angle);
5806  xlabel_props.set_rotationmode ("auto");
5807  }
5808  }
5809 }
5810 
5811 static bool updating_ylabel_position = false;
5812 
5813 void
5815 {
5816  if (updating_ylabel_position)
5817  return;
5818 
5819  graphics_object go = gh_manager::get_object (get_ylabel ());
5820 
5821  if (! go.valid_object ())
5822  return;
5823 
5824  text::properties& ylabel_props
5825  = reinterpret_cast<text::properties&> (go.get_properties ());
5826 
5827  bool is_empty = ylabel_props.get_string ().is_empty ();
5828 
5830  frame.protect_var (updating_ylabel_position);
5831  updating_ylabel_position = true;
5832 
5833  if (! is_empty)
5834  {
5835  if (ylabel_props.horizontalalignmentmode_is ("auto"))
5836  {
5837  ylabel_props.set_horizontalalignment
5838  (ystate > AXE_DEPTH_DIR ? "center" : (! xyzSym ? "left" : "right"));
5839 
5840  ylabel_props.set_horizontalalignmentmode ("auto");
5841  }
5842 
5843  if (ylabel_props.verticalalignmentmode_is ("auto"))
5844  {
5845  ylabel_props.set_verticalalignment
5846  (ystate == AXE_VERT_DIR && ! y2Dright ? "bottom" : "top");
5847 
5848  ylabel_props.set_verticalalignmentmode ("auto");
5849  }
5850  }
5851 
5852  if (ylabel_props.positionmode_is ("auto")
5853  || ylabel_props.rotationmode_is ("auto"))
5854  {
5855  graphics_xform xform = get_transform ();
5856 
5857  Matrix ext (1, 2, 0.0);
5858 
5859  // The underlying get_extents() from FreeType produces mismatched values.
5860  // x-extent accurately measures the width of the glyphs.
5861  // y-extent instead measures from baseline-to-baseline.
5862  // Pad x-extent (+4) so that it approximately matches y-extent.
5863  // This keeps ylabels about the same distance from y-axis as
5864  // xlabels are from x-axis.
5865  // ALWAYS use an even number for padding or horizontal alignment
5866  // will be off.
5867  ext = get_ticklabel_extents (get_ytick ().matrix_value (),
5868  get_yticklabel ().string_vector_value (),
5869  get_ylim ().matrix_value ());
5870 
5871  double wmax = ext(0)+4;
5872  double hmax = ext(1);
5873  double angle = 0.0;
5874  ColumnVector p =
5875  graphics_xform::xform_vector (xpTick, (ypTickN + ypTick)/2, zpTick);
5876 
5877  bool tick_along_z = nearhoriz || octave::math::isinf (fx);
5878  if (tick_along_z)
5879  p(2) += (octave::math::signum (zpTick - zpTickN) * fz * ytickoffset);
5880  else
5881  p(0) += (octave::math::signum (xpTick - xpTickN) * fx * ytickoffset);
5882 
5883  p = xform.transform (p(0), p(1), p(2), false);
5884 
5885  switch (ystate)
5886  {
5887  case AXE_ANY_DIR:
5888  p(0) += (! xyzSym ? wmax : -wmax);
5889  p(1) += hmax;
5890  break;
5891 
5892  case AXE_VERT_DIR:
5893  p(0) += (y2Dright ? wmax : -wmax);
5894  angle = 90;
5895  break;
5896 
5897  case AXE_HORZ_DIR:
5898  p(1) += hmax;
5899  break;
5900  }
5901 
5902  if (ylabel_props.positionmode_is ("auto"))
5903  {
5904  p = xform.untransform (p(0), p(1), p(2), true);
5905 
5906  p = convert_label_position (p, ylabel_props, xform,
5907  get_extent (false));
5908 
5909  ylabel_props.set_position (p.extract_n (0, 3).transpose ());
5910  ylabel_props.set_positionmode ("auto");
5911  }
5912 
5913  if (! is_empty && ylabel_props.rotationmode_is ("auto"))
5914  {
5915  ylabel_props.set_rotation (angle);
5916  ylabel_props.set_rotationmode ("auto");
5917  }
5918  }
5919 }
5920 
5921 static bool updating_zlabel_position = false;
5922 
5923 void
5925 {
5926  if (updating_zlabel_position)
5927  return;
5928 
5929  graphics_object go = gh_manager::get_object (get_zlabel ());
5930 
5931  if (! go.valid_object ())
5932  return;
5933 
5934  text::properties& zlabel_props
5935  = reinterpret_cast<text::properties&> (go.get_properties ());
5936 
5937  bool camAuto = cameraupvectormode_is ("auto");
5938  bool is_empty = zlabel_props.get_string ().is_empty ();
5939 
5941  frame.protect_var (updating_zlabel_position);
5942  updating_zlabel_position = true;
5943 
5944  if (! is_empty)
5945  {
5946  if (zlabel_props.horizontalalignmentmode_is ("auto"))
5947  {
5948  zlabel_props.set_horizontalalignment
5949  ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
5950 
5951  zlabel_props.set_horizontalalignmentmode ("auto");
5952  }
5953 
5954  if (zlabel_props.verticalalignmentmode_is ("auto"))
5955  {
5956  zlabel_props.set_verticalalignment
5957  (zstate == AXE_VERT_DIR
5958  ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
5959 
5960  zlabel_props.set_verticalalignmentmode ("auto");
5961  }
5962  }
5963 
5964  if (zlabel_props.positionmode_is ("auto")
5965  || zlabel_props.rotationmode_is ("auto"))
5966  {
5967  graphics_xform xform = get_transform ();
5968 
5969  Matrix ext (1, 2, 0.0);
5970  ext = get_ticklabel_extents (get_ztick ().matrix_value (),
5971  get_zticklabel ().string_vector_value (),
5972  get_zlim ().matrix_value ());
5973 
5974  double wmax = ext(0);
5975  double hmax = ext(1);
5976  double angle = 0.0;
5977  ColumnVector p;
5978 
5979  if (xySym)
5980  {
5981  p = graphics_xform::xform_vector (xPlaneN, yPlane,
5982  (zpTickN + zpTick)/2);
5983  if (octave::math::isinf (fy))
5984  p(0) += octave::math::signum (xPlaneN - xPlane) * fx * ztickoffset;
5985  else
5986  p(1) += octave::math::signum (yPlane - yPlaneN) * fy * ztickoffset;
5987  }
5988  else
5989  {
5990  p = graphics_xform::xform_vector (xPlane, yPlaneN,
5991  (zpTickN + zpTick)/2);
5992  if (octave::math::isinf (fx))
5993  p(1) += octave::math::signum (yPlaneN - yPlane) * fy * ztickoffset;
5994  else
5995  p(0) += octave::math::signum (xPlane - xPlaneN) * fx * ztickoffset;
5996  }
5997 
5998  p = xform.transform (p(0), p(1), p(2), false);
5999 
6000  switch (zstate)
6001  {
6002  case AXE_ANY_DIR:
6003  if (camAuto)
6004  {
6005  p(0) -= wmax;
6006  angle = 90;
6007  }
6008 
6009  // FIXME: what's the correct offset?
6010  //
6011  // p[0] += (! xySym ? wmax : -wmax);
6012  // p[1] += (zSign ? hmax : -hmax);
6013 
6014  break;
6015 
6016  case AXE_VERT_DIR:
6017  p(0) -= wmax;
6018  angle = 90;
6019  break;
6020 
6021  case AXE_HORZ_DIR:
6022  p(1) += hmax;
6023  break;
6024  }
6025 
6026  if (zlabel_props.positionmode_is ("auto"))
6027  {
6028  p = xform.untransform (p(0), p(1), p(2), true);
6029 
6030  p = convert_label_position (p, zlabel_props, xform,
6031  get_extent (false));
6032 
6033  zlabel_props.set_position (p.extract_n (0, 3).transpose ());
6034  zlabel_props.set_positionmode ("auto");
6035  }
6036 
6037  if (! is_empty && zlabel_props.rotationmode_is ("auto"))
6038  {
6039  zlabel_props.set_rotation (angle);
6040  zlabel_props.set_rotationmode ("auto");
6041  }
6042  }
6043 }
6044 
6045 static bool updating_title_position = false;
6046 
6047 void
6049 {
6050  if (updating_title_position)
6051  return;
6052 
6053  graphics_object go = gh_manager::get_object (get_title ());
6054 
6055  if (! go.valid_object ())
6056  return;
6057 
6058  text::properties& title_props
6059  = reinterpret_cast<text::properties&> (go.get_properties ());
6060 
6062  frame.protect_var (updating_title_position);
6063  updating_title_position = true;
6064 
6065  if (title_props.positionmode_is ("auto"))
6066  {
6067  graphics_xform xform = get_transform ();
6068 
6069  // FIXME: bbox should be stored in axes::properties
6070  Matrix bbox = get_extent (false);
6071 
6072  ColumnVector p =
6073  graphics_xform::xform_vector (bbox(0) + bbox(2)/2,
6074  bbox(1) - 10,
6075  (x_zlim(0) + x_zlim(1))/2);
6076 
6077  if (x2Dtop)
6078  {
6079  Matrix ext (1, 2, 0.0);
6080  ext = get_ticklabel_extents (get_xtick ().matrix_value (),
6081  get_xticklabel ().string_vector_value (),
6082  get_xlim ().matrix_value ());
6083  p(1) -= ext(1);
6084  }
6085 
6086  p = xform.untransform (p(0), p(1), p(2), true);
6087 
6088  p = convert_label_position (p, title_props, xform, bbox);
6089 
6090  title_props.set_position (p.extract_n (0, 3).transpose ());
6091  title_props.set_positionmode ("auto");
6092  }
6093 }
6094 
6095 void
6097 {
6098  if (elem_type == "xlabel")
6099  update_xlabel_position ();
6100  else if (elem_type == "ylabel")
6101  update_ylabel_position ();
6102  else if (elem_type == "zlabel")
6103  update_zlabel_position ();
6104  else if (elem_type == "title")
6105  update_title_position ();
6106  else if (elem_type == "sync")
6107  sync_positions ();
6108 }
6109 
6110 static void
6111 normalized_aspectratios (Matrix& aspectratios, const Matrix& scalefactors,
6112  double xlength, double ylength, double zlength)
6113 {
6114  double xval = xlength / scalefactors(0);
6115  double yval = ylength / scalefactors(1);
6116  double zval = zlength / scalefactors(2);
6117 
6118  double minval = octave::math::min (octave::math::min (xval, yval), zval);
6119 
6120  aspectratios(0) = xval / minval;
6121  aspectratios(1) = yval / minval;
6122  aspectratios(2) = zval / minval;
6123 }
6124 
6125 static void
6126 max_axes_scale (double& s, Matrix& limits, const Matrix& kids,
6127  double pbfactor, double dafactor, char limit_type, bool tight)
6128 {
6129  if (tight)
6130  {
6131  double minval = octave::numeric_limits<double>::Inf ();
6132  double maxval = -octave::numeric_limits<double>::Inf ();
6133  double min_pos = octave::numeric_limits<double>::Inf ();
6134  double max_neg = -octave::numeric_limits<double>::Inf ();
6135  get_children_limits (minval, maxval, min_pos, max_neg, kids, limit_type);
6136  if (octave::math::finite (minval) && octave::math::finite (maxval))
6137  {
6138  limits(0) = minval;
6139  limits(1) = maxval;
6140  s = octave::math::max (s, (maxval - minval) / (pbfactor * dafactor));
6141  }
6142  }
6143  else
6144  s = octave::math::max (s, (limits(1) - limits(0)) / (pbfactor * dafactor));
6145 }
6146 
6147 static std::set<double> updating_aspectratios;
6148 
6149 void
6151 {
6152  if (updating_aspectratios.find (get___myhandle__ ().value ())
6153  != updating_aspectratios.end ())
6154  return;
6155 
6156  Matrix xlimits = get_xlim ().matrix_value ();
6157  Matrix ylimits = get_ylim ().matrix_value ();
6158  Matrix zlimits = get_zlim ().matrix_value ();
6159 
6160  double dx = (xlimits(1) - xlimits(0));
6161  double dy = (ylimits(1) - ylimits(0));
6162  double dz = (zlimits(1) - zlimits(0));
6163 
6164  Matrix da = get_dataaspectratio ().matrix_value ();
6165  Matrix pba = get_plotboxaspectratio ().matrix_value ();
6166 
6167  if (dataaspectratiomode_is ("auto"))
6168  {
6169  if (plotboxaspectratiomode_is ("auto"))
6170  {
6171  pba = Matrix (1, 3, 1.0);
6172  plotboxaspectratio.set (pba, false);
6173  }
6174 
6175  normalized_aspectratios (da, pba, dx, dy, dz);
6176  dataaspectratio.set (da, false);
6177  }
6178  else if (plotboxaspectratiomode_is ("auto"))
6179  {
6180  normalized_aspectratios (pba, da, dx, dy, dz);
6181  plotboxaspectratio.set (pba, false);
6182  }
6183  else
6184  {
6186  bool modified_limits = false;
6187  Matrix kids;
6188 
6189  if (xlimmode_is ("auto") && ylimmode_is ("auto") && zlimmode_is ("auto"))
6190  {
6191  modified_limits = true;
6192  kids = get_children ();
6193  max_axes_scale (s, xlimits, kids, pba(0), da(0), 'x', true);
6194  max_axes_scale (s, ylimits, kids, pba(1), da(1), 'y', true);
6195  max_axes_scale (s, zlimits, kids, pba(2), da(2), 'z', true);
6196  }
6197  else if (xlimmode_is ("auto") && ylimmode_is ("auto"))
6198  {
6199  modified_limits = true;
6200  max_axes_scale (s, zlimits, kids, pba(2), da(2), 'z', false);
6201  }
6202  else if (ylimmode_is ("auto") && zlimmode_is ("auto"))
6203  {
6204  modified_limits = true;
6205  max_axes_scale (s, xlimits, kids, pba(0), da(0), 'x', false);
6206  }
6207  else if (zlimmode_is ("auto") && xlimmode_is ("auto"))
6208  {
6209  modified_limits = true;
6210  max_axes_scale (s, ylimits, kids, pba(1), da(1), 'y', false);
6211  }
6212 
6213  if (modified_limits)
6214  {
6216  frame.protect_var (updating_aspectratios);
6217 
6218  updating_aspectratios.insert (get___myhandle__ ().value ());
6219 
6220  dx = pba(0) * da(0);
6221  dy = pba(1) * da(1);
6222  dz = pba(2) * da(2);
6223  if (octave::math::isinf (s))
6224  s = 1 / octave::math::min (octave::math::min (dx, dy), dz);
6225 
6226  if (xlimmode_is ("auto"))
6227  {
6228  dx = s * dx;
6229  xlimits(0) = 0.5 * (xlimits(0) + xlimits(1) - dx);
6230  xlimits(1) = xlimits(0) + dx;
6231  set_xlim (xlimits);
6232  set_xlimmode ("auto");
6233  }
6234 
6235  if (ylimmode_is ("auto"))
6236  {
6237  dy = s * dy;
6238  ylimits(0) = 0.5 * (ylimits(0) + ylimits(1) - dy);
6239  ylimits(1) = ylimits(0) + dy;
6240  set_ylim (ylimits);
6241  set_ylimmode ("auto");
6242  }
6243 
6244  if (zlimmode_is ("auto"))
6245  {
6246  dz = s * dz;
6247  zlimits(0) = 0.5 * (zlimits(0) + zlimits(1) - dz);
6248  zlimits(1) = zlimits(0) + dz;
6249  set_zlim (zlimits);
6250  set_zlimmode ("auto");
6251  }
6252  }
6253  else
6254  {
6255  normalized_aspectratios (pba, da, dx, dy, dz);
6256  plotboxaspectratio.set (pba, false);
6257  }
6258  }
6259 }
6260 
6261 void
6263  color_property col)
6264 {
6265  gh_manager::get_object (label.handle_value ()).set ("color", col.get ());
6266 }
6267 
6268 void
6270 {
6271  txt_renderer.set_font (get ("fontname").string_value (),
6272  get ("fontweight").string_value (),
6273  get ("fontangle").string_value (),
6274  get ("fontsize_points").double_value ());
6275 }
6276 
6277 // The INTERNAL flag defines whether position or outerposition is used.
6278 
6279 Matrix
6281  const Matrix& parent_pix_size) const
6282 {
6283  Matrix pos = internal ? get_position ().matrix_value ()
6284  : get_outerposition ().matrix_value ();
6285  Matrix parent_size (parent_pix_size);
6286 
6287  if (parent_size.is_empty ())
6288  {
6290 
6291  if (go.valid_object ())
6292  parent_size =
6293  go.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
6294  else
6295  parent_size = default_figure_position ();
6296  }
6297 
6298  pos = convert_position (pos, get_units (), "pixels", parent_size);
6299 
6300  pos(0)--;
6301  pos(1)--;
6302  pos(1) = parent_size(1) - pos(1) - pos(3);
6303 
6304  return pos;
6305 }
6306 
6307 Matrix
6308 axes::properties::get_extent (bool with_text, bool only_text_height) const
6309 {
6310  graphics_xform xform = get_transform ();
6311 
6312  Matrix ext (1, 4, 0.0);
6313  ext(0) = ext(1) = octave::numeric_limits<double>::Inf ();
6314  ext(2) = ext(3) = -octave::numeric_limits<double>::Inf ();
6315  for (int i = 0; i <= 1; i++)
6316  for (int j = 0; j <= 1; j++)
6317  for (int k = 0; k <= 1; k++)
6318  {
6319  ColumnVector p = xform.transform (i ? xPlaneN : xPlane,
6320  j ? yPlaneN : yPlane,
6321  k ? zPlaneN : zPlane, false);
6322  ext(0) = std::min (ext(0), p(0));
6323  ext(1) = std::min (ext(1), p(1));
6324  ext(2) = std::max (ext(2), p(0));
6325  ext(3) = std::max (ext(3), p(1));
6326  }
6327 
6328  if (with_text)
6329  {
6330  for (int i = 0; i < 4; i++)
6331  {
6332  graphics_handle htext;
6333  if (i == 0)
6334  htext = get_title ();
6335  else if (i == 1)
6336  htext = get_xlabel ();
6337  else if (i == 2)
6338  htext = get_ylabel ();
6339  else if (i == 3)
6340  htext = get_zlabel ();
6341 
6342  text::properties& text_props
6343  = reinterpret_cast<text::properties&>
6345 
6346  Matrix text_pos = text_props.get_data_position ();
6347  text_pos = xform.transform (text_pos(0), text_pos(1), text_pos(2));
6348  if (text_props.get_string ().is_empty ())
6349  {
6350  ext(0) = std::min (ext(0), text_pos(0));
6351  ext(1) = std::min (ext(1), text_pos(1));
6352  ext(2) = std::max (ext(2), text_pos(0));
6353  ext(3) = std::max (ext(3), text_pos(1));
6354  }
6355  else
6356  {
6357  Matrix text_ext = text_props.get_extent_matrix ();
6358 
6359  bool ignore_horizontal = false;
6360  bool ignore_vertical = false;
6361  if (only_text_height)
6362  {
6363  double text_rotation = text_props.get_rotation ();
6364  if (text_rotation == 0. || text_rotation == 180.)
6365  ignore_horizontal = true;
6366  else if (text_rotation == 90. || text_rotation == 270.)
6367  ignore_vertical = true;
6368  }
6369 
6370  if (! ignore_horizontal)
6371  {
6372  ext(0) = std::min (ext(0), text_pos(0)+text_ext(0));
6373  ext(2) = std::max (ext(2),
6374  text_pos(0)+text_ext(0)+text_ext(2));
6375  }
6376 
6377  if (! ignore_vertical)
6378  {
6379  ext(1) = std::min (ext(1),
6380  text_pos(1)-text_ext(1)-text_ext(3));
6381  ext(3) = std::max (ext(3), text_pos(1)-text_ext(1));
6382  }
6383  }
6384  }
6385  }
6386 
6387  ext(2) = ext(2) - ext(0);
6388  ext(3) = ext(3) - ext(1);
6389 
6390  return ext;
6391 }
6392 
6393 static octave_value
6395 {
6397 
6398  if (val.is_cellstr ())
6399  {
6400  // Always return a column vector for Matlab compatibility
6401  if (val.columns () > 1)
6402  retval = val.reshape (dim_vector (val.numel (), 1));
6403  }
6404  else
6405  {
6406  string_vector sv;
6407  if (val.is_numeric_type ())
6408  {
6409  NDArray data = val.array_value ();
6410  std::ostringstream oss;
6411  oss.precision (5);
6412  for (octave_idx_type i = 0; i < val.numel (); i++)
6413  {
6414  oss.str ("");
6415  oss << data(i);
6416  sv.append (oss.str ());
6417  }
6418  }
6419  else if (val.is_string () && val.rows () == 1)
6420  {
6421  std::string valstr = val.string_value ();
6422  std::istringstream iss (valstr);
6423  std::string tmpstr;
6424 
6425  // Split string with delimiter '|'
6426  while (std::getline (iss, tmpstr, '|'))
6427  sv.append (tmpstr);
6428 
6429  // If string ends with '|' Matlab appends a null string
6430  if (*valstr.rbegin () == '|')
6431  sv.append (std::string (""));
6432  }
6433  else
6434  return retval;
6435 
6436  charMatrix chmat (sv, ' ');
6437 
6438  retval = octave_value (chmat);
6439  }
6440 
6441  return retval;
6442 }
6443 
6444 void
6446 {
6447  if (xticklabel.set (convert_ticklabel_string (val), false))
6448  {
6449  set_xticklabelmode ("manual");
6450  xticklabel.run_listeners (POSTSET);
6451  mark_modified ();
6452  }
6453  else
6454  set_xticklabelmode ("manual");
6455 
6456  sync_positions ();
6457 }
6458 
6459 void
6461 {
6462  if (yticklabel.set (convert_ticklabel_string (val), false))
6463  {
6464  set_yticklabelmode ("manual");
6465  yticklabel.run_listeners (POSTSET);
6466  mark_modified ();
6467  }
6468  else
6469  set_yticklabelmode ("manual");
6470 
6471  sync_positions ();
6472 }
6473 
6474 void
6476 {
6477  if (zticklabel.set (convert_ticklabel_string (val), false))
6478  {
6479  set_zticklabelmode ("manual");
6480  zticklabel.run_listeners (POSTSET);
6481  mark_modified ();
6482  }
6483  else
6484  set_zticklabelmode ("manual");
6485 
6486  sync_positions ();
6487 }
6488 
6489 // Almost identical to convert_ticklabel_string but it only accepts
6490 // cellstr or string, not numeric input.
6491 static octave_value
6493 {
6495 
6496  if (val.is_cellstr ())
6497  {
6498  // Always return a column vector for Matlab Compatibility
6499  if (val.columns () > 1)
6500  retval = val.reshape (dim_vector (val.numel (), 1));
6501  }
6502  else
6503  {
6504  string_vector sv;
6505  if (val.is_string () && val.rows () == 1)
6506  {
6507  std::string valstr = val.string_value ();
6508  std::istringstream iss (valstr);
6509  std::string tmpstr;
6510 
6511  // Split string with delimiter '|'
6512  while (std::getline (iss, tmpstr, '|'))
6513  sv.append (tmpstr);
6514 
6515  // If string ends with '|' Matlab appends a null string
6516  if (*valstr.rbegin () == '|')
6517  sv.append (std::string (""));
6518  }
6519  else
6520  return retval;
6521 
6522  charMatrix chmat (sv, ' ');
6523 
6524  retval = octave_value (chmat);
6525  }
6526 
6527  return retval;
6528 }
6529 
6530 void
6532 {
6533  linestyleorder.set (convert_linestyleorder_string (val), false);
6534 }
6535 
6536 void
6538 {
6539  caseless_str old_units = get_units ();
6540 
6541  if (units.set (val, true))
6542  {
6543  update_units (old_units);
6544  mark_modified ();
6545  }
6546 }
6547 
6548 void
6550 {
6552  Matrix parent_bb
6553  = parent_go.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
6554  caseless_str new_units = get_units ();
6555  position.set (octave_value (convert_position (get_position ().matrix_value (),
6556  old_units, new_units,
6557  parent_bb)),
6558  false);
6559  outerposition.set (octave_value (convert_position (get_outerposition ().matrix_value (),
6560  old_units, new_units,
6561  parent_bb)),
6562  false);
6563  tightinset.set (octave_value (convert_position (get_tightinset ().matrix_value (),
6564  old_units, new_units,
6565  parent_bb)),
6566  false);
6567  looseinset.set (octave_value (convert_position (get_looseinset ().matrix_value (),
6568  old_units, new_units,
6569  parent_bb)),
6570  false);
6571 }
6572 
6573 void
6575 {
6576  caseless_str old_fontunits = get_fontunits ();
6577 
6578  if (fontunits.set (val, true))
6579  {
6580  update_fontunits (old_fontunits);
6581  mark_modified ();
6582  }
6583 }
6584 
6585 void
6587 {
6588  caseless_str new_units = get_fontunits ();
6589  double parent_height = get_boundingbox (true).elem (3);
6590  double fontsz = get_fontsize ();
6591 
6592  fontsz = convert_font_size (fontsz, old_units, new_units, parent_height);
6593 
6594  set_fontsize (octave_value (fontsz));
6595 }
6596 
6597 double
6598 axes::properties::get_fontsize_points (double box_pix_height) const
6599 {
6600  double fontsz = get_fontsize ();
6601  double parent_height = box_pix_height;
6602 
6603  if (fontunits_is ("normalized") && parent_height <= 0)
6604  parent_height = get_boundingbox (true).elem (3);
6605 
6606  return convert_font_size (fontsz, get_fontunits (), "points", parent_height);
6607 }
6608 
6610 graphics_xform::xform_vector (double x, double y, double z)
6611 {
6612  return ::xform_vector (x, y, z);
6613 }
6614 
6615 Matrix
6617 {
6619 }
6620 
6622 graphics_xform::transform (double x, double y, double z, bool use_scale) const
6623 {
6624  if (use_scale)
6625  {
6626  x = sx.scale (x);
6627  y = sy.scale (y);
6628  z = sz.scale (z);
6629  }
6630 
6631  return ::transform (xform, x, y, z);
6632 }
6633 
6635 graphics_xform::untransform (double x, double y, double z,
6636  bool use_scale) const
6637 {
6638  ColumnVector v = ::transform (xform_inv, x, y, z);
6639 
6640  if (use_scale)
6641  {
6642  v(0) = sx.unscale (v(0));
6643  v(1) = sy.unscale (v(1));
6644  v(2) = sz.unscale (v(2));
6645  }
6646 
6647  return v;
6648 }
6649 
6652 {
6654 
6655  if (retval.is_undefined ())
6656  {
6657  graphics_handle parent_h = get_parent ();
6658  graphics_object parent_go = gh_manager::get_object (parent_h);
6659 
6660  retval = parent_go.get_default (pname);
6661  }
6662 
6663  return retval;
6664 }
6665 
6666 // FIXME: remove.
6667 // FIXME: maybe this should go into array_property class?
6668 /*
6669 static void
6670 check_limit_vals (double& min_val, double& max_val,
6671  double& min_pos, double& max_neg,
6672  const array_property& data)
6673 {
6674  double val = data.min_val ();
6675  if (octave::math::finite (val) && val < min_val)
6676  min_val = val;
6677  val = data.max_val ();
6678  if (octave::math::finite (val) && val > max_val)
6679  max_val = val;
6680  val = data.min_pos ();
6681  if (octave::math::finite (val) && val > 0 && val < min_pos)
6682  min_pos = val;
6683  val = data.max_neg ();
6684  if (octave::math::finite (val) && val < 0 && val > max_neg)
6685  max_neg = val;
6686 }
6687 */
6688 
6689 static void
6690 check_limit_vals (double& min_val, double& max_val,
6691  double& min_pos, double& max_neg,
6692  const octave_value& data)
6693 {
6694  if (data.is_matrix_type ())
6695  {
6696  Matrix m = data.matrix_value ();
6697 
6698  if (m.numel () == 4)
6699  {
6700  double val;
6701 
6702  val = m(0);
6703  if (octave::math::finite (val) && val < min_val)
6704  min_val = val;
6705 
6706  val = m(1);
6707  if (octave::math::finite (val) && val > max_val)
6708  max_val = val;
6709 
6710  val = m(2);
6711  if (octave::math::finite (val) && val > 0 && val < min_pos)
6712  min_pos = val;
6713 
6714  val = m(3);
6715  if (octave::math::finite (val) && val < 0 && val > max_neg)
6716  max_neg = val;
6717  }
6718  }
6719 }
6720 
6721 // magform(x) Returns (a, b),
6722 // where x = a * 10^b, abs (a) >= 1., and b is integer.
6723 
6724 static void
6725 magform (double x, double& a, int& b)
6726 {
6727  if (x == 0)
6728  {
6729  a = 0;
6730  b = 0;
6731  }
6732  else
6733  {
6734  b = static_cast<int> (std::floor (std::log10 (std::abs (x))));
6735  a = x / std::pow (10.0, b);
6736  }
6737 }
6738 
6739 // A translation from Tom Holoryd's python code at
6740 // http://kurage.nimh.nih.gov/tomh/tics.py
6741 // FIXME: add log ticks
6742 
6743 double
6744 axes::properties::calc_tick_sep (double lo, double hi)
6745 {
6746  int ticint = 5;
6747 
6748  // Reference: Lewart, C. R., "Algorithms SCALE1, SCALE2, and SCALE3 for
6749  // Determination of Scales on Computer Generated Plots", Communications of
6750  // the ACM, 10 (1973), 639-640.
6751  // Also cited as ACM Algorithm 463.
6752 
6753  double a;
6754  int b, x;
6755 
6756  magform ((hi - lo) / ticint, a, b);
6757 
6758  static const double sqrt_2 = sqrt (2.0);
6759  static const double sqrt_10 = sqrt (10.0);
6760  static const double sqrt_50 = sqrt (50.0);
6761 
6762  if (a < sqrt_2)
6763  x = 1;
6764  else if (a < sqrt_10)
6765  x = 2;
6766  else if (a < sqrt_50)
6767  x = 5;
6768  else
6769  x = 10;
6770 
6771  return x * std::pow (10., b);
6772 }
6773 
6774 // Attempt to make "nice" limits from the actual max and min of the data.
6775 // For log plots, we will also use the smallest strictly positive value.
6776 
6777 Matrix
6779  double min_pos, double max_neg,
6780  bool logscale)
6781 {
6782  Matrix retval;
6783 
6784  double min_val = xmin;
6785  double max_val = xmax;
6786 
6787  if (octave::math::isinf (min_val) && min_val > 0
6788  && octave::math::isinf (max_val) && max_val < 0)
6789  {
6790  retval = default_lim (logscale);
6791  return retval;
6792  }
6793  else if (! (octave::math::isinf (min_val) || octave::math::isinf (max_val)))
6794  {
6795  if (logscale)
6796  {
6797  if (octave::math::isinf (min_pos) && octave::math::isinf (max_neg))
6798  {
6799  // FIXME: max_neg is needed for "loglog ([0 -Inf])"
6800  // This is the *only* place where max_neg is needed.
6801  // Is there another way?
6802  retval = default_lim ();
6803  retval(0) = pow (10., retval(0));
6804  retval(1) = pow (10., retval(1));
6805  return retval;
6806  }
6807  if (min_val <= 0 && max_val > 0)
6808  {
6809  warning ("axis: omitting non-positive data in log plot");
6810  min_val = min_pos;
6811  }
6812  // FIXME: maybe this test should also be relative?
6813  if (std::abs (min_val - max_val)
6814  < sqrt (std::numeric_limits<double>::epsilon ()))
6815  {
6816  // Widen range when too small
6817  if (min_val >= 0)
6818  {
6819  min_val *= 0.9;
6820  max_val *= 1.1;
6821  }
6822  else
6823  {
6824  min_val *= 1.1;
6825  max_val *= 0.9;
6826  }
6827  }
6828  if (min_val > 0)
6829  {
6830  // Log plots with all positive data
6831  min_val = pow (10, std::floor (log10 (min_val)));
6832  max_val = pow (10, std::ceil (log10 (max_val)));
6833  }
6834  else
6835  {
6836  // Log plots with all negative data
6837  min_val = -pow (10, std::ceil (log10 (-min_val)));
6838  max_val = -pow (10, std::floor (log10 (-max_val)));
6839  }
6840  }
6841  else
6842  {
6843  if (min_val == 0 && max_val == 0)
6844  {
6845  min_val = -1;
6846  max_val = 1;
6847  }
6848  // FIXME: maybe this test should also be relative?
6849  else if (std::abs (min_val - max_val)
6850  < sqrt (std::numeric_limits<double>::epsilon ()))
6851  {
6852  min_val -= 0.1 * std::abs (min_val);
6853  max_val += 0.1 * std::abs (max_val);
6854  }
6855 
6856  double tick_sep = calc_tick_sep (min_val, max_val);
6857  double min_tick = std::floor (min_val / tick_sep);
6858  double max_tick = std::ceil (max_val / tick_sep);
6859  // Prevent round-off from cropping ticks
6860  min_val = std::min (min_val, tick_sep * min_tick);
6861  max_val = std::max (max_val, tick_sep * max_tick);
6862  }
6863  }
6864 
6865  retval.resize (1, 2);
6866 
6867  retval(0) = min_val;
6868  retval(1) = max_val;
6869 
6870  return retval;
6871 }
6872 
6873 void
6875  array_property& ticks,
6876  array_property& mticks,
6877  bool limmode_is_auto, bool is_logscale)
6878 {
6879  // FIXME: add log ticks and lims
6880 
6881  if (lims.get ().is_empty ())
6882  return;
6883 
6884  double lo = (lims.get ().matrix_value ())(0);
6885  double hi = (lims.get ().matrix_value ())(1);
6886  bool is_negative = lo < 0 && hi < 0;
6887 
6888  // FIXME: should this be checked for somewhere else? (i.e., set{x,y,z}lim)
6889  if (hi < lo)
6890  std::swap (hi, lo);
6891 
6892  if (is_logscale)
6893  {
6894  if (is_negative)
6895  {
6896  double tmp = hi;
6897  hi = std::log10 (-lo);
6898  lo = std::log10 (-tmp);
6899  }
6900  else
6901  {
6902  hi = std::log10 (hi);
6903  lo = std::log10 (lo);
6904  }
6905  }
6906 
6907  double tick_sep;
6908 
6909  if (is_logscale)
6910  {
6911  if (! (octave::math::isinf (hi) || octave::math::isinf (lo)))
6912  tick_sep = 1; // Tick is every order of magnitude (bug #39449)
6913  else
6914  tick_sep = 0;
6915  }
6916  else
6917  tick_sep = calc_tick_sep (lo, hi);
6918 
6919  double i1 = std::floor (lo / tick_sep);
6920  double i2 = std::ceil (hi / tick_sep);
6921 
6922  if (limmode_is_auto)
6923  {
6924  // Adjust limits to include min and max ticks
6925  Matrix tmp_lims (1,2);
6926  tmp_lims(0) = std::min (tick_sep * i1, lo);
6927  tmp_lims(1) = std::max (tick_sep * i2, hi);
6928 
6929  if (is_logscale)
6930  {
6931  tmp_lims(0) = std::pow (10., tmp_lims(0));
6932  tmp_lims(1) = std::pow (10., tmp_lims(1));
6933  if (tmp_lims(0) <= 0)
6934  tmp_lims(0) = std::pow (10., lo);
6935  if (is_negative)
6936  {
6937  double tmp = tmp_lims(0);
6938  tmp_lims(0) = -tmp_lims(1);
6939  tmp_lims(1) = -tmp;
6940  }
6941  }
6942  lims = tmp_lims;
6943  }
6944  else
6945  {
6946  // adjust min and max ticks to be within limits
6947  if (i1*tick_sep < lo)
6948  i1++;
6949  if (i2*tick_sep > hi && i2 > i1)
6950  i2--;
6951  }
6952 
6953  Matrix tmp_ticks (1, i2-i1+1);
6954  for (int i = 0; i <= static_cast<int> (i2-i1); i++)
6955  {
6956  tmp_ticks(i) = tick_sep * (i+i1);
6957  if (is_logscale)
6958  tmp_ticks(i) = std::pow (10., tmp_ticks(i));
6959  }
6960  if (is_logscale && is_negative)
6961  {
6962  Matrix rev_ticks (1, i2-i1+1);
6963  rev_ticks = -tmp_ticks;
6964  for (int i = 0; i <= static_cast<int> (i2-i1); i++)
6965  tmp_ticks(i) = rev_ticks(i2-i1-i);
6966  }
6967 
6968  ticks = tmp_ticks;
6969 
6970  int n = is_logscale ? 8 : 4;
6971  Matrix tmp_mticks (1, n * (tmp_ticks.numel () - 1));
6972 
6973  for (int i = 0; i < tmp_ticks.numel ()-1; i++)
6974  {
6975  double d = (tmp_ticks(i+1) - tmp_ticks(i)) / (n + 1);
6976  for (int j = 0; j < n; j++)
6977  {
6978  tmp_mticks(n*i+j) = tmp_ticks(i) + d * (j+1);
6979  }
6980  }
6981  mticks = tmp_mticks;
6982 }
6983 
6984 /*
6985 %!test <45356>
6986 %! hf = figure ("visible", "off");
6987 %! unwind_protect
6988 %! plot (1:10);
6989 %! xlim ([4.75, 8.5]);
6990 %! tics = get (gca, "xtick");
6991 %! assert (tics, [5 6 7 8]);
6992 %! unwind_protect_cleanup
6993 %! close (hf);
6994 %! end_unwind_protect
6995 */
6996 
6997 void
6999  any_property& labels, bool logscale)
7000 {
7001  Matrix values = ticks.get ().matrix_value ();
7002  Cell c (values.dims ());
7003  std::ostringstream os;
7004 
7005  if (logscale)
7006  {
7007  double significand;
7008  double exponent;
7009  double exp_max = 0.0;
7010  double exp_min = 0.0;
7011 
7012  for (int i = 0; i < values.numel (); i++)
7013  {
7014  double exp = std::log10 (values(i));
7015  exp_min = std::min (exp_min, exp);
7016  exp_max = std::max (exp_max, exp);
7017  }
7018 
7019  for (int i = 0; i < values.numel (); i++)
7020  {
7021  if (values(i) < 0.0)
7022  exponent = std::floor (std::log10 (-values(i)));
7023  else
7024  exponent = std::floor (std::log10 (values(i)));
7025  significand = values(i) * std::pow (10., -exponent);
7026 
7027  os.str ("");
7028  if ((std::abs (significand) - 1) >
7029  10*std::numeric_limits<double>::epsilon())
7030  os << significand << "x";
7031  else if (significand < 0)
7032  os << "-";
7033 
7034  os << "10^{";
7035 
7036  if (exponent < 0.0)
7037  {
7038  os << "-";
7039  exponent = -exponent;
7040  }
7041  if (exponent < 10. && (exp_max > 9 || exp_min < -9))
7042  os << "0";
7043  os << exponent << "}";
7044  c(i) = os.str ();
7045  }
7046  }
7047  else
7048  {
7049  for (int i = 0; i < values.numel (); i++)
7050  {
7051  os.str ("");
7052  os << values(i);
7053  c(i) = os.str ();
7054  }
7055  }
7056 
7057  labels = c;
7058 }
7059 
7060 Matrix
7062  const string_vector& ticklabels,
7063  const Matrix& limits)
7064 {
7065  Matrix ext (1, 2, 0.0);
7066  double wmax, hmax;
7067  wmax = hmax = 0.0;
7068  int n = std::min (ticklabels.numel (), ticks.numel ());
7069  for (int i = 0; i < n; i++)
7070  {
7071  double val = ticks(i);
7072  if (limits(0) <= val && val <= limits(1))
7073  {
7074  std::string label (ticklabels(i));
7075  label.erase (0, label.find_first_not_of (" "));
7076  label = label.substr (0, label.find_last_not_of (" ")+1);
7077 
7078  if (txt_renderer.ok ())
7079  {
7080  ext = txt_renderer.get_extent (label, 0.0,
7081  get_ticklabelinterpreter ());
7082 
7083  wmax = std::max (wmax, ext(0));
7084  hmax = std::max (hmax, ext(1));
7085  }
7086  else
7087  {
7088  // FIXME: find a better approximation
7089  double fsize = get ("fontsize").double_value ();
7090  int len = label.length ();
7091 
7092  wmax = std::max (wmax, 0.5*fsize*len);
7093  hmax = fsize;
7094  }
7095  }
7096  }
7097 
7098  ext(0) = wmax;
7099  ext(1) = hmax;
7100  return ext;
7101 }
7102 
7103 void
7104 get_children_limits (double& min_val, double& max_val,
7105  double& min_pos, double& max_neg,
7106  const Matrix& kids, char limit_type)
7107 {
7108  octave_idx_type n = kids.numel ();
7109 
7110  switch (limit_type)
7111  {
7112  case 'x':
7113  for (octave_idx_type i = 0; i < n; i++)
7114  {
7116 
7117  if (go.is_xliminclude ())
7118  {
7119  octave_value lim = go.get_xlim ();
7120 
7121  check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
7122  }
7123  }
7124  break;
7125 
7126  case 'y':
7127  for (octave_idx_type i = 0; i < n; i++)
7128  {
7130 
7131  if (go.is_yliminclude ())
7132  {
7133  octave_value lim = go.get_ylim ();
7134 
7135  check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
7136  }
7137  }
7138  break;
7139 
7140  case 'z':
7141  for (octave_idx_type i = 0; i < n; i++)
7142  {
7144 
7145  if (go.is_zliminclude ())
7146  {
7147  octave_value lim = go.get_zlim ();
7148 
7149  check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
7150  }
7151  }
7152  break;
7153 
7154  case 'c':
7155  for (octave_idx_type i = 0; i < n; i++)
7156  {
7158 
7159  if (go.is_climinclude ())
7160  {
7161  octave_value lim = go.get_clim ();
7162 
7163  check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
7164  }
7165  }
7166  break;
7167 
7168  case 'a':
7169  for (octave_idx_type i = 0; i < n; i++)
7170  {
7172 
7173  if (go.is_aliminclude ())
7174  {
7175  octave_value lim = go.get_alim ();
7176 
7177  check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
7178  }
7179  }
7180  break;
7181 
7182  default:
7183  break;
7184  }
7185 }
7186 
7187 static std::set<double> updating_axis_limits;
7188 
7189 void
7191  const graphics_handle& h)
7192 {
7193  if (updating_axis_limits.find (get_handle ().value ())
7194  != updating_axis_limits.end ())
7195  return;
7196 
7197  Matrix kids = Matrix (1, 1, h.value ());
7198 
7199  double min_val = octave::numeric_limits<double>::Inf ();
7200  double max_val = -octave::numeric_limits<double>::Inf ();
7201  double min_pos = octave::numeric_limits<double>::Inf ();
7202  double max_neg = -octave::numeric_limits<double>::Inf ();
7203 
7204  char update_type = 0;
7205 
7206  Matrix limits;
7207  double val;
7208 
7209 #define FIX_LIMITS \
7210  if (limits.numel () == 4) \
7211  { \
7212  val = limits(0); \
7213  if (octave::math::finite (val)) \
7214  min_val = val; \
7215  val = limits(1); \
7216  if (octave::math::finite (val)) \
7217  max_val = val; \
7218  val = limits(2); \
7219  if (octave::math::finite (val)) \
7220  min_pos = val; \
7221  val = limits(3); \
7222  if (octave::math::finite (val)) \
7223  max_neg = val; \
7224  } \
7225  else \
7226  { \
7227  limits.resize (4, 1); \
7228  limits(0) = min_val; \
7229  limits(1) = max_val; \
7230  limits(2) = min_pos; \
7231  limits(3) = max_neg; \
7232  }
7233 
7234  if (axis_type == "xdata" || axis_type == "xscale"
7235  || axis_type == "xlimmode" || axis_type == "xliminclude"
7236  || axis_type == "xlim")
7237  {
7238  if (xproperties.xlimmode_is ("auto"))
7239  {
7240  limits = xproperties.get_xlim ().matrix_value ();
7241  FIX_LIMITS;
7242 
7243  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x');
7244 
7245  limits = xproperties.get_axis_limits (min_val, max_val,
7246  min_pos, max_neg,
7247  xproperties.xscale_is ("log"));
7248 
7249  update_type = 'x';
7250  }
7251  }
7252  else if (axis_type == "ydata" || axis_type == "yscale"
7253  || axis_type == "ylimmode" || axis_type == "yliminclude"
7254  || axis_type == "ylim")
7255  {
7256  if (xproperties.ylimmode_is ("auto"))
7257  {
7258  limits = xproperties.get_ylim ().matrix_value ();
7259  FIX_LIMITS;
7260 
7261  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y');
7262 
7263  limits = xproperties.get_axis_limits (min_val, max_val,
7264  min_pos, max_neg,
7265  xproperties.yscale_is ("log"));
7266 
7267  update_type = 'y';
7268  }
7269  }
7270  else if (axis_type == "zdata" || axis_type == "zscale"
7271  || axis_type == "zlimmode" || axis_type == "zliminclude"
7272  || axis_type == "zlim")
7273  {
7274  if (xproperties.zlimmode_is ("auto"))
7275  {
7276  limits = xproperties.get_zlim ().matrix_value ();
7277  FIX_LIMITS;
7278 
7279  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z');
7280 
7281  limits = xproperties.get_axis_limits (min_val, max_val,
7282  min_pos, max_neg,
7283  xproperties.zscale_is ("log"));
7284 
7285  update_type = 'z';
7286  }
7287  }
7288  else if (axis_type == "cdata" || axis_type == "climmode"
7289  || axis_type == "cdatamapping" || axis_type == "climinclude"
7290  || axis_type == "clim")
7291  {
7292  if (xproperties.climmode_is ("auto"))
7293  {
7294  limits = xproperties.get_clim ().matrix_value ();
7295  FIX_LIMITS;
7296 
7297  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c');
7298 
7299  if (min_val > max_val)
7300  {
7301  min_val = min_pos = 0;
7302  max_val = 1;
7303  }
7304  else if (min_val == max_val)
7305  {
7306  max_val = min_val + 1;
7307  min_val -= 1;
7308  }
7309 
7310  limits.resize (1, 2);
7311 
7312  limits(0) = min_val;
7313  limits(1) = max_val;
7314 
7315  update_type = 'c';
7316  }
7317 
7318  }
7319  else if (axis_type == "alphadata" || axis_type == "alimmode"
7320  || axis_type == "alphadatamapping" || axis_type == "aliminclude"
7321  || axis_type == "alim")
7322  {
7323  if (xproperties.alimmode_is ("auto"))
7324  {
7325  limits = xproperties.get_alim ().matrix_value ();
7326  FIX_LIMITS;
7327 
7328  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a');
7329 
7330  if (min_val > max_val)
7331  {
7332  min_val = min_pos = 0;
7333  max_val = 1;
7334  }
7335  else if (min_val == max_val)
7336  max_val = min_val + 1;
7337 
7338  limits.resize (1, 2);
7339 
7340  limits(0) = min_val;
7341  limits(1) = max_val;
7342 
7343  update_type = 'a';
7344  }
7345 
7346  }
7347 
7348 #undef FIX_LIMITS
7349 
7351  frame.protect_var (updating_axis_limits);
7352 
7353  updating_axis_limits.insert (get_handle ().value ());
7354 
7355  switch (update_type)
7356  {
7357  case 'x':
7358  xproperties.set_xlim (limits);
7359  xproperties.set_xlimmode ("auto");
7360  xproperties.update_xlim ();
7361  break;
7362 
7363  case 'y':
7364  xproperties.set_ylim (limits);
7365  xproperties.set_ylimmode ("auto");
7366  xproperties.update_ylim ();
7367  break;
7368 
7369  case 'z':
7370  xproperties.set_zlim (limits);
7371  xproperties.set_zlimmode ("auto");
7372  xproperties.update_zlim ();
7373  break;
7374 
7375  case 'c':
7376  xproperties.set_clim (limits);
7377  xproperties.set_climmode ("auto");
7378  break;
7379 
7380  case 'a':
7381  xproperties.set_alim (limits);
7382  xproperties.set_alimmode ("auto");
7383  break;
7384 
7385  default:
7386  break;
7387  }
7388 
7389  xproperties.update_transform ();
7390 }
7391 
7392 void
7394 {
7395  if ((updating_axis_limits.find (get_handle ().value ())
7396  != updating_axis_limits.end ())
7397  || (updating_aspectratios.find (get_handle ().value ())
7398  != updating_aspectratios.end ()))
7399  return;
7400 
7401  Matrix kids = xproperties.get_children ();
7402 
7403  double min_val = octave::numeric_limits<double>::Inf ();
7404  double max_val = -octave::numeric_limits<double>::Inf ();
7405  double min_pos = octave::numeric_limits<double>::Inf ();
7406  double max_neg = -octave::numeric_limits<double>::Inf ();
7407 
7408  char update_type = 0;
7409 
7410  Matrix limits;
7411 
7412  if (axis_type == "xdata" || axis_type == "xscale"
7413  || axis_type == "xlimmode" || axis_type == "xliminclude"
7414  || axis_type == "xlim")
7415  {
7416  if (xproperties.xlimmode_is ("auto"))
7417  {
7418  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x');
7419 
7420  limits = xproperties.get_axis_limits (min_val, max_val,
7421  min_pos, max_neg,
7422  xproperties.xscale_is ("log"));
7423 
7424  update_type = 'x';
7425  }
7426  }
7427  else if (axis_type == "ydata" || axis_type == "yscale"
7428  || axis_type == "ylimmode" || axis_type == "yliminclude"
7429  || axis_type == "ylim")
7430  {
7431  if (xproperties.ylimmode_is ("auto"))
7432  {
7433  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y');
7434 
7435  limits = xproperties.get_axis_limits (min_val, max_val,
7436  min_pos, max_neg,
7437  xproperties.yscale_is ("log"));
7438 
7439  update_type = 'y';
7440  }
7441  }
7442  else if (axis_type == "zdata" || axis_type == "zscale"
7443  || axis_type == "zlimmode" || axis_type == "zliminclude"
7444  || axis_type == "zlim")
7445  {
7446  if (xproperties.zlimmode_is ("auto"))
7447  {
7448  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z');
7449 
7450  limits = xproperties.get_axis_limits (min_val, max_val,
7451  min_pos, max_neg,
7452  xproperties.zscale_is ("log"));
7453 
7454  update_type = 'z';
7455  }
7456  }
7457  else if (axis_type == "cdata" || axis_type == "climmode"
7458  || axis_type == "cdatamapping" || axis_type == "climinclude"
7459  || axis_type == "clim")
7460  {
7461  if (xproperties.climmode_is ("auto"))
7462  {
7463  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c');
7464 
7465  if (min_val > max_val)
7466  {
7467  min_val = min_pos = 0;
7468  max_val = 1;
7469  }
7470  else if (min_val == max_val)
7471  {
7472  max_val = min_val + 1;
7473  min_val -= 1;
7474  }
7475 
7476  limits.resize (1, 2);
7477 
7478  limits(0) = min_val;
7479  limits(1) = max_val;
7480 
7481  update_type = 'c';
7482  }
7483 
7484  }
7485  else if (axis_type == "alphadata" || axis_type == "alimmode"
7486  || axis_type == "alphadatamapping" || axis_type == "aliminclude"
7487  || axis_type == "alim")
7488  {
7489  if (xproperties.alimmode_is ("auto"))
7490  {
7491  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a');
7492 
7493  if (min_val > max_val)
7494  {
7495  min_val = min_pos = 0;
7496  max_val = 1;
7497  }
7498  else if (min_val == max_val)
7499  max_val = min_val + 1;
7500 
7501  limits.resize (1, 2);
7502 
7503  limits(0) = min_val;
7504  limits(1) = max_val;
7505 
7506  update_type = 'a';
7507  }
7508 
7509  }
7510 
7512  frame.protect_var (updating_axis_limits);
7513 
7514  updating_axis_limits.insert (get_handle ().value ());
7515 
7516  switch (update_type)
7517  {
7518  case 'x':
7519  xproperties.set_xlim (limits);
7520  xproperties.set_xlimmode ("auto");
7521  xproperties.update_xlim ();
7522  break;
7523 
7524  case 'y':
7525  xproperties.set_ylim (limits);
7526  xproperties.set_ylimmode ("auto");
7527  xproperties.update_ylim ();
7528  break;
7529 
7530  case 'z':
7531  xproperties.set_zlim (limits);
7532  xproperties.set_zlimmode ("auto");
7533  xproperties.update_zlim ();
7534  break;
7535 
7536  case 'c':
7537  xproperties.set_clim (limits);
7538  xproperties.set_climmode ("auto");
7539  break;
7540 
7541  case 'a':
7542  xproperties.set_alim (limits);
7543  xproperties.set_alimmode ("auto");
7544  break;
7545 
7546  default:
7547  break;
7548  }
7549 
7550  xproperties.update_transform ();
7551 }
7552 
7553 inline
7554 double force_in_range (double x, double lower, double upper)
7555 {
7556  if (x < lower)
7557  return lower;
7558  else if (x > upper)
7559  return upper;
7560  else
7561  return x;
7562 }
7563 
7564 static Matrix
7565 do_zoom (double val, double factor, const Matrix& lims, bool is_logscale)
7566 {
7567  Matrix new_lims = lims;
7568 
7569  double lo = lims(0);
7570  double hi = lims(1);
7571 
7572  bool is_negative = lo < 0 && hi < 0;
7573 
7574  if (is_logscale)
7575  {
7576  if (is_negative)
7577  {
7578  double tmp = hi;
7579  hi = std::log10 (-lo);
7580  lo = std::log10 (-tmp);
7581  val = std::log10 (-val);
7582  }
7583  else
7584  {
7585  hi = std::log10 (hi);
7586  lo = std::log10 (lo);
7587  val = std::log10 (val);
7588  }
7589  }
7590 
7591  // Perform the zooming
7592  lo = val + (lo - val) / factor;
7593  hi = val + (hi - val) / factor;
7594 
7595  if (is_logscale)
7596  {
7597  if (is_negative)
7598  {
7599  double tmp = -std::pow (10.0, hi);
7600  hi = -std::pow (10.0, lo);
7601  lo = tmp;
7602  }
7603  else
7604  {
7605  lo = std::pow (10.0, lo);
7606  hi = std::pow (10.0, hi);
7607  }
7608  }
7609 
7610  new_lims(0) = lo;
7611  new_lims(1) = hi;
7612 
7613  return new_lims;
7614 }
7615 
7616 void
7618  double x, double y, double factor,
7619  bool push_to_zoom_stack)
7620 {
7621  // FIXME: Do we need error checking here?
7622  Matrix xlims = get_xlim ().matrix_value ();
7623  Matrix ylims = get_ylim ().matrix_value ();
7624 
7625  // Get children axes limits
7626  Matrix kids = get_children ();
7627  double minx = octave::numeric_limits<double>::Inf ();
7628  double maxx = -octave::numeric_limits<double>::Inf ();
7629  double min_pos_x = octave::numeric_limits<double>::Inf ();
7630  double max_neg_x = -octave::numeric_limits<double>::Inf ();
7631  get_children_limits (minx, maxx, min_pos_x, max_neg_x, kids, 'x');
7632 
7633  double miny = octave::numeric_limits<double>::Inf ();
7634  double maxy = -octave::numeric_limits<double>::Inf ();
7635  double min_pos_y = octave::numeric_limits<double>::Inf ();
7636  double max_neg_y = -octave::numeric_limits<double>::Inf ();
7637  get_children_limits (miny, maxy, min_pos_y, max_neg_y, kids, 'y');
7638 
7639  xlims = do_zoom (x, factor, xlims, xscale_is ("log"));
7640  ylims = do_zoom (y, factor, ylims, yscale_is ("log"));
7641 
7642  zoom (mode, xlims, ylims, push_to_zoom_stack);
7643 }
7644 
7645 void
7646 axes::properties::zoom (const std::string& mode, double factor,
7647  bool push_to_zoom_stack)
7648 {
7649  // FIXME: Do we need error checking here?
7650  Matrix xlims = get_xlim ().matrix_value ();
7651  Matrix ylims = get_ylim ().matrix_value ();
7652 
7653  double x = (xlims(0) + xlims(1)) / 2;
7654  double y = (ylims(0) + ylims(1)) / 2;
7655 
7656  zoom_about_point (mode, x, y, factor, push_to_zoom_stack);
7657 }
7658 
7659 void
7661 {
7662  if (zoom_stack.empty ())
7663  {
7664  zoom_stack.push_front (xlimmode.get ());
7665  zoom_stack.push_front (xlim.get ());
7666  zoom_stack.push_front (ylimmode.get ());
7667  zoom_stack.push_front (ylim.get ());
7668  zoom_stack.push_front (zlimmode.get ());
7669  zoom_stack.push_front (zlim.get ());
7670  zoom_stack.push_front (view.get ());
7671  }
7672 }
7673 
7674 void
7676  const Matrix& xl, const Matrix& yl,
7677  bool push_to_zoom_stack)
7678 {
7679  if (push_to_zoom_stack)
7680  push_zoom_stack ();
7681 
7682  if (mode == "horizontal" || mode == "both")
7683  {
7684  xlim = xl;
7685  xlimmode = "manual";
7686  }
7687 
7688  if (mode == "vertical" || mode == "both")
7689  {
7690  ylim = yl;
7691  ylimmode = "manual";
7692  }
7693 
7694  update_transform ();
7695 
7696  if (mode == "horizontal" || mode == "both")
7697  update_xlim ();
7698 
7699  if (mode == "vertical" || mode == "both")
7700  update_ylim ();
7701 }
7702 
7703 static Matrix
7704 do_translate (double x0, double x1, const Matrix& lims, bool is_logscale)
7705 {
7706  Matrix new_lims = lims;
7707 
7708  double lo = lims(0);
7709  double hi = lims(1);
7710 
7711  bool is_negative = lo < 0 && hi < 0;
7712 
7713  double delta;
7714 
7715  if (is_logscale)
7716  {
7717  if (is_negative)
7718  {
7719  double tmp = hi;
7720  hi = std::log10 (-lo);
7721  lo = std::log10 (-tmp);
7722  x0 = -x0;
7723  x1 = -x1;
7724  }
7725  else
7726  {
7727  hi = std::log10 (hi);
7728  lo = std::log10 (lo);
7729  }
7730 
7731  delta = std::log10 (x0) - std::log10 (x1);
7732  }
7733  else
7734  {
7735  delta = x0 - x1;
7736  }
7737 
7738  // Perform the translation
7739  lo += delta;
7740  hi += delta;
7741 
7742  if (is_logscale)
7743  {
7744  if (is_negative)
7745  {
7746  double tmp = -std::pow (10.0, hi);
7747  hi = -std::pow (10.0, lo);
7748  lo = tmp;
7749  }
7750  else
7751  {
7752  lo = std::pow (10.0, lo);
7753  hi = std::pow (10.0, hi);
7754  }
7755  }
7756 
7757  new_lims(0) = lo;
7758  new_lims(1) = hi;
7759 
7760  return new_lims;
7761 }
7762 
7763 void
7765  double x0, double x1, double y0, double y1,
7766  bool push_to_zoom_stack)
7767 {
7768  // FIXME: Do we need error checking here?
7769  Matrix xlims = get_xlim ().matrix_value ();
7770  Matrix ylims = get_ylim ().matrix_value ();
7771 
7772  // Get children axes limits
7773  Matrix kids = get_children ();
7774  double minx = octave::numeric_limits<double>::Inf ();
7775  double maxx = -octave::numeric_limits<double>::Inf ();
7776  double min_pos_x = octave::numeric_limits<double>::Inf ();
7777  double max_neg_x = -octave::numeric_limits<double>::Inf ();
7778  get_children_limits (minx, maxx, min_pos_x, max_neg_x, kids, 'x');
7779 
7780  double miny = octave::numeric_limits<double>::Inf ();
7781  double maxy = -octave::numeric_limits<double>::Inf ();
7782  double min_pos_y = octave::numeric_limits<double>::Inf ();
7783  double max_neg_y = -octave::numeric_limits<double>::Inf ();
7784  get_children_limits (miny, maxy, min_pos_y, max_neg_y, kids, 'y');
7785 
7786  xlims = do_translate (x0, x1, xlims, xscale_is ("log"));
7787  ylims = do_translate (y0, y1, ylims, yscale_is ("log"));
7788 
7789  zoom (mode, xlims, ylims, push_to_zoom_stack);
7790 }
7791 
7792 void
7793 axes::properties::pan (const std::string& mode, double factor,
7794  bool push_to_zoom_stack)
7795 {
7796  // FIXME: Do we need error checking here?
7797  Matrix xlims = get_xlim ().matrix_value ();
7798  Matrix ylims = get_ylim ().matrix_value ();
7799 
7800  double x0 = (xlims(0) + xlims(1)) / 2;
7801  double y0 = (ylims(0) + ylims(1)) / 2;
7802 
7803  double x1 = x0 + (xlims(1) - xlims(0)) * factor;
7804  double y1 = y0 + (ylims(1) - ylims(0)) * factor;
7805 
7806  translate_view (mode, x0, x1, y0, y1, push_to_zoom_stack);
7807 }
7808 
7809 void
7810 axes::properties::rotate3d (double x0, double x1, double y0, double y1,
7811  bool push_to_zoom_stack)
7812 {
7813  if (push_to_zoom_stack)
7814  push_zoom_stack ();
7815 
7816  Matrix bb = get_boundingbox (true);
7817  Matrix new_view = get_view ().matrix_value ();
7818 
7819  // Compute new view angles
7820  new_view(0) += ((x0 - x1) * (180.0 / bb(2)));
7821  new_view(1) += ((y1 - y0) * (180.0 / bb(3)));
7822 
7823  // Clipping
7824  new_view(1) = std::min (new_view(1), 90.0);
7825  new_view(1) = std::max (new_view(1), -90.0);
7826  if (new_view(0) > 180.0)
7827  new_view(0) -= 360.0;
7828  else if (new_view(0) < -180.0)
7829  new_view(0) += 360.0;
7830 
7831  // Snapping
7832  double snapmargin = 1.0;
7833  for (int a = -90; a <= 90; a += 90)
7834  {
7835  if ((a - snapmargin) < new_view(1) && new_view(1) < (a + snapmargin))
7836  {
7837  new_view(1) = a;
7838  break;
7839  }
7840  }
7841 
7842  for (int a = -180; a <= 180; a += 180)
7843  if ((a - snapmargin) < new_view(0) && new_view(0) < (a + snapmargin))
7844  {
7845  if (a == 180)
7846  new_view(0) = -180;
7847  else
7848  new_view(0) = a;
7849  break;
7850  }
7851 
7852  // Update axes properties
7853  set_view (new_view);
7854 }
7855 
7856 void
7857 axes::properties::rotate_view (double delta_el, double delta_az,
7858  bool push_to_zoom_stack)
7859 {
7860  if (push_to_zoom_stack)
7861  push_zoom_stack ();
7862 
7863  Matrix v = get_view ().matrix_value ();
7864 
7865  v(1) += delta_el;
7866 
7867  if (v(1) > 90)
7868  v(1) = 90;
7869  if (v(1) < -90)
7870  v(1) = -90;
7871 
7872  v(0) = fmod (v(0) - delta_az + 720,360);
7873 
7874  set_view (v);
7875 
7876  update_transform ();
7877 }
7878 
7879 void
7881 {
7882  if (zoom_stack.size () >= 7)
7883  {
7884  view = zoom_stack.front ();
7885  zoom_stack.pop_front ();
7886 
7887  zlim = zoom_stack.front ();
7888  zoom_stack.pop_front ();
7889 
7890  zlimmode = zoom_stack.front ();
7891  zoom_stack.pop_front ();
7892 
7893  ylim = zoom_stack.front ();
7894  zoom_stack.pop_front ();
7895 
7896  ylimmode = zoom_stack.front ();
7897  zoom_stack.pop_front ();
7898 
7899  xlim = zoom_stack.front ();
7900  zoom_stack.pop_front ();
7901 
7902  xlimmode = zoom_stack.front ();
7903  zoom_stack.pop_front ();
7904 
7905  update_transform ();
7906 
7907  update_xlim ();
7908  update_ylim ();
7909  update_zlim ();
7910 
7911  update_view ();
7912  }
7913 }
7914 
7915 void
7917 {
7918  size_t items_to_leave_on_stack = do_unzoom ? 7 : 0;
7919 
7920  while (zoom_stack.size () > items_to_leave_on_stack)
7921  zoom_stack.pop_front ();
7922 
7923  if (do_unzoom)
7924  unzoom ();
7925 }
7926 
7927 void
7929 {
7930  // empty list of local defaults
7932 
7933  // reset factory defaults
7934  set_defaults ("reset");
7935 }
7936 
7937 void
7939 {
7941 
7943  xinitialize (xproperties.get_xlabel ());
7944  xinitialize (xproperties.get_ylabel ());
7945  xinitialize (xproperties.get_zlabel ());
7946 
7947  xproperties.sync_positions ();
7948 }
7949 
7950 // ---------------------------------------------------------------------
7951 
7952 Matrix
7954 {
7955  Matrix m (1, 4);
7956 
7957  m(0) = xdata.min_val ();
7958  m(1) = xdata.max_val ();
7959  m(2) = xdata.min_pos ();
7960  m(3) = xdata.max_neg ();
7961 
7962  return m;
7963 }
7964 
7965 Matrix
7967 {
7968  Matrix m (1, 4);
7969 
7970  m(0) = ydata.min_val ();
7971  m(1) = ydata.max_val ();
7972  m(2) = ydata.min_pos ();
7973  m(3) = ydata.max_neg ();
7974 
7975  return m;
7976 }
7977 
7978 // ---------------------------------------------------------------------
7979 
7980 Matrix
7982 {
7983  Matrix pos = get_position ().matrix_value ();
7984 
7985  if (! units_is ("data"))
7986  pos = convert_text_position (pos, *this, get_units (), "data");
7987 
7988  return pos;
7989 }
7990 
7991 Matrix
7993 {
7994  // FIXME: Should this function also add the (x,y) base position?
7995  return extent.get ().matrix_value ();
7996 }
7997 
8000 {
8001  // FIXME: This doesn't work right for 3D plots.
8002  // (It doesn't in Matlab either, at least not in version 6.5.)
8003  Matrix m = extent.get ().matrix_value ();
8004  Matrix pos = get_position ().matrix_value ();
8005  Matrix p = convert_text_position (pos, *this, get_units (), "pixels");
8006 
8007  m(0) += p(0);
8008  m(1) += p(1);
8009 
8010  return convert_text_position (m, *this, "pixels", get_units ());
8011 }
8012 
8013 void
8015 {
8016  caseless_str old_fontunits = get_fontunits ();
8017 
8018  if (fontunits.set (val, true))
8019  {
8020  update_fontunits (old_fontunits);
8021  mark_modified ();
8022  }
8023 }
8024 
8025 void
8027 {
8028  caseless_str new_units = get_fontunits ();
8029  double parent_height = 0;
8030  double fontsz = get_fontsize ();
8031 
8032  if (new_units == "normalized")
8033  {
8034  graphics_object go (gh_manager::get_object (get___myhandle__ ()));
8035  graphics_object ax (go.get_ancestor ("axes"));
8036 
8037  parent_height = ax.get_properties ().get_boundingbox (true).elem (3);
8038  }
8039 
8040  fontsz = convert_font_size (fontsz, old_units, new_units, parent_height);
8041 
8042  set_fontsize (octave_value (fontsz));
8043 }
8044 
8045 void
8047 {
8048  txt_renderer.set_font (get ("fontname").string_value (),
8049  get ("fontweight").string_value (),
8050  get ("fontangle").string_value (),
8051  get ("fontsize_points").double_value ());
8052 
8053  txt_renderer.set_color (get_color_rgb ());
8054 }
8055 
8056 void
8058 {
8059  int halign = 0;
8060  int valign = 0;
8061 
8062  if (horizontalalignment_is ("center"))
8063  halign = 1;
8064  else if (horizontalalignment_is ("right"))
8065  halign = 2;
8066 
8067  if (verticalalignment_is ("middle"))
8068  valign = 1;
8069  else if (verticalalignment_is ("top"))
8070  valign = 2;
8071  else if (verticalalignment_is ("baseline"))
8072  valign = 3;
8073  else if (verticalalignment_is ("cap"))
8074  valign = 4;
8075 
8076  Matrix bbox;
8077 
8078  // FIXME: string should be parsed only when modified, for efficiency
8079 
8080  octave_value string_prop = get_string ();
8081 
8082  string_vector sv = string_prop.string_vector_value ();
8083 
8084  txt_renderer.text_to_pixels (sv.join ("\n"), pixels, bbox,
8085  halign, valign, get_rotation (),
8086  get_interpreter ());
8087  // The bbox is relative to the text's position. We'll leave it that
8088  // way, because get_position does not return valid results when the
8089  // text is first constructed. Conversion to proper coordinates is
8090  // performed in get_extent.
8091  set_extent (bbox);
8092 
8093  if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel")
8094  || autopos_tag_is ("zlabel") || autopos_tag_is ("title"))
8095  update_autopos ("sync");
8096 }
8097 
8098 void
8100 {
8101  if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel")
8102  || autopos_tag_is ("zlabel") || autopos_tag_is ("title"))
8103  update_autopos (get_autopos_tag ());
8104 }
8105 
8106 void
8108 {
8109  if (! units_is ("data"))
8110  {
8111  set_xliminclude ("off");
8112  set_yliminclude ("off");
8113  set_zliminclude ("off");
8114  }
8115 
8116  Matrix pos = get_position ().matrix_value ();
8117 
8118  pos = convert_text_position (pos, *this, cached_units, get_units ());
8119 
8120  // FIXME: if the current axes view is 2D, then one should probably drop
8121  // the z-component of "pos" and leave "zliminclude" to "off".
8122 
8123  bool autopos = positionmode_is ("auto");
8124 
8125  set_position (pos);
8126 
8127  if (autopos)
8128  set_positionmode ("auto");
8129 
8130  if (units_is ("data"))
8131  {
8132  set_xliminclude ("on");
8133  set_yliminclude ("on");
8134  // FIXME: see above
8135  set_zliminclude ("off");
8136  }
8137 
8138  cached_units = get_units ();
8139 }
8140 
8141 double
8142 text::properties::get_fontsize_points (double box_pix_height) const
8143 {
8144  double fontsz = get_fontsize ();
8145  double parent_height = box_pix_height;
8146 
8147  if (fontunits_is ("normalized") && parent_height <= 0)
8148  {
8149  graphics_object go (gh_manager::get_object (get___myhandle__ ()));
8150  graphics_object ax (go.get_ancestor ("axes"));
8151 
8152  parent_height = ax.get_properties ().get_boundingbox (true).elem (3);
8153  }
8154 
8155  return convert_font_size (fontsz, get_fontunits (), "points", parent_height);
8156 }
8157 
8158 // ---------------------------------------------------------------------
8159 
8162 {
8163  return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
8164 }
8165 
8166 // ---------------------------------------------------------------------
8167 
8170 {
8171  octave_value fvc = get_facevertexcdata ();
8172  if (fvc.is_undefined () || fvc.is_empty ())
8173  return Matrix ();
8174  else
8175  return convert_cdata (*this, fvc, cdatamapping_is ("scaled"), 2);
8176 }
8177 
8178 static bool updating_patch_data = false;
8179 
8180 void
8182 {
8183  if (updating_patch_data)
8184  return;
8185 
8186  Matrix xd = get_xdata ().matrix_value ();
8187  Matrix yd = get_ydata ().matrix_value ();
8188  Matrix zd = get_zdata ().matrix_value ();
8189  NDArray cd = get_cdata ().array_value ();
8190 
8191  bad_data_msg = "";
8192  if (xd.dims () != yd.dims ()
8193  || (xd.dims () != zd.dims () && ! zd.is_empty ()))
8194  {
8195  bad_data_msg = "x/y/zdata must have the same dimensions";
8196  return;
8197  }
8198 
8199  // Faces and Vertices
8200  dim_vector dv;
8201  bool is3D = false;
8202  octave_idx_type nr = xd.rows ();
8203  octave_idx_type nc = xd.columns ();
8204  if (nr == 1 && nc > 1)
8205  {
8206  nr = nc;
8207  nc = 1;
8208  xd = xd.as_column ();
8209  yd = yd.as_column ();
8210  zd = zd.as_column ();
8211  }
8212 
8213  dv(0) = nr * nc;
8214  if (zd.is_empty ())
8215  dv(1) = 2;
8216  else
8217  {
8218  dv(1) = 3;
8219  is3D = true;
8220  }
8221 
8222  Matrix vert (dv);
8223  Matrix idx (nc, nr);
8224 
8225  octave_idx_type kk = 0;
8226  for (octave_idx_type jj = 0; jj < nc; jj++)
8227  {
8228  for (octave_idx_type ii = 0; ii < nr; ii++)
8229  {
8230  vert(kk,0) = xd(ii,jj);
8231  vert(kk,1) = yd(ii,jj);
8232  if (is3D)
8233  vert(kk,2) = zd(ii,jj);
8234 
8235  idx(jj,ii) = static_cast<double> (kk+1);
8236 
8237  kk++;
8238  }
8239  }
8240 
8241  // facevertexcdata
8242  Matrix fvc;
8243  if (cd.ndims () == 3)
8244  {
8245  dv(0) = cd.rows () * cd.columns ();
8246  dv(1) = cd.dims ()(2);
8247  fvc = cd.reshape (dv);
8248  }
8249  else
8250  fvc = cd.as_column ();
8251 
8252  // FIXME: shouldn't we update facevertexalphadata here ?
8253 
8255  frame.protect_var (updating_patch_data);
8256  updating_patch_data = true;
8257 
8258  faces.set (idx);
8259  vertices.set (vert);
8260  facevertexcdata.set (fvc);
8261 }
8262 
8263 void
8265 {
8266  if (updating_patch_data)
8267  return;
8268 
8269  Matrix idx = get_faces ().matrix_value ().transpose ();
8270  Matrix vert = get_vertices ().matrix_value ();
8271  NDArray fvc = get_facevertexcdata ().array_value ();
8272 
8273  octave_idx_type nfaces = idx.columns ();
8274  octave_idx_type nvert = vert.rows ();
8275 
8276  // Check all vertices in faces are defined
8277  bad_data_msg = "";
8278  if (static_cast<double> (nvert) < idx.row_max ().max ())
8279  {
8280  bad_data_msg = "some vertices in \"faces\" property are undefined";
8281  return;
8282  }
8283 
8284  // Replace NaNs
8285  if (idx.any_element_is_inf_or_nan ())
8286  {
8287  for (octave_idx_type jj = 0; jj < idx.columns (); jj++)
8288  {
8289  double valid_vert = idx(0,jj);
8290  bool turn_valid = false;
8291  for (octave_idx_type ii = 0; ii < idx.rows (); ii++)
8292  {
8293  if (octave::math::isnan (idx(ii,jj)) || turn_valid)
8294  {
8295  idx(ii,jj) = valid_vert;
8296  turn_valid = true;
8297  }
8298  else
8299  valid_vert = idx(ii,jj);
8300  }
8301  }
8302  }
8303 
8304  // Build cdata
8306  NDArray cd;
8307  bool pervertex = false;
8308 
8309  if (fvc.rows () == nfaces || fvc.rows () == 1)
8310  {
8311  dv(0) = 1;
8312  dv(1) = fvc.rows ();
8313  dv(2) = fvc.columns ();
8314  cd = fvc.reshape (dv);
8315  }
8316  else
8317  {
8318  if (! fvc.is_empty ())
8319  {
8320  dv(0) = idx.rows ();
8321  dv(1) = nfaces;
8322  dv(2) = fvc.columns ();
8323  cd.resize (dv);
8324  pervertex = true;
8325  }
8326  }
8327 
8328  // Build x,y,zdata and eventually per vertex cdata
8329  Matrix xd (idx.dims ());
8330  Matrix yd (idx.dims ());
8331  Matrix zd;
8332  bool has_zd = false;
8333  if (vert.columns () > 2)
8334  {
8335  zd = Matrix (idx.dims ());
8336  has_zd = true;
8337  }
8338 
8339  for (octave_idx_type jj = 0; jj < nfaces; jj++)
8340  {
8341  for (octave_idx_type ii = 0; ii < idx.rows (); ii++)
8342  {
8343  octave_idx_type row = static_cast<octave_idx_type> (idx(ii,jj)-1);
8344  xd(ii,jj) = vert(row,0);
8345  yd(ii,jj) = vert(row,1);
8346 
8347  if (has_zd)
8348  zd(ii,jj) = vert(row,2);
8349 
8350  if (pervertex)
8351  for (int kk = 0; kk < fvc.columns (); kk++)
8352  cd(ii,jj,kk) = fvc(row,kk);
8353  }
8354  }
8355 
8357  frame.protect_var (updating_patch_data);
8358  updating_patch_data = true;
8359 
8360  set_xdata (xd);
8361  set_ydata (yd);
8362  set_zdata (zd);
8363  set_cdata (cd);
8364 }
8365 
8366 // ---------------------------------------------------------------------
8367 
8370 {
8371  return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
8372 }
8373 
8374 inline void
8375 cross_product (double x1, double y1, double z1,
8376  double x2, double y2, double z2,
8377  double& x, double& y, double& z)
8378 {
8379  x += (y1 * z2 - z1 * y2);
8380  y += (z1 * x2 - x1 * z2);
8381  z += (x1 * y2 - y1 * x2);
8382 }
8383 
8384 void
8386 {
8387  if (vertexnormalsmode_is ("auto"))
8388  {
8389  Matrix x = get_xdata ().matrix_value ();
8390  Matrix y = get_ydata ().matrix_value ();
8391  Matrix z = get_zdata ().matrix_value ();
8392 
8393  int p = z.columns ();
8394  int q = z.rows ();
8395 
8396  // FIXME: There might be a cleaner way to do this. When data is changed
8397  // the update_xdata, update_ydata, update_zdata routines are called in a
8398  // serial fashion. Until the final call to update_zdata the matrices
8399  // will be of mismatched dimensions which can cause an out-of-bound
8400  // indexing in the code below. This one-liner prevents calculating
8401  // normals until dimensions match.
8402  if (x.columns () != p || y.rows () != q)
8403  return;
8404 
8405  NDArray n (dim_vector (q, p, 3), 0.0);
8406 
8407  bool x_mat = (x.rows () == q);
8408  bool y_mat = (y.columns () == p);
8409 
8410  int i1, i2, i3, j1, j2, j3;
8411  i1 = i2 = i3 = 0;
8412  j1 = j2 = j3 = 0;
8413 
8414  for (int i = 0; i < p; i++)
8415  {
8416  if (y_mat)
8417  {
8418  i1 = i - 1;
8419  i2 = i;
8420  i3 = i + 1;
8421  }
8422 
8423  for (int j = 0; j < q; j++)
8424  {
8425  if (x_mat)
8426  {
8427  j1 = j - 1;
8428  j2 = j;
8429  j3 = j + 1;
8430  }
8431 
8432  double& nx = n(j, i, 0);
8433  double& ny = n(j, i, 1);
8434  double& nz = n(j, i, 2);
8435 
8436  if ((j > 0) && (i > 0))
8437  // upper left quadrangle
8439  (x(j1,i-1)-x(j2,i), y(j-1,i1)-y(j,i2), z(j-1,i-1)-z(j,i),
8440  x(j2,i-1)-x(j1,i), y(j,i1)-y(j-1,i2), z(j,i-1)-z(j-1,i),
8441  nx, ny, nz);
8442 
8443  if ((j > 0) && (i < (p -1)))
8444  // upper right quadrangle
8446  (x(j1,i+1)-x(j2,i), y(j-1,i3)-y(j,i2), z(j-1,i+1)-z(j,i),
8447  x(j1,i)-x(j2,i+1), y(j-1,i2)-y(j,i3), z(j-1,i)-z(j,i+1),
8448  nx, ny, nz);
8449 
8450  if ((j < (q - 1)) && (i > 0))
8451  // lower left quadrangle
8453  (x(j2,i-1)-x(j3,i), y(j,i1)-y(j+1,i2), z(j,i-1)-z(j+1,i),
8454  x(j3,i-1)-x(j2,i), y(j+1,i1)-y(j,i2), z(j+1,i-1)-z(j,i),
8455  nx, ny, nz);
8456 
8457  if ((j < (q - 1)) && (i < (p -1)))
8458  // lower right quadrangle
8460  (x(j3,i)-x(j2,i+1), y(j+1,i2)-y(j,i3), z(j+1,i)-z(j,i+1),
8461  x(j3,i+1)-x(j2,i), y(j+1,i3)-y(j,i2), z(j+1,i+1)-z(j,i),
8462  nx, ny, nz);
8463 
8464  double d = -std::max (std::max (fabs (nx), fabs (ny)), fabs (nz));
8465 
8466  nx /= d;
8467  ny /= d;
8468  nz /= d;
8469  }
8470  }
8471  vertexnormals = n;
8472  }
8473 }
8474 
8475 // ---------------------------------------------------------------------
8476 
8477 void
8479 {
8480  graphics_object go = gh_manager::get_object (__myhandle__);
8481 
8482  if (go)
8483  {
8484  go.update_axis_limits ("xlim");
8485  go.update_axis_limits ("ylim");
8486  go.update_axis_limits ("zlim");
8487  go.update_axis_limits ("clim");
8488  go.update_axis_limits ("alim");
8489  }
8490 }
8491 
8492 void
8494 {
8495  graphics_object go = gh_manager::get_object (__myhandle__);
8496 
8497  if (go)
8498  {
8499  go.update_axis_limits ("xlim", h);
8500  go.update_axis_limits ("ylim", h);
8501  go.update_axis_limits ("zlim", h);
8502  go.update_axis_limits ("clim", h);
8503  go.update_axis_limits ("alim", h);
8504  }
8505 }
8506 
8507 static bool updating_hggroup_limits = false;
8508 
8509 void
8511  const graphics_handle& h)
8512 {
8513  if (updating_hggroup_limits)
8514  return;
8515 
8516  Matrix kids = Matrix (1, 1, h.value ());
8517 
8518  double min_val = octave::numeric_limits<double>::Inf ();
8519  double max_val = -octave::numeric_limits<double>::Inf ();
8520  double min_pos = octave::numeric_limits<double>::Inf ();
8521  double max_neg = -octave::numeric_limits<double>::Inf ();
8522 
8523  Matrix limits;
8524  double val;
8525 
8526  char update_type = 0;
8527 
8528  if (axis_type == "xlim" || axis_type == "xliminclude")
8529  {
8530  limits = xproperties.get_xlim ().matrix_value ();
8531  update_type = 'x';
8532  }
8533  else if (axis_type == "ylim" || axis_type == "yliminclude")
8534  {
8535  limits = xproperties.get_ylim ().matrix_value ();
8536  update_type = 'y';
8537  }
8538  else if (axis_type == "zlim" || axis_type == "zliminclude")
8539  {
8540  limits = xproperties.get_zlim ().matrix_value ();
8541  update_type = 'z';
8542  }
8543  else if (axis_type == "clim" || axis_type == "climinclude")
8544  {
8545  limits = xproperties.get_clim ().matrix_value ();
8546  update_type = 'c';
8547  }
8548  else if (axis_type == "alim" || axis_type == "aliminclude")
8549  {
8550  limits = xproperties.get_alim ().matrix_value ();
8551  update_type = 'a';
8552  }
8553 
8554  if (limits.numel () == 4)
8555  {
8556  val = limits(0);
8557  if (octave::math::finite (val))
8558  min_val = val;
8559  val = limits(1);
8560  if (octave::math::finite (val))
8561  max_val = val;
8562  val = limits(2);
8563  if (octave::math::finite (val))
8564  min_pos = val;
8565  val = limits(3);
8566  if (octave::math::finite (val))
8567  max_neg = val;
8568  }
8569  else
8570  {
8571  limits.resize (4, 1);
8572  limits(0) = min_val;
8573  limits(1) = max_val;
8574  limits(2) = min_pos;
8575  limits(3) = max_neg;
8576  }
8577 
8578  get_children_limits (min_val, max_val, min_pos, max_neg, kids, update_type);
8579 
8581  frame.protect_var (updating_hggroup_limits);
8582 
8583  updating_hggroup_limits = true;
8584 
8585  if (limits(0) != min_val || limits(1) != max_val
8586  || limits(2) != min_pos || limits(3) != max_neg)
8587  {
8588  limits(0) = min_val;
8589  limits(1) = max_val;
8590  limits(2) = min_pos;
8591  limits(3) = max_neg;
8592 
8593  switch (update_type)
8594  {
8595  case 'x':
8596  xproperties.set_xlim (limits);
8597  break;
8598 
8599  case 'y':
8600  xproperties.set_ylim (limits);
8601  break;
8602 
8603  case 'z':
8604  xproperties.set_zlim (limits);
8605  break;
8606 
8607  case 'c':
8608  xproperties.set_clim (limits);
8609  break;
8610 
8611  case 'a':
8612  xproperties.set_alim (limits);
8613  break;
8614 
8615  default:
8616  break;
8617  }
8618 
8620  }
8621 }
8622 
8623 void
8625 {
8626  if (updating_hggroup_limits)
8627  return;
8628 
8629  Matrix kids = xproperties.get_children ();
8630 
8631  double min_val = octave::numeric_limits<double>::Inf ();
8632  double max_val = -octave::numeric_limits<double>::Inf ();
8633  double min_pos = octave::numeric_limits<double>::Inf ();
8634  double max_neg = -octave::numeric_limits<double>::Inf ();
8635 
8636  char update_type = 0;
8637 
8638  if (axis_type == "xlim" || axis_type == "xliminclude")
8639  {
8640  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x');
8641 
8642  update_type = 'x';
8643  }
8644  else if (axis_type == "ylim" || axis_type == "yliminclude")
8645  {
8646  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y');
8647 
8648  update_type = 'y';
8649  }
8650  else if (axis_type == "zlim" || axis_type == "zliminclude")
8651  {
8652  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z');
8653 
8654  update_type = 'z';
8655  }
8656  else if (axis_type == "clim" || axis_type == "climinclude")
8657  {
8658  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c');
8659 
8660  update_type = 'c';
8661  }
8662  else if (axis_type == "alim" || axis_type == "aliminclude")
8663  {
8664  get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a');
8665 
8666  update_type = 'a';
8667  }
8668 
8670  frame.protect_var (updating_hggroup_limits);
8671 
8672  updating_hggroup_limits = true;
8673 
8674  Matrix limits (1, 4, 0.0);
8675 
8676  limits(0) = min_val;
8677  limits(1) = max_val;
8678  limits(2) = min_pos;
8679  limits(3) = max_neg;
8680 
8681  switch (update_type)
8682  {
8683  case 'x':
8684  xproperties.set_xlim (limits);
8685  break;
8686 
8687  case 'y':
8688  xproperties.set_ylim (limits);
8689  break;
8690 
8691  case 'z':
8692  xproperties.set_zlim (limits);
8693  break;
8694 
8695  case 'c':
8696  xproperties.set_clim (limits);
8697  break;
8698 
8699  case 'a':
8700  xproperties.set_alim (limits);
8701  break;
8702 
8703  default:
8704  break;
8705  }
8706 
8708 }
8709 
8710 // ---------------------------------------------------------------------
8711 
8713 {
8714  std::list<graphics_handle> lst = xproperties.get_dependent_obj_list ();
8715  std::list<graphics_handle>::const_iterator it;
8716 
8717  for (it = lst.begin (); it != lst.end (); it++)
8718  {
8720 
8721  if (go.valid_object () &&
8722  go.get ("uicontextmenu") == xproperties.get___myhandle__ ())
8723  go.set ("uicontextmenu", Matrix ());
8724  }
8725 }
8726 
8727 /*
8728 ## Test deletion/reset of uicontextmenu
8729 %!test
8730 %! hf = figure ("visible", "off");
8731 %! hax = axes ("parent", hf);
8732 %! unwind_protect
8733 %! hctx1 = uicontextmenu ("parent", hf);
8734 %! hctx2 = uicontextmenu ("parent", hf);
8735 %! set (hf, "uicontextmenu", hctx2);
8736 %! set (hax, "uicontextmenu", hctx2);
8737 %! assert (get (hf, "uicontextmenu"), hctx2);
8738 %! assert (get (hax, "uicontextmenu"), hctx2);
8739 %! assert (get (hf, "children"), [hctx2; hctx1; hax]);
8740 %! delete (hctx2);
8741 %! assert (get (hf, "uicontextmenu"), []);
8742 %! assert (get (hax, "uicontextmenu"), []);
8743 %! assert (get (hf, "children"), [hctx1; hax]);
8744 %! set (hf, "uicontextmenu", hctx1);
8745 %! assert (get (hf, "uicontextmenu"), hctx1);
8746 %! set (hf, "uicontextmenu", []);
8747 %! assert (get (hf, "uicontextmenu"), []);
8748 %! assert (get (hf, "children"), [hctx1; hax]);
8749 %! unwind_protect_cleanup
8750 %! close (hf);
8751 %! end_unwind_protect;
8752 */
8753 
8754 // ---------------------------------------------------------------------
8755 
8758 {
8759  Matrix m = extent.get ().matrix_value ();
8760 
8762  Matrix parent_bbox = parent_go.get_properties ().get_boundingbox (true);
8763  Matrix parent_size = parent_bbox.extract_n (0, 2, 1, 2);
8764 
8765  return convert_position (m, "pixels", get_units (), parent_size);
8766 }
8767 
8768 void
8770 {
8771  text_element *elt;
8772  octave::text_renderer txt_renderer;
8773  Matrix box;
8774 
8775  // FIXME: parsed content should be cached for efficiency
8776  // FIXME: support multiline text
8777 
8778  elt = text_parser::parse (get_string_string (), "none");
8779 
8780  txt_renderer.set_font (get_fontname (), get_fontweight (),
8781  get_fontangle (), get_fontsize ());
8782 
8783  box = txt_renderer.get_extent (elt, 0);
8784 
8785  delete elt;
8786 
8787  Matrix ext (1, 4);
8788 
8789  // FIXME: also handle left and bottom components
8790 
8791  ext(0) = ext(1) = 1;
8792  ext(2) = box(0);
8793  ext(3) = box(1);
8794 
8795  set_extent (ext);
8796 }
8797 
8798 void
8800 {
8801  Matrix pos = get_position ().matrix_value ();
8802 
8804  Matrix parent_bbox = parent_go.get_properties ().get_boundingbox (true);
8805  Matrix parent_size = parent_bbox.extract_n (0, 2, 1, 2);
8806 
8807  pos = convert_position (pos, cached_units, get_units (), parent_size);
8808  set_position (pos);
8809 
8810  cached_units = get_units ();
8811 }
8812 
8813 void
8815 {
8816  if (! get___object__ ().is_empty ())
8817  error ("set: cannot change the style of a uicontrol object after creation.");
8818 
8819  style = st;
8820 
8821  // if we know know what we are, can override value for listbox and popupmenu
8822  if (style_is ("listbox") || style_is ("popupmenu"))
8823  {
8824  Matrix v = value.get ().matrix_value ();
8825  if(v.numel () == 1 && v (0) == 0)
8826  value.set (octave_value (1));
8827  }
8828 }
8829 
8830 Matrix
8832  const Matrix& parent_pix_size) const
8833 {
8834  Matrix pos = get_position ().matrix_value ();
8835  Matrix parent_size (parent_pix_size);
8836 
8837  if (parent_size.is_empty ())
8838  {
8840 
8841  if (go.valid_object ())
8842  parent_size =
8843  go.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
8844  else
8845  parent_size = default_figure_position ();
8846  }
8847 
8848  pos = convert_position (pos, get_units (), "pixels", parent_size);
8849 
8850  pos(0)--;
8851  pos(1)--;
8852  pos(1) = parent_size(1) - pos(1) - pos(3);
8853 
8854  return pos;
8855 }
8856 
8857 void
8859 {
8860  caseless_str old_fontunits = get_fontunits ();
8861 
8862  if (fontunits.set (val, true))
8863  {
8864  update_fontunits (old_fontunits);
8865  mark_modified ();
8866  }
8867 }
8868 
8869 void
8871 {
8872  caseless_str new_units = get_fontunits ();
8873  double parent_height = get_boundingbox (false).elem (3);
8874  double fontsz = get_fontsize ();
8875 
8876  fontsz = convert_font_size (fontsz, old_units, new_units, parent_height);
8877 
8878  fontsize.set (octave_value (fontsz), true);
8879 }
8880 
8881 double
8882 uicontrol::properties::get_fontsize_points (double box_pix_height) const
8883 {
8884  double fontsz = get_fontsize ();
8885  double parent_height = box_pix_height;
8886 
8887  if (fontunits_is ("normalized") && parent_height <= 0)
8888  parent_height = get_boundingbox (false).elem (3);
8889 
8890  return convert_font_size (fontsz, get_fontunits (), "points", parent_height);
8891 }
8892 
8893 // ---------------------------------------------------------------------
8894 
8895 Matrix
8897  const Matrix& parent_pix_size) const
8898 {
8899  Matrix pos = get_position ().matrix_value ();
8900  Matrix parent_size (parent_pix_size);
8901 
8902  if (parent_size.is_empty ())
8903  {
8905 
8906  parent_size =
8907  go.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
8908  }
8909 
8910  pos = convert_position (pos, get_units (), "pixels", parent_size);
8911 
8912  pos(0)--;
8913  pos(1)--;
8914  pos(1) = parent_size(1) - pos(1) - pos(3);
8915 
8916  if (internal)
8917  {
8918  double outer_height = pos(3);
8919 
8920  pos(0) = pos(1) = 0;
8921 
8922  if (! bordertype_is ("none"))
8923  {
8924  double bw = get_borderwidth ();
8925  double mul = 1.0;
8926 
8927  if (bordertype_is ("etchedin") || bordertype_is ("etchedout"))
8928  mul = 2.0;
8929 
8930  pos(0) += mul * bw;
8931  pos(1) += mul * bw;
8932  pos(2) -= 2 * mul * bw;
8933  pos(3) -= 2 * mul * bw;
8934  }
8935 
8936  if (! get_title ().empty ())
8937  {
8938  double fontsz = get_fontsize ();
8939 
8940  if (! fontunits_is ("pixels"))
8941  {
8942  double res = xget (0, "screenpixelsperinch").double_value ();
8943 
8944  if (fontunits_is ("points"))
8945  fontsz *= (res / 72.0);
8946  else if (fontunits_is ("inches"))
8947  fontsz *= res;
8948  else if (fontunits_is ("centimeters"))
8949  fontsz *= (res / 2.54);
8950  else if (fontunits_is ("normalized"))
8951  fontsz *= outer_height;
8952  }
8953 
8954  if (titleposition_is ("lefttop") || titleposition_is ("centertop")
8955  || titleposition_is ("righttop"))
8956  pos(1) += (fontsz / 2);
8957  pos(3) -= (fontsz / 2);
8958  }
8959  }
8960 
8961  return pos;
8962 }
8963 
8964 void
8966 {
8967  caseless_str old_units = get_units ();
8968 
8969  if (units.set (val, true))
8970  {
8971  update_units (old_units);
8972  mark_modified ();
8973  }
8974 }
8975 
8976 void
8978 {
8979  Matrix pos = get_position ().matrix_value ();
8980 
8982  Matrix parent_bbox = parent_go.get_properties ().get_boundingbox (true);
8983  Matrix parent_size = parent_bbox.extract_n (0, 2, 1, 2);
8984 
8985  pos = convert_position (pos, old_units, get_units (), parent_size);
8986  set_position (pos);
8987 }
8988 
8989 void
8991 {
8992  caseless_str old_fontunits = get_fontunits ();
8993 
8994  if (fontunits.set (val, true))
8995  {
8996  update_fontunits (old_fontunits);
8997  mark_modified ();
8998  }
8999 }
9000 
9001 void
9003 {
9004  caseless_str new_units = get_fontunits ();
9005  double parent_height = get_boundingbox (false).elem (3);
9006  double fontsz = get_fontsize ();
9007 
9008  fontsz = convert_font_size (fontsz, old_units, new_units, parent_height);
9009 
9010  set_fontsize (octave_value (fontsz));
9011 }
9012 
9013 double
9015 {
9016  double fontsz = get_fontsize ();
9017  double parent_height = box_pix_height;
9018 
9019  if (fontunits_is ("normalized") && parent_height <= 0)
9020  parent_height = get_boundingbox (false).elem (3);
9021 
9022  return convert_font_size (fontsz, get_fontunits (), "points", parent_height);
9023 }
9024 
9025 void
9027 {
9028  graphics_handle current_selectedobject = get_selectedobject();
9029  selectedobject = current_selectedobject;
9030  if (v.is_empty ())
9031  {
9032  if (current_selectedobject.ok ())
9033  {
9034  selectedobject = graphics_handle ();
9035  mark_modified ();
9036  }
9037  return;
9038  }
9039 
9040  graphics_handle val (v);
9041  if (val.ok ())
9042  {
9044  base_properties& gop = go.get_properties ();
9045 
9046  if (go.valid_object ()
9047  && gop.get_parent () == get___myhandle__ ()
9048  && go.isa ("uicontrol"))
9049  {
9051  = dynamic_cast<uicontrol::properties&> (go.get_properties ());
9052  const caseless_str& style = cop.get_style ();
9053  if (style.compare ("radiobutton") || style.compare ("togglebutton"))
9054  {
9055  selectedobject = val;
9056  mark_modified ();
9057  return;
9058  }
9059  }
9060  }
9061  err_set_invalid ("selectedobject");
9062 }
9063 
9064 // ---------------------------------------------------------------------
9065 
9066 Matrix
9068  const Matrix& parent_pix_size) const
9069 {
9070  Matrix pos = get_position ().matrix_value ();
9071  Matrix parent_size (parent_pix_size);
9072 
9073  if (parent_size.is_empty ())
9074  {
9076 
9077  parent_size =
9078  go.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
9079  }
9080 
9081  pos = convert_position (pos, get_units (), "pixels", parent_size);
9082 
9083  pos(0)--;
9084  pos(1)--;
9085  pos(1) = parent_size(1) - pos(1) - pos(3);
9086 
9087  if (internal)
9088  {
9089  double outer_height = pos(3);
9090 
9091  pos(0) = pos(1) = 0;
9092 
9093  if (! bordertype_is ("none"))
9094  {
9095  double bw = get_borderwidth ();
9096  double mul = 1.0;
9097 
9098  if (bordertype_is ("etchedin") || bordertype_is ("etchedout"))
9099  mul = 2.0;
9100 
9101  pos(0) += mul * bw;
9102  pos(1) += mul * bw;
9103  pos(2) -= 2 * mul * bw;
9104  pos(3) -= 2 * mul * bw;
9105  }
9106 
9107  if (! get_title ().empty ())
9108  {
9109  double fontsz = get_fontsize ();
9110 
9111  if (! fontunits_is ("pixels"))
9112  {
9113  double res = xget (0, "screenpixelsperinch").double_value ();
9114 
9115  if (fontunits_is ("points"))
9116  fontsz *= (res / 72.0);
9117  else if (fontunits_is ("inches"))
9118  fontsz *= res;
9119  else if (fontunits_is ("centimeters"))
9120  fontsz *= (res / 2.54);
9121  else if (fontunits_is ("normalized"))
9122  fontsz *= outer_height;
9123  }
9124 
9125  if (titleposition_is ("lefttop") || titleposition_is ("centertop")
9126  || titleposition_is ("righttop"))
9127  pos(1) += (fontsz / 2);
9128  pos(3) -= (fontsz / 2);
9129  }
9130  }
9131 
9132  return pos;
9133 }
9134 
9135 void
9137 {
9138  caseless_str old_units = get_units ();
9139 
9140  if (units.set (val, true))
9141  {
9142  update_units (old_units);
9143  mark_modified ();
9144  }
9145 }
9146 
9147 void
9149 {
9150  Matrix pos = get_position ().matrix_value ();
9151 
9153  Matrix parent_bbox = parent_go.get_properties ().get_boundingbox (true);
9154  Matrix parent_size = parent_bbox.extract_n (0, 2, 1, 2);
9155 
9156  pos = convert_position (pos, old_units, get_units (), parent_size);
9157  set_position (pos);
9158 }
9159 
9160 void
9162 {
9163  caseless_str old_fontunits = get_fontunits ();
9164 
9165  if (fontunits.set (val, true))
9166  {
9167  update_fontunits (old_fontunits);
9168  mark_modified ();
9169  }
9170 }
9171 
9172 void
9174 {
9175  caseless_str new_units = get_fontunits ();
9176  double parent_height = get_boundingbox (false).elem (3);
9177  double fontsz = get_fontsize ();
9178 
9179  fontsz = convert_font_size (fontsz, old_units, new_units, parent_height);
9180 
9181  set_fontsize (octave_value (fontsz));
9182 }
9183 
9184 double
9185 uipanel::properties::get_fontsize_points (double box_pix_height) const
9186 {
9187  double fontsz = get_fontsize ();
9188  double parent_height = box_pix_height;
9189 
9190  if (fontunits_is ("normalized") && parent_height <= 0)
9191  parent_height = get_boundingbox (false).elem (3);
9192 
9193  return convert_font_size (fontsz, get_fontunits (), "points", parent_height);
9194 }
9195 
9196 // ---------------------------------------------------------------------
9197 
9200 {
9202 
9203  if (retval.is_undefined ())
9204  {
9205  graphics_handle parent_h = get_parent ();
9206  graphics_object parent_go = gh_manager::get_object (parent_h);
9207 
9208  retval = parent_go.get_default (pname);
9209  }
9210 
9211  return retval;
9212 }
9213 
9214 void
9216 {
9217  // empty list of local defaults
9219 
9221 }
9222 
9223 // ---------------------------------------------------------------------
9224 
9227 {
9228  graphics_handle parent_h = get_parent ();
9229  graphics_object parent_go = gh_manager::get_object (parent_h);
9230 
9231  return parent_go.get_default (type () + pname);
9232 }
9233 
9236 {
9237  graphics_object parent_go = gh_manager::get_object (0);
9238 
9239  return parent_go.get_factory_default (type () + name);
9240 }
9241 
9242 // We use a random value for the handle to avoid issues with plots and
9243 // scalar values for the first argument.
9245  : handle_map (), handle_free_list (),
9246  next_handle (-1.0 - (rand () + 1.0) / (RAND_MAX + 2.0)),
9247  figure_list (), graphics_lock (), event_queue (),
9248  callback_objects (), event_processing (0)
9249 {
9250  handle_map[0] = graphics_object (new root_figure ());
9251 
9252  // Make sure the default graphics toolkit is registered.
9254 }
9255 
9256 void
9258 {
9259  instance = new gh_manager ();
9260 
9261  if (instance)
9263 }
9264 
9267  const graphics_handle& p,
9268  bool integer_figure_handle,
9269  bool do_createfcn,
9270  bool do_notify_toolkit)
9271 {
9272  graphics_handle h = get_handle (integer_figure_handle);
9273 
9274  base_graphics_object *bgo = 0;
9275 
9276  bgo = make_graphics_object_from_type (go_name, h, p);
9277 
9278  if (! bgo)
9279  error ("gh_manager::do_make_graphics_handle: invalid object type '%s'",
9280  go_name.c_str ());
9281 
9282  graphics_object go (bgo);
9283 
9284  handle_map[h] = go;
9285 
9286  // Overriding defaults will work now because the handle is valid
9287  // and we can find parent objects (not just handles).
9288  go.override_defaults ();
9289 
9290  if (go_name == "axes")
9291  {
9292  // Handle defaults for labels since overriding defaults for
9293  // them can't work before the axes object is fully
9294  // constructed.
9295 
9296  axes::properties& props =
9297  dynamic_cast<axes::properties&> (go.get_properties ());
9298 
9299  graphics_object tgo;
9300 
9301  tgo = gh_manager::get_object (props.get_xlabel ());
9302  tgo.override_defaults ();
9303 
9304  tgo = gh_manager::get_object (props.get_ylabel ());
9305  tgo.override_defaults ();
9306 
9307  tgo = gh_manager::get_object (props.get_zlabel ());
9308  tgo.override_defaults ();
9309 
9310  tgo = gh_manager::get_object (props.get_title ());
9311  tgo.override_defaults ();
9312  }
9313 
9314  if (do_createfcn)
9315  bgo->get_properties ().execute_createfcn ();
9316 
9317  // Notify graphics toolkit.
9318  if (do_notify_toolkit)
9319  go.initialize ();
9320 
9321  return h;
9322 }
9323 
9325 gh_manager::do_make_figure_handle (double val, bool do_notify_toolkit)
9326 {
9327  graphics_handle h = val;
9328 
9329  base_graphics_object* bgo = new figure (h, 0);
9330  graphics_object go (bgo);
9331 
9332  handle_map[h] = go;
9333 
9334  // Notify graphics toolkit.
9335  if (do_notify_toolkit)
9336  go.initialize ();
9337 
9338  go.override_defaults ();
9339 
9340  return h;
9341 }
9342 
9343 void
9345 {
9346  do_pop_figure (h);
9347 
9348  figure_list.push_front (h);
9349 }
9350 
9351 void
9353 {
9354  for (auto it = figure_list.begin (); it != figure_list.end (); it++)
9355  {
9356  if (*it == h)
9357  {
9358  figure_list.erase (it);
9359  break;
9360  }
9361  }
9362 }
9363 
9364 class
9366 {
9367 public:
9369  const octave_value& data = Matrix ())
9370  : base_graphics_event (), handle (h), callback_name (name),
9371  callback (), callback_data (data) { }
9372 
9374  const octave_value& data = Matrix ())
9375  : base_graphics_event (), handle (h), callback_name (),
9376  callback (cb), callback_data (data) { }
9377 
9378  void execute (void)
9379  {
9380  if (callback.is_defined ())
9381  gh_manager::execute_callback (handle, callback, callback_data);
9382  else
9383  gh_manager::execute_callback (handle, callback_name, callback_data);
9384  }
9385 
9386 private:
9388  : base_graphics_event (), handle (), callback_name (), callback_data ()
9389  { }
9390 
9391 private:
9396 };
9397 
9398 class
9400 {
9401 public:
9403  : base_graphics_event (), function (fcn), function_data (data)
9404  { }
9405 
9406  void execute (void)
9407  {
9408  function (function_data);
9409  }
9410 
9411 private:
9412 
9414 
9416 
9417  // function_event objects must be created with at least a function.
9418  function_event (void);
9419 
9420  // No copying!
9421 
9422  function_event (const function_event&);
9423 
9424  function_event & operator = (const function_event&);
9425 };
9426 
9427 class
9429 {
9430 public:
9431  set_event (const graphics_handle& h, const std::string& name,
9432  const octave_value& value, bool do_notify_toolkit = true)
9433  : base_graphics_event (), handle (h), property_name (name),
9434  property_value (value), notify_toolkit (do_notify_toolkit) { }
9435 
9436  void execute (void)
9437  {
9438  gh_manager::auto_lock guard;
9439 
9441 
9442  if (go)
9443  {
9444  property p = go.get_properties ().get_property (property_name);
9445 
9446  if (p.ok ())
9447  p.set (property_value, true, notify_toolkit);
9448  }
9449  }
9450 
9451 private:
9452  set_event (void)
9453  : base_graphics_event (), handle (), property_name (), property_value ()
9454  { }
9455 
9456 private:
9461 };
9462 
9465  const std::string& name,
9466  const octave_value& data)
9467 {
9468  graphics_event e;
9469 
9470  e.rep = new callback_event (h, name, data);
9471 
9472  return e;
9473 }
9474 
9477  const octave_value& cb,
9478  const octave_value& data)
9479 {
9480  graphics_event e;
9481 
9482  e.rep = new callback_event (h, cb, data);
9483 
9484  return e;
9485 }
9486 
9489  void *data)
9490 {
9491  graphics_event e;
9492 
9493  e.rep = new function_event (fcn, data);
9494 
9495  return e;
9496 }
9497 
9500  const std::string& name,
9501  const octave_value& data,
9502  bool notify_toolkit)
9503 {
9504  graphics_event e;
9505 
9506  e.rep = new set_event (h, name, data, notify_toolkit);
9507 
9508  return e;
9509 }
9510 
9511 static void
9513 {
9515  root_figure::properties& props =
9516  dynamic_cast<root_figure::properties&> (go.get_properties ());
9517 
9518  props.set_callbackobject (h.as_octave_value ());
9519 }
9520 
9521 void
9523 {
9524  gh_manager::auto_lock guard;
9525 
9526  callback_objects.pop_front ();
9527 
9528  xset_gcbo (callback_objects.empty ()
9529  ? graphics_handle () : callback_objects.front ().get_handle ());
9530 }
9531 
9532 void
9534  const octave_value& l)
9535 {
9538  else
9539  {
9540  gh_manager::auto_lock guard;
9541 
9543  }
9544 }
9545 
9546 void
9548  const octave_value& cb_arg,
9549  const octave_value& data)
9550 {
9551  if (cb_arg.is_defined () && ! cb_arg.is_empty ())
9552  {
9554  octave_function *fcn = 0;
9555 
9556  args(0) = h.as_octave_value ();
9557  if (data.is_defined ())
9558  args(1) = data;
9559  else
9560  args(1) = Matrix ();
9561 
9564 
9565  if (true)
9566  {
9567  gh_manager::auto_lock guard;
9568 
9569  callback_objects.push_front (get_object (h));
9570  xset_gcbo (h);
9571  }
9572 
9573  // Copy CB because "function_value" method is non-const.
9574 
9575  octave_value cb = cb_arg;
9576 
9577  if (cb.is_function () || cb.is_function_handle ())
9578  fcn = cb.function_value ();
9579  else if (cb.is_string ())
9580  {
9581  int status;
9582  std::string s = cb.string_value ();
9583 
9584  try
9585  {
9586  eval_string (s, false, status, 0);
9587  }
9588  catch (octave::execution_exception&)
9589  {
9590  std::cerr << "execution error in graphics callback function"
9591  << std::endl;
9592  feval ("lasterr",
9593  ovl ("execution error in graphics callback function"));
9595  }
9596  }
9597  else if (cb.is_cell () && cb.length () > 0
9598  && (cb.rows () == 1 || cb.columns () == 1)
9599  && (cb.cell_value ()(0).is_function ()
9600  || cb.cell_value ()(0).is_function_handle ()))
9601  {
9602  Cell c = cb.cell_value ();
9603 
9604  fcn = c(0).function_value ();
9605 
9606  for (int i = 1; i < c.numel () ; i++)
9607  args(1+i) = c(i);
9608  }
9609  else
9610  {
9611  std::string nm = cb.class_name ();
9612  error ("trying to execute non-executable object (class = %s)",
9613  nm.c_str ());
9614  }
9615 
9616  if (fcn)
9617  try
9618  {
9619  feval (fcn, args);
9620  }
9621  catch (octave::execution_exception&)
9622  {
9623  std::cerr << "execution error in graphics callback function"
9624  << std::endl;
9625  feval ("lasterr",
9626  ovl ("execution error in graphics callback function"));
9628  }
9629 
9630  // Redraw after interacting with a user-interface (ui*) object.
9631  if (Vdrawnow_requested)
9632  {
9633  graphics_object go = get_object (h);
9634 
9635  if (go)
9636  {
9637  std::string go_name = go.get_properties ()
9639 
9640  if (go_name.length () > 1
9641  && go_name[0] == 'u' && go_name[1] == 'i')
9642  {
9643  Fdrawnow ();
9644  Vdrawnow_requested = false;
9645  }
9646  }
9647  }
9648  }
9649 }
9650 
9651 void
9653 {
9654  event_queue.push_back (e);
9655 
9657 }
9658 
9659 void
9661  const octave_value& data)
9662 {
9663  gh_manager::auto_lock guard;
9664 
9665  graphics_object go = get_object (h);
9666 
9667  if (go.valid_object ())
9668  {
9669  if (callback_objects.empty ())
9671  else
9672  {
9673  const graphics_object& current = callback_objects.front ();
9674 
9675  if (current.get_properties ().is_interruptible ())
9677  data));
9678  else
9679  {
9680  std::string busy_action (go.get_properties ().get_busyaction ());
9681 
9682  if (busy_action == "queue")
9684  data));
9685  else
9686  {
9687  caseless_str cname (name);
9688 
9689  if (cname.compare ("deletefcn")
9690  || cname.compare ("createfcn")
9691  || (go.isa ("figure")
9692  && (cname.compare ("closerequestfcn")
9693  || cname.compare ("resizefcn"))))
9694  do_post_event (
9695  graphics_event::create_callback_event (h, name, data));
9696  }
9697  }
9698  }
9699  }
9700 }
9701 
9702 void
9704 {
9705  gh_manager::auto_lock guard;
9706 
9708 }
9709 
9710 void
9712  const octave_value& value, bool notify_toolkit)
9713 {
9714  gh_manager::auto_lock guard;
9715 
9717  notify_toolkit));
9718 }
9719 
9720 int
9722 {
9723  graphics_event e;
9724  bool old_Vdrawnow_requested = Vdrawnow_requested;
9725  bool events_executed = false;
9726 
9727  do
9728  {
9729  e = graphics_event ();
9730 
9731  {
9732  gh_manager::auto_lock guard;
9733 
9734  if (! event_queue.empty ())
9735  {
9736  if (callback_objects.empty () || force)
9737  {
9738  e = event_queue.front ();
9739 
9740  event_queue.pop_front ();
9741  }
9742  else
9743  {
9744  const graphics_object& go = callback_objects.front ();
9745 
9746  if (go.get_properties ().is_interruptible ())
9747  {
9748  e = event_queue.front ();
9749 
9750  event_queue.pop_front ();
9751  }
9752  }
9753  }
9754  }
9755 
9756  if (e.ok ())
9757  {
9758  e.execute ();
9759  events_executed = true;
9760  }
9761  }
9762  while (e.ok ());
9763 
9764  {
9765  gh_manager::auto_lock guard;
9766 
9767  if (event_queue.empty () && event_processing == 0)
9769  }
9770 
9771  if (events_executed)
9773 
9774  if (Vdrawnow_requested && ! old_Vdrawnow_requested)
9775  {
9776  Fdrawnow ();
9777 
9778  Vdrawnow_requested = false;
9779  }
9780 
9781  return 0;
9782 }
9783 
9784 void
9786 {
9787  gh_manager::auto_lock guard;
9788 
9789  if (enable)
9790  {
9791  event_processing++;
9792 
9794  }
9795  else
9796  {
9797  event_processing--;
9798 
9799  if (event_queue.empty () && event_processing == 0)
9801  }
9802 }
9803 
9806 {
9808 
9809  plist_map["figure"] = figure::properties::factory_defaults ();
9810  plist_map["axes"] = axes::properties::factory_defaults ();
9811  plist_map["line"] = line::properties::factory_defaults ();
9812  plist_map["text"] = text::properties::factory_defaults ();
9813  plist_map["image"] = image::properties::factory_defaults ();
9814  plist_map["patch"] = patch::properties::factory_defaults ();
9815  plist_map["surface"] = surface::properties::factory_defaults ();
9816  plist_map["light"] = light::properties::factory_defaults ();
9817  plist_map["hggroup"] = hggroup::properties::factory_defaults ();
9818  plist_map["uimenu"] = uimenu::properties::factory_defaults ();
9819  plist_map["uicontrol"] = uicontrol::properties::factory_defaults ();
9820  plist_map["uibuttongroup"] = uibuttongroup::properties::factory_defaults ();
9821  plist_map["uipanel"] = uipanel::properties::factory_defaults ();
9822  plist_map["uicontextmenu"] = uicontextmenu::properties::factory_defaults ();
9823  plist_map["uitoolbar"] = uitoolbar::properties::factory_defaults ();
9824  plist_map["uipushtool"] = uipushtool::properties::factory_defaults ();
9825  plist_map["uitoggletool"] = uitoggletool::properties::factory_defaults ();
9826 
9827  return plist_map;
9828 }
9829 
9830 // ---------------------------------------------------------------------
9831 
9832 DEFUN (ishandle, args, ,
9833  doc: /* -*- texinfo -*-
9834 @deftypefn {} {} ishandle (@var{h})
9835 Return true if @var{h} is a graphics handle and false otherwise.
9836 
9837 @var{h} may also be a matrix of handles in which case a logical array is
9838 returned that is true where the elements of @var{h} are graphics handles and
9839 false where they are not.
9840 @seealso{isaxes, isfigure}
9841 @end deftypefn */)
9842 {
9843  gh_manager::auto_lock guard;
9844 
9845  if (args.length () != 1)
9846  print_usage ();
9847 
9848  return ovl (is_handle (args(0)));
9849 }
9850 
9851 static bool
9853 {
9854  return h.ok () && gh_manager::is_handle_visible (h);
9855 }
9856 
9857 static bool
9859 {
9860  return is_handle_visible (gh_manager::lookup (val));
9861 }
9862 
9863 static octave_value
9865 {
9866  octave_value retval = false;
9867 
9868  if (val.is_real_scalar () && is_handle_visible (val.double_value ()))
9869  retval = true;
9870  else if (val.is_numeric_type () && val.is_real_type ())
9871  {
9872  const NDArray handles = val.array_value ();
9873 
9874  boolNDArray result (handles.dims ());
9875 
9876  for (octave_idx_type i = 0; i < handles.numel (); i++)
9877  result.xelem (i) = is_handle_visible (handles(i));
9878 
9879  retval = result;
9880  }
9881 
9882  return retval;
9883 }
9884 
9885 DEFUN (__is_handle_visible__, args, ,
9886  doc: /* -*- texinfo -*-
9887 @deftypefn {} {} __is_handle_visible__ (@var{h})
9888 Undocumented internal function.
9889 @end deftypefn */)
9890 {
9891  if (args.length () != 1)
9892  print_usage ();
9893 
9894  return ovl (is_handle_visible (args(0)));
9895 }
9896 
9897 DEFUN (reset, args, ,
9898  doc: /* -*- texinfo -*-
9899 @deftypefn {} {} reset (@var{h})
9900 Reset the properties of the graphic object @var{h} to their default values.
9901 
9902 For figures, the properties @qcode{"position"}, @qcode{"units"},
9903 @qcode{"windowstyle"}, and @qcode{"paperunits"} are not affected.
9904 For axes, the properties @qcode{"position"} and @qcode{"units"} are
9905 not affected.
9906 
9907 The input @var{h} may also be a vector of graphic handles in which case
9908 each individual object will be reset.
9909 @seealso{cla, clf, newplot}
9910 @end deftypefn */)
9911 {
9912  if (args.length () != 1)
9913  print_usage ();
9914 
9915  // get vector of graphics handles
9916  ColumnVector hcv = args(0).xvector_value ("reset: H must be a graphics handle");
9917 
9918  // loop over graphics objects
9919  for (octave_idx_type n = 0; n < hcv.numel (); n++)
9920  gh_manager::get_object (hcv(n)).reset_default_properties ();
9921 
9922  Fdrawnow ();
9923 
9924  return ovl ();
9925 }
9926 
9927 /*
9928 
9929 %!test # line object
9930 %! hf = figure ("visible", "off");
9931 %! unwind_protect
9932 %! tol = 20 * eps;
9933 %! hax = axes ("defaultlinelinewidth", 3);
9934 %!
9935 %! hli = line (1:10, 1:10, 1:10, "marker", "o",
9936 %! "markerfacecolor", "b", "linestyle", ":");
9937 %!
9938 %! reset (hli);
9939 %! assert (get (hli, "marker"), get (0, "defaultlinemarker"));
9940 %! assert (get (hli, "markerfacecolor"),
9941 %! get (0, "defaultlinemarkerfacecolor"));
9942 %! assert (get (hli, "linestyle"), get (0, "defaultlinelinestyle"));
9943 %! assert (get (hli, "linewidth"), 3, tol); # parent axes defaults
9944 %!
9945 %! unwind_protect_cleanup
9946 %! close (hf);
9947 %! end_unwind_protect
9948 
9949 %!test # patch object
9950 %! hf = figure ("visible", "off");
9951 %! unwind_protect
9952 %! tol = 20 * eps;
9953 %! t1 = (1/16:1/8:1)' * 2*pi;
9954 %! t2 = ((1/16:1/16:1)' + 1/32) * 2*pi;
9955 %! x1 = sin (t1) - 0.8;
9956 %! y1 = cos (t1);
9957 %! x2 = sin (t2) + 0.8;
9958 %! y2 = cos (t2);
9959 %! vert = [x1, y1; x2, y2];
9960 %! fac = [1:8,NaN(1,8);9:24];
9961 %! hpa = patch ("Faces",fac, "Vertices",vert, "FaceColor","r");
9962 %!
9963 %! reset (hpa);
9964 %! assert (get (hpa, "faces"), get (0, "defaultpatchfaces"), tol);
9965 %! assert (get (hpa, "vertices"), get (0, "defaultpatchvertices"), tol);
9966 %! assert (get (hpa, "facevertexcdata"),
9967 %! get (0, "defaultpatchfacevertexcdata"), tol);
9968 %! unwind_protect_cleanup
9969 %! close (hf);
9970 %! end_unwind_protect
9971 
9972 %!test # surface object
9973 %! hf = figure ("visible", "off");
9974 %! unwind_protect
9975 %! tol = 20 * eps;
9976 %! hsu = surface (peaks, "edgecolor", "none");
9977 %!
9978 %! reset (hsu);
9979 %! assert (get (hsu, "xdata"), get (0, "defaultsurfacexdata"), tol);
9980 %! assert (get (hsu, "ydata"), get (0, "defaultsurfaceydata"), tol);
9981 %! assert (get (hsu, "zdata"), get (0, "defaultsurfacezdata"), tol);
9982 %! assert (get (hsu, "edgecolor"), get (0, "defaultsurfaceedgecolor"), tol);
9983 %! unwind_protect_cleanup
9984 %! close (hf);
9985 %! end_unwind_protect
9986 
9987 %!test # image object
9988 %! hf = figure ("visible", "off");
9989 %! unwind_protect
9990 %! tol = 20 * eps;
9991 %! him = image (rand (10,10), "cdatamapping", "scaled");
9992 %!
9993 %! reset (him);
9994 %! assert (get (him, "cdata"), get (0, "defaultimagecdata"), tol);
9995 %! assert (get (him, "cdatamapping"),
9996 %! get (0, "defaultimagecdatamapping"), tol);
9997 %! unwind_protect_cleanup
9998 %! close (hf);
9999 %! end_unwind_protect
10000 
10001 %!test # text object
10002 %! hf = figure ("visible", "off");
10003 %! unwind_protect
10004 %! tol = 20 * eps;
10005 %! hte = text (5, 5, "Hi!", "fontsize", 20 ,"color", "r");
10006 %!
10007 %! reset (hte);
10008 %! assert (get (hte, "position"), get (0, "defaulttextposition"), tol);
10009 %! assert (get (hte, "fontsize"), get (0, "defaulttextfontsize"), tol);
10010 %! assert (get (hte, "color"), get (0, "defaulttextcolor"), tol);
10011 %! unwind_protect_cleanup
10012 %! close (hf);
10013 %! end_unwind_protect
10014 
10015 %!test # axes object
10016 %! hf = figure ("visible", "off");
10017 %! unwind_protect
10018 %! tol = 20 * eps;
10019 %! pos = get (0, "defaultaxesposition") * .5;
10020 %! hax = axes ("linewidth", 2, "position", pos);
10021 %! title ("Reset me, please!");
10022 %!
10023 %! reset (hax);
10024 %! assert (get (hax, "linewidth"), get (0, "defaultaxeslinewidth"), tol);
10025 %! assert (get (hax, "position"), pos, tol); # axes position is unchanged
10026 %! assert (get (hax, "default"), struct ()); # no more axes' defaults
10027 %! assert (get (get (hax, "title"), "string"), "");
10028 %! unwind_protect_cleanup
10029 %! close (hf);
10030 %! end_unwind_protect
10031 
10032 %!test # root figure object
10033 %! set (0, "defaultfigurevisible", "off");
10034 %! hf = figure ("visible", "off", "paperunits", "centimeters",
10035 %! "papertype", "a4");
10036 %! unwind_protect
10037 %! reset (hf);
10038 %! assert (get (hf, "papertype"), get (0, "defaultfigurepapertype"));
10039 %! assert (get (hf, "paperunits"), "centimeters"); # paperunits is unchanged
10040 %! assert (get (hf, "visible"), get (0, "defaultfigurevisible"));
10041 %! unwind_protect_cleanup
10042 %! close (hf);
10043 %! set (0, "defaultfigurevisible", "remove");
10044 %! end_unwind_protect
10045 
10046 */
10047 
10048 DEFUN (set, args, nargout,
10049  doc: /* -*- texinfo -*-
10050 @deftypefn {} {} set (@var{h}, @var{property}, @var{value}, @dots{})
10051 @deftypefnx {} {} set (@var{h}, @var{properties}, @var{values})
10052 @deftypefnx {} {} set (@var{h}, @var{pv})
10053 @deftypefnx {} {@var{value_list} =} set (@var{h}, @var{property})
10054 @deftypefnx {} {@var{all_value_list} =} set (@var{h})
10055 Set named property values for the graphics handle (or vector of graphics
10056 handles) @var{h}.
10057 
10058 There are three ways to give the property names and values:
10059 
10060 @itemize
10061 @item as a comma separated list of @var{property}, @var{value} pairs
10062 
10063 Here, each @var{property} is a string containing the property name, each
10064 @var{value} is a value of the appropriate type for the property.
10065 
10066 @item as a cell array of strings @var{properties} containing property names
10067 and a cell array @var{values} containing property values.
10068 
10069 In this case, the number of columns of @var{values} must match the number of
10070 elements in @var{properties}. The first column of @var{values} contains
10071 values for the first entry in @var{properties}, etc. The number of rows of
10072 @var{values} must be 1 or match the number of elements of @var{h}. In the
10073 first case, each handle in @var{h} will be assigned the same values. In the
10074 latter case, the first handle in @var{h} will be assigned the values from
10075 the first row of @var{values} and so on.
10076 
10077 @item as a structure array @var{pv}
10078 
10079 Here, the field names of @var{pv} represent the property names, and the
10080 field values give the property values. In contrast to the previous case,
10081 all elements of @var{pv} will be set in all handles in @var{h} independent
10082 of the dimensions of @var{pv}.
10083 @end itemize
10084 
10085 @code{set} is also used to query the list of values a named property will
10086 take. @code{@var{clist} = set (@var{h}, "property")} will return the list
10087 of possible values for @qcode{"property"} in the cell list @var{clist}.
10088 If no output variable is used then the list is formatted and printed to the
10089 screen.
10090 
10091 If no property is specified (@code{@var{slist} = set (@var{h})}) then a
10092 structure @var{slist} is returned where the fieldnames are the properties of
10093 the object @var{h} and the fields are the list of possible values for each
10094 property. If no output variable is used then the list is formatted and
10095 printed to the screen.
10096 
10097 For example,
10098 
10099 @example
10100 @group
10101 hf = figure ();
10102 set (hf, "paperorientation")
10103 @result{} paperorientation: [ landscape | @{portrait@} | rotated ]
10104 @end group
10105 @end example
10106 
10107 @noindent
10108 shows the paperorientation property can take three values with the default
10109 being @qcode{"portrait"}.
10110 @seealso{get}
10111 @end deftypefn */)
10112 {
10114 
10115  int nargin = args.length ();
10116 
10117  if (nargin == 0)
10118  print_usage ();
10119 
10121 
10122  // get vector of graphics handles
10123  ColumnVector hcv = args(0).xvector_value ("set: H must be a graphics handle");
10124 
10125  bool request_drawnow = false;
10126 
10127  // loop over graphics objects
10128  for (octave_idx_type n = 0; n < hcv.numel (); n++)
10129  {
10131 
10132  if (! go)
10133  error ("set: invalid handle (= %g)", hcv(n));
10134 
10135  if (nargin == 3 && args(1).is_cellstr () && args(2).is_cell ())
10136  {
10137  if (args(2).cell_value ().rows () == 1)
10138  go.set (args(1).cellstr_value (), args(2).cell_value (), 0);
10139  else if (hcv.numel () == args(2).cell_value ().rows ())
10140  go.set (args(1).cellstr_value (), args(2).cell_value (), n);
10141  else
10142  error ("set: number of graphics handles must match number of value rows (%d != %d)",
10143  hcv.numel (), args(2).cell_value ().rows ());
10144  }
10145  else if (nargin == 2 && args(1).is_map ())
10146  go.set (args(1).map_value ());
10147  else if (nargin == 2 && args(1).is_string ())
10148  {
10149  std::string property = args(1).string_value ();
10150 
10151  octave_map pmap = go.values_as_struct ();
10152 
10154  if (nargout != 0)
10155  retval = Matrix ();
10156  else
10157  octave_stdout << "set: " << property
10158  <<" is read-only" << std::endl;
10159  else if (pmap.isfield (property))
10160  {
10161  if (nargout != 0)
10162  retval = pmap.getfield (property)(0);
10163  else
10164  {
10166 
10167  octave_stdout << s;
10168  }
10169  }
10170  else
10171  error ("set: unknown property");
10172  }
10173  else if (nargin == 1)
10174  {
10175  if (nargout != 0)
10176  retval = go.values_as_struct ();
10177  else
10178  {
10179  std::string s = go.values_as_string ();
10180 
10181  octave_stdout << s;
10182  }
10183  }
10184  else
10185  {
10186  go.set (args.splice (0, 1));
10187  request_drawnow = true;
10188  }
10189 
10190  request_drawnow = true;
10191  }
10192 
10193  if (request_drawnow)
10194  Vdrawnow_requested = true;
10195 
10196  return retval;
10197 }
10198 
10199 static std::string
10201 {
10203 
10205 
10206  if (! go)
10207  error ("get: invalid handle (= %g)", val);
10208 
10209  return go.type ();
10210 }
10211 
10212 DEFUN (get, args, ,
10213  doc: /* -*- texinfo -*-
10214 @deftypefn {} {@var{val} =} get (@var{h})
10215 @deftypefnx {} {@var{val} =} get (@var{h}, @var{p})
10216 Return the value of the named property @var{p} from the graphics handle
10217 @var{h}.
10218 
10219 If @var{p} is omitted, return the complete property list for @var{h}.
10220 
10221 If @var{h} is a vector, return a cell array including the property values or
10222 lists respectively.
10223 @seealso{set}
10224 @end deftypefn */)
10225 {
10226  gh_manager::auto_lock guard;
10227 
10228  int nargin = args.length ();
10229 
10230  if (nargin < 1 || nargin > 2)
10231  print_usage ();
10232 
10233  if (args(0).is_empty ())
10234  return ovl (Matrix ());
10235 
10236  ColumnVector hcv = args(0).xvector_value ("get: H must be a graphics handle");
10237 
10238  octave_idx_type hcv_len = hcv.numel ();
10239 
10240  if (nargin == 1 && hcv_len > 1)
10241  {
10243 
10244  for (octave_idx_type n = 1; n < hcv_len; n++)
10245  {
10247 
10248  if (typ != typ0)
10249  error ("get: vector of handles must all have the same type");
10250  }
10251  }
10252 
10254  Cell vals;
10255  bool use_cell_format = false;
10256 
10257  if (nargin > 1 && args(1).is_cellstr ())
10258  {
10259  Array<std::string> plist = args(1).cellstr_value ();
10260 
10261  octave_idx_type plen = plist.numel ();
10262 
10263  use_cell_format = true;
10264 
10265  vals.resize (dim_vector (hcv_len, plen));
10266 
10267  for (octave_idx_type n = 0; n < hcv_len; n++)
10268  {
10270 
10271  if (! go)
10272  error ("get: invalid handle (= %g)", hcv(n));
10273 
10274  for (octave_idx_type m = 0; m < plen; m++)
10275  {
10276  caseless_str property = plist(m);
10277 
10278  vals(n, m) = go.get (property);
10279  }
10280  }
10281  }
10282  else
10283  {
10285 
10286  if (nargin > 1)
10287  property = args(1).xstring_value ("get: second argument must be property name or cell array of property names");
10288 
10289  vals.resize (dim_vector (hcv_len, 1));
10290 
10291  for (octave_idx_type n = 0; n < hcv_len; n++)
10292  {
10294 
10295  if (! go)
10296  error ("get: invalid handle (= %g)", hcv(n));
10297 
10298  if (nargin == 1)
10299  vals(n) = go.get ();
10300  else
10301  vals(n) = go.get (property);
10302  }
10303  }
10304 
10305  if (use_cell_format)
10306  retval = vals;
10307  else
10308  {
10309  octave_idx_type vals_len = vals.numel ();
10310 
10311  if (vals_len == 0)
10312  retval = Matrix ();
10313  else if (vals_len == 1)
10314  retval = vals(0);
10315  else if (vals_len > 1 && nargin == 1)
10316  {
10318 
10319  for (octave_idx_type n = 0; n < vals_len; n++)
10320  tmp[n] = vals(n).scalar_map_value ();
10321 
10322  retval = octave_map::cat (0, vals_len, tmp);
10323  }
10324  else
10325  retval = vals;
10326  }
10327 
10328  return retval;
10329 }
10330 
10331 /*
10332 %!assert (get (findobj (0, "Tag", "nonexistenttag"), "nonexistentproperty"), [])
10333 */
10334 
10335 // Return all properties from the graphics handle @var{h}.
10336 // If @var{h} is a vector, return a cell array including the
10337 // property values or lists respectively.
10338 
10339 DEFUN (__get__, args, ,
10340  doc: /* -*- texinfo -*-
10341 @deftypefn {} {} __get__ (@var{h})
10342 Undocumented internal function.
10343 @end deftypefn */)
10344 {
10345  gh_manager::auto_lock guard;
10346 
10347  if (args.length () != 1)
10348  print_usage ();
10349 
10350  ColumnVector hcv = args(0).xvector_value ("get: H must be a graphics handle");
10351 
10352  octave_idx_type hcv_len = hcv.numel ();
10353 
10354  Cell vals (dim_vector (hcv_len, 1));
10355 
10356 // vals.resize (dim_vector (hcv_len, 1));
10357 
10358  for (octave_idx_type n = 0; n < hcv_len; n++)
10359  {
10361 
10362  if (! go)
10363  error ("get: invalid handle (= %g)", hcv(n));
10364 
10365  vals(n) = go.get (true);
10366  }
10367 
10368  octave_idx_type vals_len = vals.numel ();
10369 
10370  if (vals_len > 1)
10371  return ovl (vals);
10372  else if (vals_len == 1)
10373  return ovl (vals(0));
10374  else
10375  return ovl ();
10376 }
10377 
10378 static octave_value
10379 make_graphics_object (const std::string& go_name,
10380  bool integer_figure_handle,
10381  const octave_value_list& args)
10382 {
10384 
10386 
10387  octave_value_list xargs = args.splice (0, 1);
10388 
10389  caseless_str p ("parent");
10390 
10391  for (int i = 0; i < xargs.length (); i++)
10392  {
10393  if (xargs(i).is_string () && p.compare (xargs(i).string_value ()))
10394  {
10395  if (i >= (xargs.length () - 1))
10396  error ("__go_%s__: missing value for parent property",
10397  go_name.c_str ());
10398 
10399  val = xargs(i+1).double_value ();
10400 
10401  xargs = xargs.splice (i, 2);
10402  break;
10403  }
10404  }
10405 
10406  if (octave::math::isnan (val))
10407  val = args(0).xdouble_value ("__go_%s__: invalid parent", go_name.c_str ());
10408 
10409  graphics_handle parent = gh_manager::lookup (val);
10410 
10411  if (! parent.ok ())
10412  error ("__go_%s__: invalid parent", go_name.c_str ());
10413 
10415 
10416  try
10417  {
10418  h = gh_manager::make_graphics_handle (go_name, parent,
10419  integer_figure_handle,
10420  false, false);
10421  }
10422  catch (octave::execution_exception& e)
10423  {
10424  error (e, "__go%s__: unable to create graphics handle",
10425  go_name.c_str ());
10426  }
10427 
10428  adopt (parent, h);
10429 
10430  xset (h, xargs);
10431  xcreatefcn (h);
10432  xinitialize (h);
10433 
10434  retval = h.value ();
10435 
10436  Vdrawnow_requested = true;
10437 
10438  return retval;
10439 }
10440 
10441 DEFUN (__go_figure__, args, ,
10442  doc: /* -*- texinfo -*-
10443 @deftypefn {} {} __go_figure__ (@var{fignum})
10444 Undocumented internal function.
10445 @end deftypefn */)
10446 {
10447  gh_manager::auto_lock guard;
10448 
10449  if (args.length () == 0)
10450  print_usage ();
10451 
10452  double val = args(0).xdouble_value ("__go_figure__: figure number must be a double value");
10453 
10455 
10456  if (is_figure (val))
10457  {
10459 
10460  xset (h, args.splice (0, 1));
10461 
10462  retval = h.value ();
10463  }
10464  else
10465  {
10466  bool int_fig_handle = true;
10467 
10468  octave_value_list xargs = args.splice (0, 1);
10469 
10471 
10472  if (octave::math::isnan (val))
10473  {
10474  caseless_str pname ("integerhandle");
10475 
10476  for (int i = 0; i < xargs.length (); i++)
10477  {
10478  if (xargs(i).is_string ()
10479  && pname.compare (xargs(i).string_value ()))
10480  {
10481  if (i < (xargs.length () - 1))
10482  {
10483  std::string pval = xargs(i+1).string_value ();
10484 
10485  caseless_str on ("on");
10486  int_fig_handle = on.compare (pval);
10487  xargs = xargs.splice (i, 2);
10488 
10489  break;
10490  }
10491  }
10492  }
10493 
10494  h = gh_manager::make_graphics_handle ("figure", 0,
10495  int_fig_handle,
10496  false, false);
10497 
10498  if (! int_fig_handle)
10499  {
10500  // We need to initialize the integerhandle property
10501  // without calling the set_integerhandle method,
10502  // because doing that will generate a new handle value...
10504  go.get_properties ().init_integerhandle ("off");
10505  }
10506  }
10507  else if (val > 0 && octave::math::x_nint (val) == val)
10508  h = gh_manager::make_figure_handle (val, false);
10509 
10510  if (! h.ok ())
10511  error ("__go_figure__: failed to create figure handle");
10512 
10513  adopt (0, h);
10514 
10516 
10517  xset (h, xargs);
10518  xcreatefcn (h);
10519  xinitialize (h);
10520 
10521  retval = h.value ();
10522  }
10523 
10524  return retval;
10525 }
10526 
10527 #define GO_BODY(TYPE) \
10528  gh_manager::auto_lock guard; \
10529  \
10530  if (args.length () == 0) \
10531  print_usage (); \
10532  \
10533  return octave_value (make_graphics_object (#TYPE, false, args)); \
10534 
10535 int
10536 calc_dimensions (const graphics_object& go)
10537 {
10538  int nd = 2;
10539 
10540  if (go.isa ("surface"))
10541  nd = 3;
10542  else if ((go.isa ("line") || go.isa ("patch"))
10543  && ! go.get ("zdata").is_empty ())
10544  nd = 3;
10545  else
10546  {
10547  Matrix kids = go.get_properties ().get_children ();
10548 
10549  for (octave_idx_type i = 0; i < kids.numel (); i++)
10550  {
10551  graphics_handle hkid = gh_manager::lookup (kids(i));
10552 
10553  if (hkid.ok ())
10554  {
10555  const graphics_object& kid = gh_manager::get_object (hkid);
10556 
10557  if (kid.valid_object ())
10558  nd = calc_dimensions (kid);
10559 
10560  if (nd == 3)
10561  break;
10562  }
10563  }
10564  }
10565 
10566  return nd;
10567 }
10568 
10569 DEFUN (__calc_dimensions__, args, ,
10570  doc: /* -*- texinfo -*-
10571 @deftypefn {} {} __calc_dimensions__ (@var{axes})
10572 Internal function.
10573 
10574 Determine the number of dimensions in a graphics object, either 2 or 3.
10575 @end deftypefn */)
10576 {
10577  gh_manager::auto_lock guard;
10578 
10579  if (args.length () != 1)
10580  print_usage ();
10581 
10582  double h = args(0).xdouble_value ("__calc_dimensions__: first argument must be a graphics handle");
10583 
10585 }
10586 
10587 DEFUN (__go_axes__, args, ,
10588  doc: /* -*- texinfo -*-
10589 @deftypefn {} {} __go_axes__ (@var{parent})
10590 Undocumented internal function.
10591 @end deftypefn */)
10592 {
10593  GO_BODY (axes);
10594 }
10595 
10596 DEFUN (__go_line__, args, ,
10597  doc: /* -*- texinfo -*-
10598 @deftypefn {} {} __go_line__ (@var{parent})
10599 Undocumented internal function.
10600 @end deftypefn */)
10601 {
10602  GO_BODY (line);
10603 }
10604 
10605 DEFUN (__go_text__, args, ,
10606  doc: /* -*- texinfo -*-
10607 @deftypefn {} {} __go_text__ (@var{parent})
10608 Undocumented internal function.
10609 @end deftypefn */)
10610 {
10611  GO_BODY (text);
10612 }
10613 
10614 DEFUN (__go_image__, args, ,
10615  doc: /* -*- texinfo -*-
10616 @deftypefn {} {} __go_image__ (@var{parent})
10617 Undocumented internal function.
10618 @end deftypefn */)
10619 {
10620  GO_BODY (image);
10621 }
10622 
10623 DEFUN (__go_surface__, args, ,
10624  doc: /* -*- texinfo -*-
10625 @deftypefn {} {} __go_surface__ (@var{parent})
10626 Undocumented internal function.
10627 @end deftypefn */)
10628 {
10629  GO_BODY (surface);
10630 }
10631 
10632 DEFUN (__go_patch__, args, ,
10633  doc: /* -*- texinfo -*-
10634 @deftypefn {} {} __go_patch__ (@var{parent})
10635 Undocumented internal function.
10636 @end deftypefn */)
10637 {
10638  GO_BODY (patch);
10639 }
10640 
10641 DEFUN (__go_light__, args, ,
10642  doc: /* -*- texinfo -*-
10643 @deftypefn {} {} __go_light__ (@var{parent})
10644 Undocumented internal function.
10645 @end deftypefn */)
10646 {
10647  GO_BODY (light);
10648 }
10649 
10650 DEFUN (__go_hggroup__, args, ,
10651  doc: /* -*- texinfo -*-
10652 @deftypefn {} {} __go_hggroup__ (@var{parent})
10653 Undocumented internal function.
10654 @end deftypefn */)
10655 {
10656  GO_BODY (hggroup);
10657 }
10658 
10659 DEFUN (__go_uimenu__, args, ,
10660  doc: /* -*- texinfo -*-
10661 @deftypefn {} {} __go_uimenu__ (@var{parent})
10662 Undocumented internal function.
10663 @end deftypefn */)
10664 {
10665  GO_BODY (uimenu);
10666 }
10667 
10668 DEFUN (__go_uicontrol__, args, ,
10669  doc: /* -*- texinfo -*-
10670 @deftypefn {} {} __go_uicontrol__ (@var{parent})
10671 Undocumented internal function.
10672 @end deftypefn */)
10673 {
10674  GO_BODY (uicontrol);
10675 }
10676 
10677 DEFUN (__go_uibuttongroup__, args, ,
10678  doc: /* -*- texinfo -*-
10679 @deftypefn {} {} __go_uibuttongroup__ (@var{parent})
10680 Undocumented internal function.
10681 @end deftypefn */)
10682 {
10684 }
10685 
10686 DEFUN (__go_uipanel__, args, ,
10687  doc: /* -*- texinfo -*-
10688 @deftypefn {} {} __go_uipanel__ (@var{parent})
10689 Undocumented internal function.
10690 @end deftypefn */)
10691 {
10692  GO_BODY (uipanel);
10693 }
10694 
10695 DEFUN (__go_uicontextmenu__, args, ,
10696  doc: /* -*- texinfo -*-
10697 @deftypefn {} {} __go_uicontextmenu__ (@var{parent})
10698 Undocumented internal function.
10699 @end deftypefn */)
10700 {
10702 }
10703 
10704 DEFUN (__go_uitoolbar__, args, ,
10705  doc: /* -*- texinfo -*-
10706 @deftypefn {} {} __go_uitoolbar__ (@var{parent})
10707 Undocumented internal function.
10708 @end deftypefn */)
10709 {
10710  GO_BODY (uitoolbar);
10711 }
10712 
10713 DEFUN (__go_uipushtool__, args, ,
10714  doc: /* -*- texinfo -*-
10715 @deftypefn {} {} __go_uipushtool__ (@var{parent})
10716 Undocumented internal function.
10717 @end deftypefn */)
10718 {
10719  GO_BODY (uipushtool);
10720 }
10721 
10722 DEFUN (__go_uitoggletool__, args, ,
10723  doc: /* -*- texinfo -*-
10724 @deftypefn {} {} __go_uitoggletool__ (@var{parent})
10725 Undocumented internal function.
10726 @end deftypefn */)
10727 {
10729 }
10730 
10731 DEFUN (__go_delete__, args, ,
10732  doc: /* -*- texinfo -*-
10733 @deftypefn {} {} __go_delete__ (@var{h})
10734 Undocumented internal function.
10735 @end deftypefn */)
10736 {
10737  gh_manager::auto_lock guard;
10738 
10739  if (args.length () != 1)
10740  print_usage ();
10741 
10743 
10744  const NDArray vals = args(0).xarray_value ("delete: invalid graphics object");
10745 
10746  // Check all the handles to delete are valid first,
10747  // as callbacks might delete one of the handles we later want to delete.
10748  for (octave_idx_type i = 0; i < vals.numel (); i++)
10749  {
10750  h = gh_manager::lookup (vals(i));
10751 
10752  if (! h.ok ())
10753  error ("delete: invalid graphics object (= %g)", vals(i));
10754  }
10755 
10756  delete_graphics_objects (vals);
10757 
10758  return ovl ();
10759 }
10760 
10761 DEFUN (__go_axes_init__, args, ,
10762  doc: /* -*- texinfo -*-
10763 @deftypefn {} {} __go_axes_init__ (@var{h}, @var{mode})
10764 Undocumented internal function.
10765 @end deftypefn */)
10766 {
10767  gh_manager::auto_lock guard;
10768 
10769  int nargin = args.length ();
10770 
10771  if (nargin < 1 || nargin > 2)
10772  print_usage ();
10773 
10774  std::string mode;
10775  if (nargin == 2)
10776  mode = args(1).string_value ();
10777 
10779 
10780  double val = args(0).xdouble_value ("__go_axes_init__: invalid graphics object");
10781 
10782  h = gh_manager::lookup (val);
10783 
10784  if (! h.ok ())
10785  error ("__go_axes_init__: invalid graphics object (= %g)", val);
10786 
10788 
10789  go.set_defaults (mode);
10790 
10791  h = gh_manager::lookup (val);
10792  if (! h.ok ())
10793  error ("__go_axes_init__: axis deleted during initialization (= %g)", val);
10794 
10795  return ovl ();
10796 }
10797 
10798 DEFUN (__go_handles__, args, ,
10799  doc: /* -*- texinfo -*-
10800 @deftypefn {} {} __go_handles__ (@var{show_hidden})
10801 Undocumented internal function.
10802 @end deftypefn */)
10803 {
10804  gh_manager::auto_lock guard;
10805 
10806  bool show_hidden = false;
10807 
10808  if (args.length () > 0)
10809  show_hidden = args(0).bool_value ();
10810 
10811  return ovl (gh_manager::handle_list (show_hidden));
10812 }
10813 
10814 DEFUN (__go_figure_handles__, args, ,
10815  doc: /* -*- texinfo -*-
10816 @deftypefn {} {} __go_figure_handles__ (@var{show_hidden})
10817 Undocumented internal function.
10818 @end deftypefn */)
10819 {
10820  gh_manager::auto_lock guard;
10821 
10822  bool show_hidden = false;
10823 
10824  if (args.length () > 0)
10825  show_hidden = args(0).bool_value ();
10826 
10827  return ovl (gh_manager::figure_handle_list (show_hidden));
10828 }
10829 
10830 DEFUN (__go_execute_callback__, args, ,
10831  doc: /* -*- texinfo -*-
10832 @deftypefn {} {} __go_execute_callback__ (@var{h}, @var{name})
10833 @deftypefnx {} {} __go_execute_callback__ (@var{h}, @var{name}, @var{param})
10834 Undocumented internal function.
10835 @end deftypefn */)
10836 {
10837  int nargin = args.length ();
10838 
10839  if (nargin < 2 || nargin > 3)
10840  print_usage ();
10841 
10842  const NDArray vals = args(0).xarray_value ("__go_execute_callback__: invalid graphics object");
10843 
10844  std::string name = args(1).xstring_value ("__go_execute_callback__: invalid callback name");
10845 
10846  for (octave_idx_type i = 0; i < vals.numel (); i++)
10847  {
10848  double val = vals(i);
10849 
10851 
10852  if (! h.ok ())
10853  error ("__go_execute_callback__: invalid graphics object (= %g)", val);
10854 
10855  if (nargin == 2)
10856  gh_manager::execute_callback (h, name);
10857  else
10858  gh_manager::execute_callback (h, name, args(2));
10859  }
10860 
10861  return ovl ();
10862 }
10863 
10864 DEFUN (__image_pixel_size__, args, ,
10865  doc: /* -*- texinfo -*-
10866 @deftypefn {} {@var{px}, @var{py}} __image_pixel_size__ (@var{h})
10867 Internal function: returns the pixel size of the image in normalized units.
10868 @end deftypefn */)
10869 {
10870  if (args.length () != 1)
10871  print_usage ();
10872 
10873  double h = args(0).xdouble_value ("__image_pixel_size__: argument is not a handle");
10874 
10876  if (! go || ! go.isa ("image"))
10877  error ("__image_pixel_size__: object is not an image");
10878 
10879  image::properties& ip =
10880  dynamic_cast<image::properties&> (go.get_properties ());
10881 
10882  Matrix dp = Matrix (1, 2);
10883  dp(0) = ip.pixel_xsize ();
10884  dp(1) = ip.pixel_ysize ();
10885  return ovl (dp);
10886 }
10887 
10889 
10890 void
10892 {
10893  instance = new gtk_manager ();
10894 
10895  if (instance)
10897 }
10898 
10901 {
10903 
10904  if (dtk.empty ())
10905  error ("no graphics toolkits are available!");
10906 
10908 
10909  if (pl == loaded_toolkits.end ())
10910  {
10912 
10913  if (pa == available_toolkits.end ())
10914  error ("default graphics toolkit '%s' is not available!",
10915  dtk.c_str ());
10916 
10918  args(0) = dtk;
10919  feval ("graphics_toolkit", args);
10920 
10921  pl = loaded_toolkits.find (dtk);
10922 
10923  if (pl == loaded_toolkits.end ())
10924  error ("failed to load %s graphics toolkit", dtk.c_str ());
10925 
10926  retval = pl->second;
10927  }
10928  else
10929  retval = pl->second;
10930 
10931  return retval;
10932 }
10933 
10934 void
10936 {
10937  if (dtk.empty () || name == "qt"
10938  || (name == "fltk"
10939  && available_toolkits.find ("qt") == available_toolkits.end ()))
10940  dtk = name;
10941 
10942  available_toolkits.insert (name);
10943 }
10944 
10945 void
10947 {
10948  available_toolkits.erase (name);
10949 
10950  if (dtk == name)
10951  {
10952  if (available_toolkits.empty ())
10953  dtk.clear ();
10954  else
10955  {
10957 
10958  dtk = *pa++;
10959 
10960  while (pa != available_toolkits.end ())
10961  {
10962  std::string tk_name = *pa++;
10963 
10964  if (tk_name == "qt"
10965  || (tk_name == "fltk"
10966  && (available_toolkits.find ("qt")
10967  == available_toolkits.end ())))
10968  dtk = tk_name;
10969  }
10970  }
10971  }
10972 }
10973 
10974 DEFUN (available_graphics_toolkits, , ,
10975  doc: /* -*- texinfo -*-
10976 @deftypefn {} {} available_graphics_toolkits ()
10977 Return a cell array of registered graphics toolkits.
10978 @seealso{graphics_toolkit, register_graphics_toolkit}
10979 @end deftypefn */)
10980 {
10981  gh_manager::auto_lock guard;
10982 
10984 }
10985 
10986 DEFUN (register_graphics_toolkit, args, ,
10987  doc: /* -*- texinfo -*-
10988 @deftypefn {} {} register_graphics_toolkit (@var{toolkit})
10989 List @var{toolkit} as an available graphics toolkit.
10990 @seealso{available_graphics_toolkits}
10991 @end deftypefn */)
10992 {
10993  gh_manager::auto_lock guard;
10994 
10995  if (args.length () != 1)
10996  print_usage ();
10997 
10998  std::string name = args(0).xstring_value ("register_graphics_toolkit: TOOLKIT must be a string");
10999 
11001 
11002  return ovl ();
11003 }
11004 
11005 DEFUN (loaded_graphics_toolkits, , ,
11006  doc: /* -*- texinfo -*-
11007 @deftypefn {} {} loaded_graphics_toolkits ()
11008 Return a cell array of the currently loaded graphics toolkits.
11009 @seealso{available_graphics_toolkits}
11010 @end deftypefn */)
11011 {
11012  gh_manager::auto_lock guard;
11013 
11015 }
11016 
11017 DEFUN (drawnow, args, ,
11018  doc: /* -*- texinfo -*-
11019 @deftypefn {} {} drawnow ()
11020 @deftypefnx {} {} drawnow ("expose")
11021 @deftypefnx {} {} drawnow (@var{term}, @var{file}, @var{debug_file})
11022 Update figure windows and their children.
11023 
11024 The event queue is flushed and any callbacks generated are executed.
11025 
11026 With the optional argument @qcode{"expose"}, only graphic objects are
11027 updated and no other events or callbacks are processed.
11028 
11029 The third calling form of @code{drawnow} is for debugging and is
11030 undocumented.
11031 @seealso{refresh}
11032 @end deftypefn */)
11033 {
11034  static int drawnow_executing = 0;
11035 
11036  if (args.length () > 3)
11037  print_usage ();
11038 
11040 
11041  frame.protect_var (Vdrawnow_requested, false);
11042  frame.protect_var (drawnow_executing);
11043 
11044  // Redraw, unless we are in the middle of an existing redraw or deletion.
11045  if (++drawnow_executing <= 1 && ! delete_executing)
11046  {
11047  gh_manager::auto_lock guard;
11048 
11049  if (args.length () == 0 || args.length () == 1)
11050  {
11051  Matrix hlist = gh_manager::figure_handle_list (true);
11052 
11053  for (int i = 0; i < hlist.numel (); i++)
11054  {
11055  graphics_handle h = gh_manager::lookup (hlist(i));
11056 
11057  if (h.ok () && h != 0)
11058  {
11060  figure::properties& fprops
11061  = dynamic_cast<figure::properties&> (go.get_properties ());
11062 
11063  if (fprops.is_modified ())
11064  {
11065  if (fprops.is_visible ())
11066  {
11067  gh_manager::unlock ();
11068 
11069  fprops.get_toolkit ().redraw_figure (go);
11070 
11071  gh_manager::lock ();
11072  }
11073 
11074  fprops.set_modified (false);
11075  }
11076  }
11077  }
11078 
11079  bool do_events = true;
11080 
11081  if (args.length () == 1)
11082  {
11083  caseless_str val (args(0).xstring_value ("drawnow: first argument must be a string"));
11084 
11085  if (val.compare ("expose"))
11086  do_events = false;
11087  else
11088  error ("drawnow: invalid argument, 'expose' is only valid option");
11089  }
11090 
11091  if (do_events)
11092  {
11093  gh_manager::unlock ();
11094 
11096 
11097  gh_manager::lock ();
11098  }
11099  }
11100  else if (args.length () >= 2 && args.length () <= 3)
11101  {
11102  std::string term, file, debug_file;
11103 
11104  term = args(0).xstring_value ("drawnow: TERM must be a string");
11105 
11106  file = args(1).xstring_value ("drawnow: FILE must be a string");
11107 
11108  if (file.empty ())
11109  error ("drawnow: empty output ''");
11110  else if (file.length () == 1 && file[0] == '|')
11111  error ("drawnow: empty pipe '|'");
11112  else if (file[0] != '|')
11113  {
11114  size_t pos = file.find_last_of (octave::sys::file_ops::dir_sep_chars ());
11115 
11116  if (pos != std::string::npos)
11117  {
11118  std::string dirname = file.substr (0, pos+1);
11119 
11120  octave::sys::file_stat fs (dirname);
11121 
11122  if (! fs || ! fs.is_dir ())
11123  error ("drawnow: nonexistent directory '%s'",
11124  dirname.c_str ());
11125 
11126  }
11127  }
11128 
11129  debug_file = (args.length () > 2 ? args(2).xstring_value ("drawnow: DEBUG_FILE must be a string") : "");
11130 
11131  graphics_handle h = gcf ();
11132 
11133  if (! h.ok ())
11134  error ("drawnow: nothing to draw");
11135 
11137 
11138  // FIXME: when using qt toolkit the print_figure method
11139  // returns immediately and Canvas::print doesn't have
11140  // enough time to lock the mutex before we lock it here
11141  // again. We thus wait 50 ms (which may not be enough) to
11142  // give it a chance: see http://octave.1599824.n4.nabble.com/Printing-issues-with-Qt-toolkit-tp4673270.html
11143 
11144  gh_manager::unlock ();
11145 
11146  go.get_toolkit ().print_figure (go, term, file, debug_file);
11147 
11148  // FIXME: In ObjectProxy.cc ObjectProxy::init
11149  // we now use connect (..., Qt::BlockingQueuedConnection)
11150  // which should make the sleep unnecessary.
11151  // See bug #44463 and #48519
11152  // Remove it and the FIXME block above after testing.
11153 
11154  // octave_sleep (0.05);
11155 
11156  gh_manager::lock ();
11157  }
11158  }
11159 
11160  return ovl ();
11161 }
11162 
11163 DEFUN (addlistener, args, ,
11164  doc: /* -*- texinfo -*-
11165 @deftypefn {} {} addlistener (@var{h}, @var{prop}, @var{fcn})
11166 Register @var{fcn} as listener for the property @var{prop} of the graphics
11167 object @var{h}.
11168 
11169 Property listeners are executed (in order of registration) when the property
11170 is set. The new value is already available when the listeners are executed.
11171 
11172 @var{prop} must be a string naming a valid property in @var{h}.
11173 
11174 @var{fcn} can be a function handle, a string or a cell array whose first
11175 element is a function handle. If @var{fcn} is a function handle, the
11176 corresponding function should accept at least 2 arguments, that will be
11177 set to the object handle and the empty matrix respectively. If @var{fcn}
11178 is a string, it must be any valid octave expression. If @var{fcn} is a cell
11179 array, the first element must be a function handle with the same signature
11180 as described above. The next elements of the cell array are passed
11181 as additional arguments to the function.
11182 
11183 Example:
11184 
11185 @example
11186 @group
11187 function my_listener (h, dummy, p1)
11188  fprintf ("my_listener called with p1=%s\n", p1);
11189 endfunction
11190 
11191 addlistener (gcf, "position", @{@@my_listener, "my string"@})
11192 @end group
11193 @end example
11194 
11195 @seealso{addproperty, hggroup}
11196 @end deftypefn */)
11197 {
11198  gh_manager::auto_lock guard;
11199 
11200  int nargin = args.length ();
11201 
11202  if (nargin < 3 || nargin > 4)
11203  print_usage ();
11204 
11205  double h = args(0).xdouble_value ("addlistener: invalid handle H");
11206 
11207  std::string pname = args(1).xstring_value ("addlistener: PROP must be a string");
11208 
11210 
11211  if (! gh.ok ())
11212  error ("addlistener: invalid graphics object (= %g)", h);
11213 
11215 
11216  go.add_property_listener (pname, args(2), POSTSET);
11217 
11218  if (args.length () == 4)
11219  {
11220  caseless_str persistent = args(3).string_value ();
11221  if (persistent.compare ("persistent"))
11222  go.add_property_listener (pname, args(2), PERSISTENT);
11223  }
11224 
11225  return ovl ();
11226 }
11227 
11228 DEFUN (dellistener, args, ,
11229  doc: /* -*- texinfo -*-
11230 @deftypefn {} {} dellistener (@var{h}, @var{prop}, @var{fcn})
11231 Remove the registration of @var{fcn} as a listener for the property
11232 @var{prop} of the graphics object @var{h}.
11233 
11234 The function @var{fcn} must be the same variable (not just the same value),
11235 as was passed to the original call to @code{addlistener}.
11236 
11237 If @var{fcn} is not defined then all listener functions of @var{prop}
11238 are removed.
11239 
11240 Example:
11241 
11242 @example
11243 @group
11244 function my_listener (h, dummy, p1)
11245  fprintf ("my_listener called with p1=%s\n", p1);
11246 endfunction
11247 
11248 c = @{@@my_listener, "my string"@};
11249 addlistener (gcf, "position", c);
11250 dellistener (gcf, "position", c);
11251 @end group
11252 @end example
11253 
11254 @end deftypefn */)
11255 {
11256  gh_manager::auto_lock guard;
11257 
11258  if (args.length () < 2 || args.length () > 3)
11259  print_usage ();
11260 
11261  double h = args(0).xdouble_value ("dellistener: invalid handle");
11262 
11263  std::string pname = args(1).xstring_value ("dellistener: PROP must be a string");
11264 
11266 
11267  if (! gh.ok ())
11268  error ("dellistener: invalid graphics object (= %g)", h);
11269 
11271 
11272  if (args.length () == 2)
11274  else
11275  {
11276  if (args(2).is_string ()
11277  && args(2).string_value () == "persistent")
11278  {
11279  go.delete_property_listener (pname, octave_value (),
11280  PERSISTENT);
11281  go.delete_property_listener (pname, octave_value (),
11282  POSTSET);
11283  }
11284  else
11285  go.delete_property_listener (pname, args(2), POSTSET);
11286  }
11287 
11288  return ovl ();
11289 }
11290 
11291 DEFUN (addproperty, args, ,
11292  doc: /* -*- texinfo -*-
11293 @deftypefn {} {} addproperty (@var{name}, @var{h}, @var{type})
11294 @deftypefnx {} {} addproperty (@var{name}, @var{h}, @var{type}, @var{arg}, @dots{})
11295 Create a new property named @var{name} in graphics object @var{h}.
11296 
11297 @var{type} determines the type of the property to create. @var{args}
11298 usually contains the default value of the property, but additional
11299 arguments might be given, depending on the type of the property.
11300 
11301 The supported property types are:
11302 
11303 @table @code
11304 @item string
11305 A string property. @var{arg} contains the default string value.
11306 
11307 @item any
11308 An @nospell{un-typed} property. This kind of property can hold any octave
11309 value. @var{args} contains the default value.
11310 
11311 @item radio
11312 A string property with a limited set of accepted values. The first
11313 argument must be a string with all accepted values separated by
11314 a vertical bar ('|'). The default value can be marked by enclosing
11315 it with a '@{' '@}' pair. The default value may also be given as
11316 an optional second string argument.
11317 
11318 @item boolean
11319 A boolean property. This property type is equivalent to a radio
11320 property with "on|off" as accepted values. @var{arg} contains
11321 the default property value.
11322 
11323 @item double
11324 A scalar double property. @var{arg} contains the default value.
11325 
11326 @item handle
11327 A handle property. This kind of property holds the handle of a
11328 graphics object. @var{arg} contains the default handle value.
11329 When no default value is given, the property is initialized to
11330 the empty matrix.
11331 
11332 @item data
11333 A data (matrix) property. @var{arg} contains the default data
11334 value. When no default value is given, the data is initialized to
11335 the empty matrix.
11336 
11337 @item color
11338 A color property. @var{arg} contains the default color value.
11339 When no default color is given, the property is set to black.
11340 An optional second string argument may be given to specify an
11341 additional set of accepted string values (like a radio property).
11342 @end table
11343 
11344 @var{type} may also be the concatenation of a core object type and
11345 a valid property name for that object type. The property created
11346 then has the same characteristics as the referenced property (type,
11347 possible values, hidden state@dots{}). This allows one to clone an
11348 existing property into the graphics object @var{h}.
11349 
11350 Examples:
11351 
11352 @example
11353 @group
11354 addproperty ("my_property", gcf, "string", "a string value");
11355 addproperty ("my_radio", gcf, "radio", "val_1|val_2|@{val_3@}");
11356 addproperty ("my_style", gcf, "linelinestyle", "--");
11357 @end group
11358 @end example
11359 
11360 @seealso{addlistener, hggroup}
11361 @end deftypefn */)
11362 {
11363  gh_manager::auto_lock guard;
11364 
11365  if (args.length () < 3)
11366  print_usage ();
11367 
11368  std::string name = args(0).xstring_value ("addproperty: NAME must be a string");
11369 
11370  double h = args(1).xdouble_value ("addproperty: invalid handle H");
11371 
11373 
11374  if (! gh.ok ())
11375  error ("addproperty: invalid graphics object (= %g)", h);
11376 
11378 
11379  std::string type = args(2).xstring_value ("addproperty: TYPE must be a string");
11380 
11381  if (go.get_properties ().has_property (name))
11382  error ("addproperty: a '%s' property already exists in the graphics object",
11383  name.c_str ());
11384 
11385  property p = property::create (name, gh, type, args.splice (0, 3));
11386 
11387  go.get_properties ().insert_property (name, p);
11388 
11389  return ovl ();
11390 }
11391 
11393 get_property_from_handle (double handle, const std::string& property,
11394  const std::string& func)
11395 {
11396  gh_manager::auto_lock guard;
11397 
11399 
11400  if (! go)
11401  error ("%s: invalid handle (= %g)", func.c_str (), handle);
11402 
11403  return ovl (go.get (caseless_str (property)));
11404 }
11405 
11406 bool
11407 set_property_in_handle (double handle, const std::string& property,
11408  const octave_value& arg, const std::string& func)
11409 {
11410  gh_manager::auto_lock guard;
11411 
11412  int ret = false;
11414 
11415  if (! go)
11416  error ("%s: invalid handle (= %g)", func.c_str (), handle);
11417 
11418  go.set (caseless_str (property), arg);
11419 
11420  ret = true;
11421 
11422  return ret;
11423 }
11424 
11425 static bool
11426 compare_property_values (const octave_value& ov1, const octave_value& ov2)
11427 {
11429 
11430  args(0) = ov1;
11431  args(1) = ov2;
11432 
11433  octave_value_list result = feval ("isequal", args, 1);
11434 
11435  if (result.length () > 0)
11436  return result(0).bool_value ();
11437 
11438  return false;
11439 }
11440 
11441 static std::map<uint32_t, bool> waitfor_results;
11442 
11443 static void
11444 cleanup_waitfor_id (uint32_t id)
11445 {
11446  waitfor_results.erase (id);
11447 }
11448 
11449 static void
11451  listener_mode mode = POSTSET)
11452 {
11453  Cell c = listener.cell_value ();
11454 
11455  if (c.numel () >= 4)
11456  {
11457  double h = c(2).double_value ();
11458 
11459  caseless_str pname = c(3).string_value ();
11460 
11461  gh_manager::auto_lock guard;
11462 
11464 
11465  if (gh.ok ())
11466  {
11468 
11469  if (go.get_properties ().has_property (pname))
11470  {
11471  go.get_properties ().delete_listener (pname, listener, mode);
11472 
11473  if (mode == POSTSET)
11474  go.get_properties ().delete_listener (pname, listener,
11475  PERSISTENT);
11476  }
11477  }
11478  }
11479 }
11480 
11481 static void
11483 { do_cleanup_waitfor_listener (listener, POSTSET); }
11484 
11485 static void
11487 { do_cleanup_waitfor_listener (listener, PREDELETE); }
11488 
11489 static octave_value_list
11491 {
11492  if (args.length () > 3)
11493  {
11494  uint32_t id = args(2).uint32_scalar_value ().value ();
11495 
11496  if (args.length () > 5)
11497  {
11498  double h = args(0).double_value ();
11499 
11500  caseless_str pname = args(4).string_value ();
11501 
11502  gh_manager::auto_lock guard;
11503 
11505 
11506  if (gh.ok ())
11507  {
11509  octave_value pvalue = go.get (pname);
11510 
11511  if (compare_property_values (pvalue, args(5)))
11512  waitfor_results[id] = true;
11513  }
11514  }
11515  else
11516  waitfor_results[id] = true;
11517  }
11518 
11519  return ovl ();
11520 }
11521 
11522 static octave_value_list
11524 {
11525  if (args.length () > 2)
11526  {
11527  uint32_t id = args(2).uint32_scalar_value ().value ();
11528 
11529  waitfor_results[id] = true;
11530  }
11531 
11532  return ovl ();
11533 }
11534 
11535 DEFUN (waitfor, args, ,
11536  doc: /* -*- texinfo -*-
11537 @deftypefn {} {} waitfor (@var{h})
11538 @deftypefnx {} {} waitfor (@var{h}, @var{prop})
11539 @deftypefnx {} {} waitfor (@var{h}, @var{prop}, @var{value})
11540 @deftypefnx {} {} waitfor (@dots{}, "timeout", @var{timeout})
11541 Suspend the execution of the current program until a condition is
11542 satisfied on the graphics handle @var{h}.
11543 
11544 While the program is suspended graphics events are still processed normally,
11545 allowing callbacks to modify the state of graphics objects. This function
11546 is reentrant and can be called from a callback, while another @code{waitfor}
11547 call is pending at the top-level.
11548 
11549 In the first form, program execution is suspended until the graphics object
11550 @var{h} is destroyed. If the graphics handle is invalid, the function
11551 returns immediately.
11552 
11553 In the second form, execution is suspended until the graphics object is
11554 destroyed or the property named @var{prop} is modified. If the graphics
11555 handle is invalid or the property does not exist, the function returns
11556 immediately.
11557 
11558 In the third form, execution is suspended until the graphics object is
11559 destroyed or the property named @var{prop} is set to @var{value}. The
11560 function @code{isequal} is used to compare property values. If the graphics
11561 handle is invalid, the property does not exist or the property is already
11562 set to @var{value}, the function returns immediately.
11563 
11564 An optional timeout can be specified using the property @code{timeout}.
11565 This timeout value is the number of seconds to wait for the condition to be
11566 true. @var{timeout} must be at least 1. If a smaller value is specified, a
11567 warning is issued and a value of 1 is used instead. If the timeout value is
11568 not an integer, it is truncated towards 0.
11569 
11570 To define a condition on a property named @code{timeout}, use the string
11571 @code{\timeout} instead.
11572 
11573 In all cases, typing CTRL-C stops program execution immediately.
11574 @seealso{waitforbuttonpress, isequal}
11575 @end deftypefn */)
11576 {
11577  if (args.length () == 0)
11579 
11580  double h = args(0).xdouble_value ("waitfor: invalid handle value");
11581 
11583 
11585 
11586  static uint32_t id_counter = 0;
11587  uint32_t id = 0;
11588 
11589  int max_arg_index = 0;
11590  int timeout_index = -1;
11591 
11592  double timeout = 0;
11593 
11594  if (args.length () > 1)
11595  {
11596  pname = args(1).xstring_value ("waitfor: PROP must be a string");
11597 
11598  if (pname.empty ())
11599  error ("waitfor: PROP must be a non-empty string");
11600 
11601  if (pname != "timeout")
11602  {
11603  if (pname.compare ("\\timeout"))
11604  pname = "timeout";
11605 
11606  static octave_value wf_listener;
11607 
11608  if (! wf_listener.is_defined ())
11609  wf_listener =
11611  "waitfor_listener"));
11612 
11613  max_arg_index++;
11614  if (args.length () > 2)
11615  {
11616  if (args(2).is_string ())
11617  {
11618  caseless_str s = args(2).string_value ();
11619 
11620  if (s.compare ("timeout"))
11621  timeout_index = 2;
11622  else
11623  max_arg_index++;
11624  }
11625  else
11626  max_arg_index++;
11627  }
11628 
11629  Cell listener (1, max_arg_index >= 2 ? 5 : 4);
11630 
11631  id = id_counter++;
11632  frame.add_fcn (cleanup_waitfor_id, id);
11633  waitfor_results[id] = false;
11634 
11635  listener(0) = wf_listener;
11636  listener(1) = octave_uint32 (id);
11637  listener(2) = h;
11638  listener(3) = pname;
11639 
11640  if (max_arg_index >= 2)
11641  listener(4) = args(2);
11642 
11643  octave_value ov_listener (listener);
11644 
11645  gh_manager::auto_lock guard;
11646 
11648 
11649  if (gh.ok ())
11650  {
11652 
11653  if (max_arg_index >= 2
11654  && compare_property_values (go.get (pname), args(2)))
11655  waitfor_results[id] = true;
11656  else
11657  {
11658 
11659  frame.add_fcn (cleanup_waitfor_postset_listener, ov_listener);
11660  go.add_property_listener (pname, ov_listener, POSTSET);
11661  go.add_property_listener (pname, ov_listener, PERSISTENT);
11662 
11663  if (go.get_properties ().has_dynamic_property (pname))
11664  {
11665  static octave_value wf_del_listener;
11666 
11667  if (! wf_del_listener.is_defined ())
11668  wf_del_listener =
11671  "waitfor_del_listener"));
11672 
11673  Cell del_listener (1, 4);
11674 
11675  del_listener(0) = wf_del_listener;
11676  del_listener(1) = octave_uint32 (id);
11677  del_listener(2) = h;
11678  del_listener(3) = pname;
11679 
11680  octave_value ov_del_listener (del_listener);
11681 
11683  ov_del_listener);
11684  go.add_property_listener (pname, ov_del_listener,
11685  PREDELETE);
11686  }
11687  }
11688  }
11689  }
11690  }
11691 
11692  if (timeout_index < 0 && args.length () > (max_arg_index + 1))
11693  {
11694  caseless_str s = args(max_arg_index + 1).xstring_value ("waitfor: invalid parameter, expected 'timeout'");
11695 
11696  if (! s.compare ("timeout"))
11697  error ("waitfor: invalid parameter '%s'", s.c_str ());
11698 
11699  timeout_index = max_arg_index + 1;
11700  }
11701 
11702  if (timeout_index >= 0)
11703  {
11704  if (args.length () <= (timeout_index + 1))
11705  error ("waitfor: missing TIMEOUT value");
11706 
11707  timeout = args(timeout_index + 1).xscalar_value ("waitfor: TIMEOUT must be a scalar >= 1");
11708 
11709  if (timeout < 1)
11710  {
11711  warning ("waitfor: TIMEOUT value must be >= 1, using 1 instead");
11712  timeout = 1;
11713  }
11714  }
11715 
11716  // FIXME: There is still a "hole" in the following loop. The code
11717  // assumes that an object handle is unique, which is a fair
11718  // assumption, except for figures. If a figure is destroyed
11719  // then recreated with the same figure ID, within the same
11720  // run of event hooks, then the figure destruction won't be
11721  // caught and the loop will not stop. This is an unlikely
11722  // possibility in practice, though.
11723  //
11724  // Using deletefcn callback is also unreliable as it could be
11725  // modified during a callback execution and the waitfor loop
11726  // would not stop.
11727  //
11728  // The only "good" implementation would require object
11729  // listeners, similar to property listeners.
11730 
11732 
11733  if (timeout > 0)
11734  start.stamp ();
11735 
11736  while (true)
11737  {
11738  if (true)
11739  {
11740  gh_manager::auto_lock guard;
11741 
11743 
11744  if (gh.ok ())
11745  {
11746  if (! pname.empty () && waitfor_results[id])
11747  break;
11748  }
11749  else
11750  break;
11751  }
11752 
11753  octave_sleep (0.1); // FIXME: really needed?
11754 
11755  OCTAVE_QUIT;
11756 
11758 
11759  if (timeout > 0)
11760  {
11762 
11763  if (start + timeout < now)
11764  break;
11765  }
11766  }
11767 
11768  return ovl ();
11769 }
11770 
11771 DEFUN (__zoom__, args, ,
11772  doc: /* -*- texinfo -*-
11773 @deftypefn {} {} __zoom__ (@var{axes}, @var{mode}, @var{factor})
11774 @deftypefnx {} {} __zoom__ (@var{axes}, "out")
11775 @deftypefnx {} {} __zoom__ (@var{axes}, "reset")
11776 Undocumented internal function.
11777 @end deftypefn */)
11778 {
11779  int nargin = args.length ();
11780 
11781  if (nargin != 2 && nargin != 3)
11782  print_usage ();
11783 
11784  double h = args(0).double_value ();
11785 
11786  gh_manager::auto_lock guard;
11787 
11788  graphics_handle handle = gh_manager::lookup (h);
11789 
11790  if (! handle.ok ())
11791  error ("__zoom__: invalid handle");
11792 
11794 
11795  axes::properties& ax_props =
11796  dynamic_cast<axes::properties&> (ax.get_properties ());
11797 
11798  if (nargin == 2)
11799  {
11800  std::string opt = args(1).string_value ();
11801 
11802  if (opt == "out" || opt == "reset")
11803  {
11804  if (opt == "out")
11805  {
11806  ax_props.clear_zoom_stack ();
11807  Vdrawnow_requested = true;
11808  }
11809  else
11810  ax_props.clear_zoom_stack (false);
11811  }
11812  }
11813  else
11814  {
11815  std::string mode = args(1).string_value ();
11816  double factor = args(2).scalar_value ();
11817 
11818  ax_props.zoom (mode, factor);
11819  Vdrawnow_requested = true;
11820  }
11821 
11822  return ovl ();
11823 }
static Matrix default_axes_ticklength(void)
Definition: graphics.cc:459
uint32_t id
Definition: graphics.cc:11587
bool Vdebug_on_error
Definition: error.cc:61
uint8NDArray uint8_array_value(void) const
Definition: ov.h:896
enum double_radio_property::current_enum current_type
int warning_enabled(const std::string &id)
Definition: error.cc:661
void do_register_toolkit(const std::string &name)
Definition: graphics.cc:10935
std::map< graphics_handle, graphics_object >::iterator iterator
Definition: graphics.h:13987
static void pop_figure(const graphics_handle &h)
Definition: graphics.h:13832
static graphics_event create_set_event(const graphics_handle &h, const std::string &name, const octave_value &value, bool notify_toolkit=true)
Definition: graphics.cc:9499
OCTAVE_EXPORT octave_value_list Fdrawnow(const octave_value_list &args, int) only graphic objects are updated and no other events or callbacks are processed.The third calling form of ode
Definition: graphics.cc:11032
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:803
string_vector keys(void) const
Definition: oct-map.h:338
static bool has_core_property(const caseless_str &pname)
octave_value get_default(const caseless_str &name) const
Definition: graphics.h:3231
static void convert_cdata_2(bool is_scaled, bool is_real, double clim_0, double clim_1, const double *cmapv, double x, octave_idx_type lda, octave_idx_type nc, octave_idx_type i, double *av)
Definition: graphics.cc:860
plist_map_iterator find(const std::string &go_name)
Definition: graphics.h:2047
double get_fontsize_points(double box_pix_height=0) const
Definition: graphics.cc:8882
void flush_octave_stdout(void)
Definition: pager.cc:454
const Cell & contents(const_iterator p) const
Definition: oct-map.h:313
radio_values radio_val
Definition: graphics.h:1277
#define OCTAVE_DEFAULT_FONTNAME
Definition: graphics.h:53
bool is_empty(void) const
Definition: Array.h:575
octave_value get_extent(void) const
Definition: graphics.cc:8757
void set_visible(const octave_value &val)
Definition: graphics.cc:3682
OCTINTERP_API void octave_sleep(double seconds)
graphics_handle get_parent(void) const
Definition: graphics.h:3272
static Matrix default_screensize(void)
Definition: graphics.cc:222
std::string dtk
Definition: graphics.h:2331
static std::set< double > updating_aspectratios
Definition: graphics.cc:6147
octave_value get_color_data(void) const
Definition: graphics.cc:8161
std::string get_busyaction(void) const
Definition: graphics.h:2665
static Matrix default_axes_tick(void)
Definition: graphics.cc:444
void rotate3d(double x0, double x1, double y0, double y1, bool push_to_zoom_stack=true)
Definition: graphics.cc:7810
virtual void reparent(const graphics_handle &np)
Definition: graphics.h:3022
OCTAVE_EXPORT octave_value_list column
Definition: sparse.cc:123
Definition: Cell.h:37
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:120
void update_axis_limits(const std::string &axis_type)
Definition: graphics.cc:8624
#define GO_BODY(TYPE)
void update_fontunits(const caseless_str &old_units)
Definition: graphics.cc:9002
static double default_screenpixelsperinch(void)
Definition: graphics.cc:235
void execute(void)
Definition: graphics.cc:9406
static caseless_str validate_property_name(const std::string &who, const std::string &what, const std::set< std::string > &pnames, const caseless_str &pname)
Definition: graphics.cc:78
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
Definition: oct-map.cc:661
static Matrix default_axes_outerposition(void)
Definition: graphics.cc:420
std::string values_as_string(void) const
Definition: graphics.cc:1214
static Matrix default_axes_view(void)
Definition: graphics.cc:433
bool Vdebug_on_warning
Definition: error.cc:69
bool is_real_type(void) const
Definition: ov.h:667
void * function_data
Definition: graphics.cc:9415
void set_fontunits(const octave_value &val)
Definition: graphics.cc:9161
virtual bool do_set(const octave_value &)
Definition: graphics.h:396
octave_idx_type nelem(void) const
Definition: graphics.h:901
std::string get_title(void) const
Definition: graphics.cc:4427
void override_defaults(base_graphics_object &obj)
Definition: graphics.h:4782
std::map< graphics_handle, graphics_object > handle_map
Definition: graphics.h:13998
OCTINTERP_API bool is_equal(const octave_value &v) const
Definition: graphics.cc:1467
enum color_property::current_enum current_type
graphics_handle do_get_handle(bool integer_figure_handle)
Definition: graphics.cc:2459
void set_fontunits(const octave_value &val)
Definition: graphics.cc:8990
void update_font(void)
Definition: graphics.cc:6269
void reset_default_properties(void)
Definition: graphics.cc:7928
static bool executing_callback
Definition: graphics.cc:1675
bool is_visible(void) const
Definition: graphics.h:2704
void override_defaults(base_graphics_object &obj)
Definition: graphics.cc:3078
void(* event_fcn)(void *)
Definition: graphics.h:13681
void update_text_extent(void)
Definition: graphics.cc:8057
virtual property get_property(const caseless_str &pname)
void convert_cdata_1(bool is_scaled, bool is_real, double clim_0, double clim_1, const double *cmapv, const T *cv, octave_idx_type lda, octave_idx_type nc, double *av)
Definition: graphics.cc:892
static Matrix default_control_sliderstep(void)
Definition: graphics.cc:520
octave_value reshape(const dim_vector &dv) const
Definition: ov.h:515
octave_idx_type rows(void) const
Definition: ov.h:489
virtual void update(const graphics_object &, int)
Definition: graphics.h:2112
static property_list::pval_map_type factory_defaults(void)
static ColumnVector xform_vector(double x, double y, double z)
Definition: graphics.cc:6610
void do_renumber_figure(const graphics_handle &old_gh, const graphics_handle &new_gh)
Definition: graphics.cc:2543
void set(const caseless_str &name, const octave_value &value)
Definition: graphics.h:4796
void update_units(void)
static void register_toolkit(const std::string &name)
Definition: graphics.h:2254
Matrix get_data_position(void) const
Definition: graphics.cc:7981
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:145
octave_int< T > xmax(const octave_int< T > &x, const octave_int< T > &y)
graphics_handle gca(void)
Definition: graphics.cc:2642
void erase(const std::string pname)
Definition: graphics.h:2006
static octave_value convert_cdata(const base_properties &props, const octave_value &cdata, bool is_scaled, int cdim)
Definition: graphics.cc:902
static Matrix default_figure_paperposition(void)
Definition: graphics.cc:494
graphics_handle get_xlabel(void) const
Definition: graphics.h:5592
void update_xlabel_position(void)
Definition: graphics.cc:5713
void update_paperorientation(void)
Definition: graphics.cc:4345
void set_horizontalalignmentmode(const octave_value &val)
Definition: graphics.h:8455
static Matrix do_translate(double x0, double x1, const Matrix &lims, bool is_logscale)
Definition: graphics.cc:7704
int8NDArray int8_array_value(void) const
Definition: ov.h:884
static Matrix default_patch_xdata(void)
Definition: graphics.cc:387
static Cell available_toolkits_list(void)
Definition: graphics.h:2284
void set_papertype(const octave_value &val)
Definition: graphics.cc:3817
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:8831
void insert_property(const std::string &name, property p)
Definition: graphics.h:2447
static property_list::pval_map_type factory_defaults(void)
void update_limits(void) const
Definition: graphics.cc:8478
void do_execute_listener(const graphics_handle &h, const octave_value &l)
Definition: graphics.cc:9533
static property_list::pval_map_type factory_defaults(void)
bool isa(const std::string &go_name) const
Definition: graphics.h:3286
void update_axes_layout(void)
Definition: graphics.cc:5474
static Matrix default_data(void)
Definition: graphics.cc:295
virtual void init_integerhandle(const octave_value &)
Definition: graphics.h:2437
bool is_uint16_type(void) const
Definition: ov.h:650
graphics_handle get_zlabel(void) const
Definition: graphics.h:5679
int ndims(void) const
Definition: Array.h:590
void set_rotationmode(const octave_value &val)
Definition: graphics.h:8444
void set___mouse_mode__(const octave_value &val)
Definition: graphics.cc:1879
static void run_event_hooks(void)
Definition: cmd-edit.cc:1575
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
std::set< caseless_str > possible_vals
Definition: graphics.h:906
std::set< std::string >::const_iterator const_available_toolkits_iterator
Definition: graphics.h:2342
bool is_function(void) const
Definition: ov.h:711
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
property_list get_defaults_list(void) const
Definition: graphics.h:4826
static std::string dir_sep_chars(void)
Definition: file-ops.h:85
static Matrix default_patch_ydata(void)
Definition: graphics.cc:397
void update_fontunits(void)
Matrix xscale(const Matrix &m) const
Definition: graphics.h:4899
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
int16NDArray int16_array_value(void) const
Definition: ov.h:887
void set_integerhandle(const octave_value &val)
Definition: graphics.cc:3467
void request_autopos(void)
Definition: graphics.cc:8099
virtual void defaults(void) const
Definition: graphics.h:3030
octave_idx_type length(void) const
Definition: ovl.h:96
OCTINTERP_API bool do_set(const octave_value &v)
Definition: graphics.cc:1367
static bool is_octave_thread(void)
std::string value_as_string(const std::string &prop)
Definition: graphics.h:3265
void set_units(const octave_value &val)
Definition: graphics.cc:8965
void set_linestyleorder(const octave_value &val)
Definition: graphics.cc:6531
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6386
void set_verticalalignmentmode(const octave_value &val)
Definition: graphics.h:8466
void set_currentaxes(const octave_value &val)
Definition: graphics.cc:3611
bool is_scalar_type(void) const
Definition: ov.h:673
std::string default_value(void) const
Definition: graphics.h:846
static bool has_core_property(const caseless_str &pname)
octave::sys::time now
Definition: data.cc:6299
bool is_numeric_type(void) const
Definition: ov.h:679
bool is_climinclude(void) const
Definition: graphics.h:3335
static OCTAVE_NORETURN void err_set_invalid(const std::string &pname)
Definition: graphics.cc:68
bool is_defined(void) const
Definition: ov.h:536
bool isnan(double x)
Definition: lo-mappers.cc:347
#define CHECK_ARRAY_EQUAL(T, F, A)
static bool updating_zlabel_position
Definition: graphics.cc:5921
static bool updating_axes_layout
Definition: graphics.cc:5471
RowVector xform2cam(const ColumnVector &v)
Definition: graphics.cc:5246
void execute_deletefcn(const octave_value &data=octave_value()) const
Definition: graphics.h:2676
static bool has_core_property(const caseless_str &pname)
return ovl()
virtual void remove_all_listeners(void)
Definition: graphics.cc:3211
static void cleanup_waitfor_postset_listener(const octave_value &listener)
Definition: graphics.cc:11482
Matrix xform_matrix(void)
Definition: graphics.cc:5085
T max(T x, T y)
Definition: lo-mappers.h:391
void update_units(const caseless_str &old_units)
Definition: graphics.cc:8977
void do_post_event(const graphics_event &e)
Definition: graphics.cc:9652
bool ok(void) const
Definition: oct-handle.h:109
octave_value get_dynamic(const caseless_str &pname) const
Definition: graphics.cc:2946
for large enough k
Definition: lu.cc:606
void sync_positions(void)
Definition: graphics.cc:4603
std::set< std::string > type_constraints
Definition: graphics.h:1388
const_iterator find(const std::string pname) const
Definition: graphics.h:1959
bool isa(const std::string &go_name) const
Definition: graphics.h:3068
void resize(int n, int fill_value=0)
Definition: dim-vector.h:316
octave_value get_extent(void) const
Definition: graphics.cc:7999
Matrix extract_n(octave_idx_type r1, octave_idx_type c1, octave_idx_type nr, octave_idx_type nc) const
Definition: dMatrix.cc:408
virtual void add_listener(const caseless_str &, const octave_value &, listener_mode=POSTSET)
Definition: graphics.cc:3162
static double y_dpi(void)
Definition: display.h:67
uint64NDArray uint64_array_value(void) const
Definition: ov.h:905
static void push_figure(const graphics_handle &h)
Definition: graphics.h:13826
virtual octave_value get_xlim(void) const
Definition: graphics.h:2572
double ceil(double x)
Definition: lo-mappers.h:138
OCTINTERP_API void run_listeners(listener_mode mode=POSTSET)
Definition: graphics.cc:1171
Matrix unit_cube(void)
Definition: graphics.cc:5215
void mark_modified(void)
Definition: graphics.cc:3067
void protect_var(T &var)
bool positionmode_is(const std::string &v) const
Definition: graphics.h:8118
virtual octave_value get_alim(void) const
Definition: graphics.h:2570
Matrix get_axis_limits(double xmin, double xmax, double min_pos, double max_neg, bool logscale)
Definition: graphics.cc:6778
static bool has_core_property(const caseless_str &pname)
float pixel_ysize(void)
Definition: graphics.h:9091
void do_post_function(graphics_event::event_fcn fcn, void *fcn_data)
Definition: graphics.cc:9703
void set_units(const octave_value &val)
Definition: graphics.cc:6537
graphics_toolkit get_toolkit(void) const
Definition: graphics.h:3350
Matrix get_auto_paperposition(void)
Definition: graphics.cc:3989
virtual std::string graphics_object_name(void) const
Definition: graphics.h:2431
pval_map_type::const_iterator pval_map_const_iterator
Definition: graphics.h:2027
static void execute_listener(const graphics_handle &h, const octave_value &l)
Definition: graphics.h:13876
Matrix get_extent(bool with_text=false, bool only_text_height=false) const
Definition: graphics.cc:6308
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
set_event(const graphics_handle &h, const std::string &name, const octave_value &value, bool do_notify_toolkit=true)
Definition: graphics.cc:9431
void error(const char *fmt,...)
Definition: error.cc:570
void set_dynamic(const caseless_str &pname, const octave_value &val)
Definition: graphics.cc:2988
void finalize(void)
Definition: graphics.h:3362
void reset_default_properties(void)
Definition: graphics.cc:3599
void do_free(const graphics_handle &h)
Definition: graphics.cc:2500
int32NDArray int32_array_value(void) const
Definition: ov.h:890
void set_fontunits(const octave_value &val)
Definition: graphics.cc:8014
void zoom(const std::string &mode, double factor, bool push_to_zoom_stack=true)
Definition: graphics.cc:7646
double xmaxp
Definition: graphics.h:1387
callback_event(const graphics_handle &h, const std::string &name, const octave_value &data=Matrix())
Definition: graphics.cc:9368
base_graphics_event * rep
Definition: graphics.h:13735
OCTINTERP_API octave_value_list set_warning_state(const std::string &id, const std::string &state)
bool valid_object(void) const
Definition: graphics.h:4835
property get_property_dynamic(const caseless_str &pname)
Definition: graphics.cc:3005
void set(const caseless_str &name, const octave_value &val)
Definition: graphics.cc:1939
bool is_int8_type(void) const
Definition: ov.h:635
Matrix zscale(const Matrix &m) const
Definition: graphics.h:4901
std::list< dim_vector > size_constraints
Definition: graphics.h:1389
static Matrix default_axes_position(void)
Definition: graphics.cc:407
virtual void update_axis_limits(const std::string &axis_type)
Definition: graphics.cc:3186
virtual Matrix get_boundingbox(bool=false, const Matrix &=Matrix()) const
Definition: graphics.h:2499
pval_map_type::iterator pval_map_iterator
Definition: graphics.h:2026
virtual void initialize(const graphics_object &go)
Definition: graphics.h:3102
static Matrix figure_handle_list(bool show_hidden=false)
Definition: graphics.h:13870
static property_list::pval_map_type factory_defaults(void)
void adopt(const graphics_handle &h)
Definition: graphics.h:3280
OCTINTERP_API bool str2rgb(const std::string &str)
Definition: graphics.cc:1254
bool contains(const std::string &val, std::string &match)
Definition: graphics.h:858
void setfield(const std::string &key, const octave_value &val)
Definition: oct-map.cc:178
static void xset_gcbo(const graphics_handle &h)
Definition: graphics.cc:9512
std::set< graphics_handle >::iterator free_list_iterator
Definition: graphics.h:13991
static void restore_gcbo(void)
Definition: graphics.h:14126
void translate_view(const std::string &mode, double x0, double x1, double y0, double y1, bool push_to_zoom_stack=true)
Definition: graphics.cc:7764
static double make_handle_fraction(void)
Definition: graphics.cc:2451
bool verticalalignmentmode_is(const std::string &v) const
Definition: graphics.h:8127
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:524
static std::set< double > updating_axis_limits
Definition: graphics.cc:7187
void do_restore_gcbo(void)
Definition: graphics.cc:9522
bool is_cell(void) const
Definition: ov.h:545
double calc_tick_sep(double minval, double maxval)
Definition: graphics.cc:6744
void set_position(const octave_value &val)
Definition: graphics.h:7893
static graphics_handle make_graphics_handle(const std::string &go_name, const graphics_handle &parent, bool integer_figure_handle=false, bool do_createfcn=true, bool do_notify_toolkit=true)
Definition: graphics.h:13805
T & elem(octave_idx_type n)
Definition: Array.h:482
static property_list::pval_map_type factory_defaults(void)
void update_ticklength(void)
Definition: graphics.cc:5633
color_values color_val
Definition: graphics.h:1147
u
Definition: lu.cc:138
bool rotationmode_is(const std::string &v) const
Definition: graphics.h:8121
octave_idx_type numel(void) const
Definition: oct-map.h:371
static int height(void)
Definition: display.h:47
static void force_close_figure(const graphics_handle &h)
Definition: graphics.cc:2709
std::string get_style(void) const
Definition: graphics.h:11982
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
listener_map listeners
Definition: graphics.h:414
bool is_int32_type(void) const
Definition: ov.h:641
function_event(graphics_event::event_fcn fcn, void *data=0)
Definition: graphics.cc:9402
static bool is_handle_visible(const graphics_handle &h)
Definition: graphics.h:13947
bool has_dynamic_property(const std::string &pname)
Definition: graphics.cc:2977
friend class graphics_object
Definition: graphics.h:2891
virtual void delete_children(bool clear=false)
Definition: graphics.h:2548
static void cleanup_waitfor_predelete_listener(const octave_value &listener)
Definition: graphics.cc:11486
static std::string get_graphics_object_type(double val)
Definition: graphics.cc:10200
void set_rotation(const octave_value &val)
Definition: graphics.h:8309
void update_axis_limits(const std::string &axis_type)
Definition: graphics.cc:7393
static void max_axes_scale(double &s, Matrix &limits, const Matrix &kids, double pbfactor, double dafactor, char limit_type, bool tight)
Definition: graphics.cc:6126
std::string get_units(void) const
Definition: graphics.h:8098
double fix(double x)
Definition: lo-mappers.h:158
static Matrix default_surface_xdata(void)
Definition: graphics.cc:322
graphics_handle gh
Definition: graphics.cc:11209
s
Definition: file-io.cc:2682
static std::string default_toolkit(void)
Definition: graphics.h:2300
Cell getfield(const std::string &key) const
Definition: oct-map.cc:263
static double default_screendepth(void)
Definition: graphics.cc:216
void delete_property_listener(const std::string &nm, const octave_value &v, listener_mode mode=POSTSET)
Definition: graphics.h:3356
callback_event(void)
Definition: graphics.cc:9387
void print_figure(const graphics_object &go, const std::string &term, const std::string &file, const std::string &debug_file="") const
Definition: graphics.h:2200
graphics_handle do_make_figure_handle(double val, bool do_notify_toolkit)
Definition: graphics.cc:9325
void set_xlabel(const octave_value &val)
Definition: graphics.cc:4737
static void unlock(void)
Definition: graphics.h:13864
i e
Definition: data.cc:2724
void reset_default_properties(void)
Definition: graphics.cc:4461
void delete_text_child(handle_property &h)
Definition: graphics.cc:5027
graphics_handle current_val
Definition: graphics.h:1546
Matrix yscale(const Matrix &m) const
Definition: graphics.h:4900
const_iterator end(void) const
Definition: oct-map.h:304
virtual graphics_handle get_parent(void) const
Definition: graphics.h:2990
virtual void set(const caseless_str &pname, const octave_value &pval)
Definition: graphics.h:2923
void renumber_child(graphics_handle old_gh, graphics_handle new_gh)
Definition: graphics.h:2553
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:8896
static Matrix default_lim(bool logscale=false)
Definition: graphics.cc:276
void update_axis_limits(const std::string &axis_type)
Definition: graphics.h:3295
any_property __plot_stream__
Definition: graphics.h:3915
bool is_function_handle(void) const
Definition: ov.h:702
octave_idx_type rows(void) const
Definition: Array.h:401
property_list get_factory_defaults_list(void) const
Definition: graphics.h:3253
octave_value arg
Definition: pr-output.cc:3440
octave_value get(bool all=false) const
Definition: graphics.h:3211
octave_base_value * clone(void) const
Definition: ov.cc:1149
double round(double x)
Definition: lo-mappers.cc:333
octave_function * fcn
Definition: ov-class.cc:1743
void build_user_defaults_map(property_list::pval_map_type &def, const std::string go_name) const
Definition: graphics.cc:3246
void calc_ticklabels(const array_property &ticks, any_property &labels, bool is_logscale)
Definition: graphics.cc:6998
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
OCTINTERP_API bool do_set(const octave_value &newval)
Definition: graphics.cc:1296
Matrix compute_xlim(void) const
Definition: graphics.cc:7953
graphics_xform get_transform(void) const
Definition: graphics.h:4989
RowVector transpose(void) const
Definition: dColVector.cc:124
bool has_readonly_property(const caseless_str &pname) const
Definition: graphics.h:3258
static int depth(void)
Definition: display.h:57
virtual void update_boundingbox(void)
Definition: graphics.cc:3139
cell array If invoked with two or more scalar integer or a vector of integer values
Definition: ov-cell.cc:1205
void init(void)
Definition: graphics.cc:4480
static void delete_graphics_object(const graphics_handle &h)
Definition: graphics.cc:2651
bool is_handle_visible(void) const
Definition: graphics.cc:3121
#define CONVERT_CDATA_1(ARRAY_T, VAL_FN, IS_REAL)
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
void do_post_callback(const graphics_handle &h, const std::string &name, const octave_value &data)
Definition: graphics.cc:9660
octave_value get(void) const
Definition: graphics.h:1312
virtual void adopt(const graphics_handle &h)
Definition: graphics.h:3014
Cell cell_value(void) const
Definition: ov.cc:1687
int64NDArray int64_array_value(void) const
Definition: ov.h:893
static void check_limit_vals(double &min_val, double &max_val, double &min_pos, double &max_neg, const octave_value &data)
Definition: graphics.cc:6690
void update_fontunits(const caseless_str &old_units)
Definition: graphics.cc:9173
Array< T > as_column(void) const
Return the array as a column vector.
Definition: Array.h:367
bool swap
Definition: load-save.cc:725
virtual octave_value get(bool all=false) const
Definition: graphics.h:2936
static property_list::pval_map_type factory_defaults(void)
JNIEnv void * args
Definition: ov-java.cc:67
graphics_handle gcf(void)
Definition: graphics.cc:2632
void set_currentfigure(const octave_value &val)
Definition: graphics.cc:3451
virtual void finalize(const graphics_object &go)
Definition: graphics.h:3108
void update_units(const caseless_str &old_units)
Definition: graphics.cc:9148
std::string current_val
Definition: graphics.h:1149
void update_units(const caseless_str &old_units)
Definition: graphics.cc:4402
void pan(const std::string &mode, double factor, bool push_to_zoom_stack=true)
Definition: graphics.cc:7793
bool is_aliminclude(void) const
Definition: graphics.h:3332
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:439
void set_defaults(const std::string &mode)
Definition: graphics.h:3209
void update_aspectratios(void)
Definition: graphics.cc:6150
int max_arg_index
Definition: graphics.cc:11589
property_list default_properties
Definition: graphics.h:4848
static void cleanup_waitfor_id(uint32_t id)
Definition: graphics.cc:11444
static void initialize_r(const graphics_handle &h)
Definition: graphics.cc:1847
void execute_createfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:2673
static void free(const graphics_handle &h)
Definition: graphics.h:13770
callback_event(const graphics_handle &h, const octave_value &cb, const octave_value &data=Matrix())
Definition: graphics.cc:9373
bool is_dir(void) const
Definition: file-stat.cc:57
virtual octave_value get_default(const caseless_str &) const
Definition: graphics.cc:9226
ColumnVector row_max(void) const
Definition: dMatrix.cc:2548
static bool updating_xlabel_position
Definition: graphics.cc:5710
void execute(void)
Definition: graphics.h:13711
Matrix xform_translate(double x, double y, double z)
Definition: graphics.cc:5137
void set_zlabel(const octave_value &val)
Definition: graphics.cc:4765
double h
Definition: graphics.cc:11205
void update_units(void)
Definition: graphics.cc:8799
void initialize(const graphics_object &go)
Definition: graphics.cc:7938
octave_idx_type columns(void) const
Definition: ov.h:491
done
Definition: syscalls.cc:248
create a structure array and initialize its values The dimensions of each cell array of values must match Singleton cells and non cell values are repeated so that they fill the entire array If the cells are empty
Definition: ov-struct.cc:1688
static bool has_core_property(const caseless_str &pname)
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
octave_value data
Definition: graphics.h:1383
static bool has_core_property(const caseless_str &pname)
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:941
static bool has_core_property(const caseless_str &pname)
void do_pop_figure(const graphics_handle &h)
Definition: graphics.cc:9352
OCTINTERP_API void disable_warning(const std::string &id)
virtual octave_value get_clim(void) const
Definition: graphics.h:2571
Complex atan(const Complex &x)
Definition: lo-mappers.cc:210
void update_paperunits(const caseless_str &old_paperunits)
Definition: graphics.cc:4104
static bool updating_ylabel_position
Definition: graphics.cc:5811
static bool updating_patch_data
Definition: graphics.cc:8178
octave_fields::const_iterator const_iterator
Definition: oct-map.h:177
void initialize(void)
Definition: graphics.h:3360
void update_text_extent(void)
Definition: graphics.cc:8769
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:935
void do_enable_event_processing(bool enable=true)
Definition: graphics.cc:9785
void add_fcn(void(*fcn)(void))
static Matrix default_patch_vertices(void)
Definition: graphics.cc:375
double value(void) const
Definition: oct-handle.h:74
const_iterator begin(void) const
Definition: oct-map.h:180
virtual void update(const graphics_object &go, int id)
Definition: graphics.h:3117
ColumnVector hcv
Definition: graphics.cc:10123
void set_style(const octave_value &val)
Definition: graphics.cc:8814
static bool has_core_property(const caseless_str &pname)
graphics_handle get_parent(void) const
Definition: graphics.h:293
virtual octave_value get_zlim(void) const
Definition: graphics.h:2574
std::set< std::string > dynamic_property_names(void) const
Definition: graphics.cc:2971
bool Vdrawnow_requested
Definition: input.cc:106
Matrix get_children(void) const
Definition: graphics.h:2517
bool isfield(const std::string &name) const
Definition: oct-map.h:329
void update_title_position(void)
Definition: graphics.cc:6048
static bool is_figure(double val)
Definition: graphics.cc:2808
int event_processing
Definition: graphics.h:14020
octave_idx_type nfields(void) const
Definition: oct-map.h:326
graphics_toolkit do_get_toolkit(void) const
Definition: graphics.cc:10900
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:411
bool is_bool_type(void) const
Definition: ov.h:661
bool is_real_scalar(void) const
Definition: ov.h:551
ColumnVector cam2xform(const Array< double > &m)
Definition: graphics.cc:5236
void update_units(void)
Definition: graphics.cc:8107
Matrix xrgb
Definition: graphics.h:1042
bool is_beingdeleted(void) const
Definition: graphics.h:2661
void reset_default_properties(void)
Definition: graphics.cc:9215
#define PERSISTENT
Definition: oct-parse.cc:349
std::string string_value(bool force=false) const
Definition: ov.h:908
plist_map_iterator end(void)
Definition: graphics.h:2044
double force_in_range(double x, double lower, double upper)
Definition: graphics.cc:7554
int timeout_index
Definition: graphics.cc:11590
void mark_modified(void)
Definition: graphics.h:3174
static char default_im_data[]
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
std::string join(const std::string &sep="") const
Definition: str-vec.cc:134
virtual void delete_listener(const caseless_str &, const octave_value &, listener_mode=POSTSET)
Definition: graphics.cc:3173
ColumnVector xform_vector(void)
Definition: graphics.cc:5096
static void add(fptr f)
octave_value get_factory_default(const caseless_str &name) const
Definition: graphics.h:3236
virtual void adopt(const graphics_handle &h)
Definition: graphics.h:2489
gtk_manager(void)
Definition: graphics.h:2307
#define OCTAVE_SAFE_CALL(F, ARGS)
Definition: interpreter.h:67
void set_font(const std::string &name, const std::string &weight, const std::string &angle, double size)
static Matrix default_control_position(void)
Definition: graphics.cc:507
bool is_matrix_type(void) const
Definition: ov.h:676
Matrix get_extent_matrix(void) const
Definition: graphics.cc:7992
void do_delete_children(bool clear)
Definition: graphics.cc:1636
int nargin
Definition: graphics.cc:10115
void set_callbackobject(const octave_value &val)
Definition: graphics.cc:3424
~uicontextmenu(void)
Definition: graphics.cc:8712
octave_value callback_data
Definition: graphics.cc:9395
double signum(double x)
Definition: lo-mappers.h:259
bool is_string(void) const
Definition: ov.h:578
std::string get_name(void) const
Definition: graphics.h:2195
virtual void update_autopos(const std::string &elem_type)
Definition: graphics.cc:3153
std::string str
Definition: hash.cc:118
static void xset(const graphics_handle &h, const caseless_str &pname, const octave_value &val)
Definition: graphics.cc:2574
static bool is_handle(const graphics_handle &h)
Definition: graphics.cc:2772
bool is_double_type(void) const
Definition: ov.h:624
static octave_value_list waitfor_listener(const octave_value_list &args, int)
Definition: graphics.cc:11490
octave_value get_default(const caseless_str &name) const
Definition: graphics.cc:6651
octave_value get(void) const
Definition: graphics.h:1096
nd group nd example bool waitfor_results
Definition: graphics.cc:11361
Matrix xform_scale(double x, double y, double z)
Definition: graphics.cc:5124
void rotate_view(double delta_az, double delta_el, bool push_to_zoom_stack=true)
Definition: graphics.cc:7857
octave_value retval
Definition: graphics.cc:10120
void update_font(void)
Definition: graphics.cc:8046
static Matrix xform_eye(void)
Definition: graphics.cc:6616
ColumnVector extract_n(octave_idx_type r1, octave_idx_type n) const
Definition: dColVector.cc:165
const T * data(void) const
Definition: Array.h:582
static Matrix default_figure_position(void)
Definition: graphics.cc:470
Matrix compute_ylim(void) const
Definition: graphics.cc:7966
double norm(const ColumnVector &v)
Definition: graphics.cc:5197
void unzoom(void)
Definition: graphics.cc:7880
static void remove_event_hook(event_hook_fcn f)
Definition: cmd-edit.cc:1558
double timeout
Definition: graphics.cc:11592
void set_yticklabel(const octave_value &val)
Definition: graphics.cc:6460
string_vector & append(const std::string &s)
Definition: str-vec.cc:107
void set_zticklabel(const octave_value &val)
Definition: graphics.cc:6475
void execute(void)
Definition: graphics.cc:9436
static uint32_t id_counter
Definition: graphics.cc:11586
static bool updating_hggroup_limits
Definition: graphics.cc:8507
bool is_complex_type(void) const
Definition: ov.h:670
radio_values radio_val
Definition: graphics.h:1148
virtual octave_value get_factory_default(const caseless_str &) const
Definition: graphics.cc:9235
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1028
Matrix do_get_children(bool return_hidden) const
Definition: graphics.cc:1599
static base_graphics_object * make_graphics_object_from_type(const caseless_str &type, const graphics_handle &h=graphics_handle(), const graphics_handle &p=graphics_handle())
Definition: graphics.cc:1102
octave_value get_clim(void) const
Definition: graphics.h:3320
Cell values_as_cell(void) const
Definition: graphics.cc:1243
octave_int< T > pow(const octave_int< T > &a, const octave_int< T > &b)
double tmp
Definition: data.cc:6300
std::list< double > children_list
Definition: graphics.h:1666
double get_fontsize_points(double box_pix_height=0) const
Definition: graphics.cc:8142
bool is_yliminclude(void) const
Definition: graphics.h:3341
octave_value get_alim(void) const
Definition: graphics.h:3317
const_iterator end(void) const
Definition: oct-map.h:181
bool is_int64_type(void) const
Definition: ov.h:644
bool is_cellstr(void) const
Definition: ov.h:548
octave_value_list splice(octave_idx_type offset, octave_idx_type len, const octave_value_list &lst=octave_value_list()) const
Definition: ovl.cc:126
static Matrix default_panel_position(void)
Definition: graphics.cc:531
void set_defaults(base_graphics_object &obj, const std::string &mode)
Definition: graphics.cc:4793
Matrix transpose(void) const
Definition: dMatrix.h:129
void update_data(void)
Definition: graphics.cc:8264
virtual base_properties & get_properties(void)
Definition: graphics.h:3039
std::map< std::string, graphics_toolkit >::const_iterator const_loaded_toolkits_iterator
Definition: graphics.h:2348
static bool has_core_property(const caseless_str &pname)
static bool has_core_property(const caseless_str &pname)
bool finite(double x)
Definition: lo-mappers.cc:367
bool request_drawnow
Definition: graphics.cc:10125
void set_toolkit(const graphics_toolkit &b)
Definition: graphics.cc:1863
static octave_value convert_linestyleorder_string(const octave_value &val)
Definition: graphics.cc:6492
static Matrix default_figure_papersize(void)
Definition: graphics.cc:483
base_properties & get_properties(void)
Definition: graphics.h:3288
virtual void remove_child(const graphics_handle &h)
Definition: graphics.h:2480
static void get_array_limits(const Array< T > &m, double &emin, double &emax, double &eminp, double &emaxp)
Definition: graphics.cc:994
static bool lookup_object_name(const caseless_str &name, caseless_str &go_name, caseless_str &rest)
Definition: graphics.cc:1023
void reset_default_properties(void)
Definition: graphics.h:3366
virtual text_element * parse(const std::string &s)=0
octave_value get_default(const caseless_str &name) const
Definition: graphics.cc:9199
static Matrix default_light_position(void)
Definition: graphics.cc:544
static Matrix papersize_from_type(const caseless_str punits, const caseless_str ptype)
Definition: graphics.cc:3833
octave_idx_type length(void) const
Definition: ov.cc:1623
static Matrix handle_list(bool show_hidden=false)
Definition: graphics.h:13844
void update_camera(void)
Definition: graphics.cc:5252
idx type
Definition: ov.cc:3129
std::ostream & list_in_columns(std::ostream &, int width=0, const std::string &prefix="") const
Definition: str-vec.cc:195
graphics_toolkit toolkit
Definition: graphics.h:4769
Definition: dMatrix.h:37
void zoom_about_point(const std::string &mode, double x, double y, double factor, bool push_to_zoom_stack=true)
Definition: graphics.cc:7617
sz
Definition: data.cc:5342
void renumber_parent(graphics_handle new_gh)
Definition: graphics.h:2558
void do_unregister_toolkit(const std::string &name)
Definition: graphics.cc:10946
octave_value lookup(const caseless_str &name) const
Definition: graphics.cc:2077
static property_list::pval_map_type factory_defaults(void)
static Matrix default_surface_ydata(void)
Definition: graphics.cc:334
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
static graphics_event create_function_event(event_fcn fcn, void *data=0)
Definition: graphics.cc:9488
static Matrix convert_text_position(const Matrix &pos, const text::properties &props, const caseless_str &from_units, const caseless_str &to_units)
Definition: graphics.cc:759
ColumnVector cross(const ColumnVector &v1, const ColumnVector &v2)
Definition: graphics.cc:5203
graphics_object get_ancestor(const std::string &type) const
Definition: graphics.cc:3404
const_iterator begin(void) const
Definition: oct-map.h:303
octave_value get_zlim(void) const
Definition: graphics.h:3329
static dim_vector alloc(int n)
Definition: dim-vector.h:270
static Matrix default_colororder(void)
Definition: graphics.cc:241
void update_fontunits(const caseless_str &old_units)
Definition: graphics.cc:8870
void override_defaults(base_graphics_object &obj)
Definition: graphics.h:3176
static void close_figure(const graphics_handle &h)
Definition: graphics.cc:2701
dim_vector dims(void) const
Definition: ov.h:486
double get_fontsize_points(double box_pix_height=0) const
Definition: graphics.cc:6598
octave_value property_value
Definition: graphics.cc:9459
string_vector string_vector_value(bool pad=false) const
Definition: ov.h:911
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:787
OCTINTERP_API radio_values(const std::string &opt_string="")
Definition: graphics.cc:1179
std::string pname
Definition: graphics.cc:11207
#define FIX_LIMITS
Matrix map_to_boundingbox(double x, double y) const
Definition: graphics.cc:3745
void set(const caseless_str &name, const octave_value &val)
Definition: graphics.h:3194
void update_zlabel_position(void)
Definition: graphics.cc:5924
static graphics_event create_callback_event(const graphics_handle &h, const std::string &name, const octave_value &data=Matrix())
Definition: graphics.cc:9464
graphics_handle parent
Definition: graphics.h:412
OCTINTERP_API void execute(const octave_value &data=octave_value()) const
Definition: graphics.cc:1678
virtual void reset_default_properties(void)
Definition: graphics.cc:3269
With real return the complex result
Definition: data.cc:3375
set_event(void)
Definition: graphics.cc:9452
static void execute_callback(const graphics_handle &h, const std::string &name, const octave_value &data=Matrix())
Definition: graphics.h:13883
octave_int< uint32_t > octave_uint32
feval(ar{f}, 1) esult
Definition: oct-parse.cc:8829
static void cleanup_instance(void)
Definition: graphics.h:13761
bool isinf(double x)
Definition: lo-mappers.cc:387
void remove_child(const graphics_handle &h)
Definition: graphics.cc:5058
void set_position(const octave_value &val, bool do_notify_toolkit=true)
Definition: graphics.cc:3762
static gh_manager * instance
Definition: graphics.h:13985
graphics_handle do_make_graphics_handle(const std::string &go_name, const graphics_handle &p, bool integer_figure_handle, bool do_createfcn, bool do_notify_toolkit)
Definition: graphics.cc:9266
void add_dependent_obj(graphics_handle gh)
Definition: graphics.h:11650
T min(T x, T y)
Definition: lo-mappers.h:384
static Matrix convert_position(const Matrix &pos, const caseless_str &from_units, const caseless_str &to_units, const Matrix &parent_dim)
Definition: graphics.cc:614
std::set< std::string > available_toolkits
Definition: graphics.h:2334
octave_value get_string(void) const
Definition: graphics.h:8095
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:112
octave_function * function_value(bool silent=false) const
Definition: ov.cc:1705
graphics_toolkit get_toolkit(void) const
Definition: graphics.h:3752
virtual void set_defaults(const std::string &)
Definition: graphics.h:2931
double get_fontsize_points(double box_pix_height=0) const
Definition: graphics.cc:9185
bool is_int16_type(void) const
Definition: ov.h:638
static Matrix default_surface_cdata(void)
Definition: graphics.cc:357
octave_int< T > xmin(const octave_int< T > &x, const octave_int< T > &y)
octave_value get_deletefcn(void) const
Definition: graphics.h:2677
graphics_handle get_title(void) const
Definition: graphics.h:5563
void set_units(const octave_value &val)
Definition: graphics.cc:4390
static void magform(double x, double &a, int &b)
Definition: graphics.cc:6725
octave_value get_default(const caseless_str &name) const
Definition: graphics.cc:4445
void warning(const char *fmt,...)
Definition: error.cc:788
void do_post_set(const graphics_handle &h, const std::string &name, const octave_value &value, bool notify_toolkit=true)
Definition: graphics.cc:9711
static std::map< caseless_str, graphics_object > dprop_obj_map
Definition: graphics.cc:1703
virtual void finalize(const graphics_object &)
Definition: graphics.h:2131
string_property __graphics_toolkit__
Definition: graphics.h:3911
void update_ylabel_position(void)
Definition: graphics.cc:5814
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:9067
octave::unwind_protect frame
Definition: graphics.cc:11584
void recover_from_exception(void)
Definition: interpreter.cc:200
double xminp
Definition: graphics.h:1386
void set_xticklabel(const octave_value &val)
Definition: graphics.cc:6445
std::string type(void) const
Definition: graphics.h:3308
ColumnVector untransform(double x, double y, double z, bool use_scale=true) const
Definition: graphics.cc:6635
bool valid_object(void) const
Definition: graphics.h:3306
std::string current_val
Definition: graphics.h:1278
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:126
void get_children_limits(double &min_val, double &max_val, double &min_pos, double &max_neg, const Matrix &kids, char limit_type)
Definition: graphics.cc:7104
std::string type_name(void) const
Definition: ov.h:1232
std::string property_name
Definition: graphics.cc:9458
double get_rotation(void) const
Definition: graphics.h:8093
OCTINTERP_API bool validate(const octave_value &v)
Definition: graphics.cc:1409
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
Matrix get_extent(text_element *elt, double rotation=0.0)
static graphics_handle make_figure_handle(double val, bool do_notify_toolkit=true)
Definition: graphics.h:13818
bool is_empty(void) const
Definition: ov.h:542
bool is_bool_scalar(void) const
Definition: ov.h:563
static bool has_core_property(const caseless_str &pname)
#define Inf
Definition: Faddeeva.cc:247
void set_selectedobject(const octave_value &val)
Definition: graphics.cc:9026
#define octave_stdout
Definition: pager.h:146
const octave_char_matrix & v2
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:793
void update_label_color(handle_property label, color_property col)
Definition: graphics.cc:6262
octave::sys::time start
Definition: graphics.cc:11731
static property_list::pval_map_type factory_defaults(void)
void update_autopos(const std::string &elem_type)
Definition: graphics.cc:6096
octave_value callback
Definition: graphics.cc:9394
static void cleanup_instance(void)
Definition: graphics.h:2326
void do_close_all_figures(void)
Definition: graphics.cc:2721
double max(void) const
Definition: dColVector.cc:260
void do_push_figure(const graphics_handle &h)
Definition: graphics.cc:9344
static void do_cleanup_waitfor_listener(const octave_value &listener, listener_mode mode=POSTSET)
Definition: graphics.cc:11450
static void adopt(const graphics_handle &parent_h, const graphics_handle &h)
Definition: graphics.cc:2765
std::string default_val
Definition: graphics.h:905
bool ok(void) const
Definition: graphics.h:13714
double dot(const ColumnVector &v1, const ColumnVector &v2)
Definition: graphics.cc:5191
void set_outerposition(const octave_value &val, bool do_notify_toolkit=true)
Definition: graphics.cc:3792
virtual std::string value_as_string(const std::string &prop)
Definition: graphics.cc:3325
static octave_value box(JNIEnv *jni_env, void *jobj, void *jcls_arg=0)
Convert the Java object pointed to by jobj_arg with class jcls_arg to an Octave value.
Definition: ov-java.cc:1192
void set_title(const octave_value &val)
Definition: graphics.cc:4779
virtual bool initialize(const graphics_object &)
Definition: graphics.h:2120
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
static octave_value xget(const graphics_handle &h, const caseless_str &name)
Definition: graphics.cc:2592
std::map< std::string, pval_map_type > plist_map_type
Definition: graphics.h:2024
static octave_value convert_ticklabel_string(const octave_value &val)
Definition: graphics.cc:6394
void calc_ticks_and_lims(array_property &lims, array_property &ticks, array_property &mticks, bool limmode_is_auto, bool is_logscale)
Definition: graphics.cc:6874
properties xproperties
Definition: graphics.h:4773
void cross_product(double x1, double y1, double z1, double x2, double y2, double z2, double &x, double &y, double &z)
Definition: graphics.cc:8375
void set_fontunits(const octave_value &val)
Definition: graphics.cc:8858
OCTAVE_EXPORT octave_value_list return the value of the option it must match the dimension of the state and the relative tolerance must also be a vector of the same length tem it must match the dimension of the state and the absolute tolerance must also be a vector of the same length The local error test applied at each integration step is xample roup abs(local error in x(i))<
static void xinitialize(const graphics_handle &h)
Definition: graphics.cc:2823
void remove_child(const graphics_handle &h)
Definition: graphics.h:3278
bool is_uint8_type(void) const
Definition: ov.h:647
void push_zoom_stack(void)
Definition: graphics.cc:7660
static Matrix default_image_cdata(void)
Definition: graphics.cc:306
p
Definition: lu.cc:138
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:223
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
static property_list::pval_map_type factory_defaults(void)
static graphics_handle lookup(double val)
Definition: graphics.h:13783
virtual graphics_toolkit get_toolkit(void) const
Definition: graphics.cc:3128
static OCTINTERP_API property create(const std::string &name, const graphics_handle &parent, const caseless_str &type, const octave_value_list &args)
Definition: graphics.cc:1706
bool is_interruptible(void) const
Definition: graphics.h:2685
double get_fontsize_points(double box_pix_height=0) const
Definition: graphics.cc:9014
void set_fontunits(const octave_value &val)
Definition: graphics.cc:6574
octave_value get_xlim(void) const
Definition: graphics.h:3323
octave_handle graphics_handle
Definition: graphics.h:56
void add_property_listener(const std::string &nm, const octave_value &v, listener_mode mode=POSTSET)
Definition: graphics.h:3352
void normalize(ColumnVector &v)
Definition: graphics.cc:5184
OCTINTERP_API bool set(const octave_value &v, bool do_run=true, bool do_notify_toolkit=true)
Definition: graphics.cc:1148
octave_map values_as_struct(void)
Definition: graphics.h:3270
octave_value get_ylim(void) const
Definition: graphics.h:3326
int do_process_events(bool force=false)
Definition: graphics.cc:9721
void set_value_or_default(const caseless_str &name, const octave_value &val)
Definition: graphics.cc:2396
static OCTINTERP_API void create_instance(void)
Definition: graphics.cc:10891
void remove_child(const graphics_handle &h)
Definition: graphics.cc:3622
issues an error eealso double
Definition: ov-bool-mat.cc:594
virtual octave_value get_ylim(void) const
Definition: graphics.h:2573
property(void)
Definition: graphics.h:1833
Matrix map_from_boundingbox(double x, double y) const
Definition: graphics.cc:3728
virtual void mark_modified(void)
Definition: graphics.h:2897
static graphics_handle get_handle(bool integer_figure_handle)
Definition: graphics.h:13763
Matrix get_all_children(void) const
Definition: graphics.h:2522
void update_papertype(void)
Definition: graphics.cc:4159
void adopt(const graphics_handle &h)
Definition: graphics.cc:3650
std::string callback_name
Definition: graphics.cc:9393
void set_units(const octave_value &val)
Definition: graphics.cc:9136
static property_list::pval_map_type factory_defaults(void)
void remove_child(const graphics_handle &h)
Definition: graphics.cc:3584
bool compare(const std::string &s, size_t limit=std::string::npos) const
Definition: caseless-str.h:76
bool is_modified(void) const
Definition: graphics.h:2478
static void normalized_aspectratios(Matrix &aspectratios, const Matrix &scalefactors, double xlength, double ylength, double zlength)
Definition: graphics.cc:6111
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:301
std::string class_name(void) const
Definition: ov.h:1234
the element is set to zero In other the statement xample y
Definition: data.cc:5342
static void renumber_figure(const graphics_handle &old_gh, const graphics_handle &new_gh)
Definition: graphics.h:13776
array_property Matrix() callback_property closerequestfcn
static property_list::pval_map_type factory_defaults(void)
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5150
b
Definition: cellfun.cc:398
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol NaN(Not a Number).NaN is the result of operations which do not produce a well defined 0 result.Common operations which produce a NaN are arithmetic with infinity ex($\infty-\infty $)
void set_horizontalalignment(const octave_value &val)
Definition: graphics.h:8253
void clear_zoom_stack(bool do_unzoom=true)
Definition: graphics.cc:7916
bool any_element_is_inf_or_nan(void) const
Definition: dNDArray.cc:561
void set_verticalalignment(const octave_value &val)
Definition: graphics.h:8346
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
ColumnVector row_min(void) const
Definition: dMatrix.cc:2493
graphics_handle handle
Definition: graphics.cc:9457
static graphics_object get_object(double val)
Definition: graphics.h:13794
bool is_undefined(void) const
Definition: ov.h:539
bool is_uint64_type(void) const
Definition: ov.h:656
void set_paperunits(const octave_value &val)
Definition: graphics.cc:3800
void set_boundingbox(const Matrix &bb, bool internal=false, bool do_notify_toolkit=true)
Definition: graphics.cc:3710
octave::sys::file_stat fs(filename)
bool empty(void) const
double xdouble_value(const char *fmt,...) const
Definition: ov.cc:2063
static property_list::pval_map_type factory_defaults(void)
static property_list factory_properties
Definition: graphics.h:3730
std::string values_as_string(void)
Definition: graphics.h:3263
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5118
graphics_handle get_parent(void) const
Definition: graphics.h:2688
void do_execute_callback(const graphics_handle &h, const octave_value &cb, const octave_value &data)
Definition: graphics.cc:9547
OCTINTERP_API int calc_dimensions(const graphics_object &gh)
static void add_event_hook(event_hook_fcn f)
Definition: cmd-edit.cc:1545
virtual void update_axis_limits(const std::string &axis_type) const
Definition: graphics.cc:3087
listener_mode
Definition: graphics.h:264
float pixel_xsize(void)
Definition: graphics.h:9086
double floor(double x)
Definition: lo-mappers.cc:330
void set_text_child(handle_property &h, const std::string &who, const octave_value &v)
Definition: graphics.cc:4702
static Matrix viridis_colormap(void)
Definition: graphics.cc:132
static property_list::pval_map_type factory_defaults(void)
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:171
void set_beingdeleted(const octave_value &val)
Definition: graphics.h:2713
octave_value get_color_data(void) const
Definition: graphics.cc:8169
OCTAVE_EXPORT octave_value_list it applies a binary function and expands as necessary singleton dimensions in either input argument function
Definition: bsxfun.cc:336
static Matrix do_zoom(double val, double factor, const Matrix &lims, bool is_logscale)
Definition: graphics.cc:7565
void execute(void)
Definition: graphics.cc:9378
void set_ylabel(const octave_value &val)
Definition: graphics.cc:4751
void reparent(const graphics_handle &h)
Definition: graphics.h:3282
std::list< graphics_object > callback_objects
Definition: graphics.h:14017
addproperty("my_style", gcf,"linelinestyle","--")
graphics_handle handle
Definition: graphics.cc:9392
void update_fvc(void)
Definition: graphics.cc:8181
octave_value get_property_from_handle(double handle, const std::string &property, const std::string &func)
virtual void update_uicontextmenu(void) const
Definition: graphics.cc:3106
graphics_handle get_handle(void) const
Definition: graphics.h:3274
void update(int id)
Definition: graphics.h:3364
OCTINTERP_API octave_value_list eval_string(const std::string &, bool silent, int &parse_status, int nargout)
static property_list::pval_map_type factory_defaults(void)
std::map< std::string, graphics_toolkit > loaded_toolkits
Definition: graphics.h:2337
static property_list::pval_map_type factory_defaults(void)
static Cell loaded_toolkits_list(void)
Definition: graphics.h:2289
bool notify_toolkit
Definition: graphics.cc:9460
octave_value get_color_data(void) const
Definition: graphics.cc:8369
std::list< graphics_handle > figure_list
Definition: graphics.h:14008
graphics_handle get___myhandle__(void) const
Definition: graphics.h:2710
void set_modified(const octave_value &val)
Definition: graphics.h:2532
void redraw_figure(const graphics_object &go) const
Definition: graphics.h:2197
const T * fortran_vec(void) const
Definition: Array.h:584
static OCTINTERP_API gtk_manager * instance
Definition: graphics.h:2328
octave_fields::const_iterator const_iterator
Definition: oct-map.h:300
bool is_single_type(void) const
Definition: ov.h:627
MArray< T > reshape(const dim_vector &new_dims) const
Definition: MArray.h:91
Matrix calc_tightbox(const Matrix &init_pos)
Definition: graphics.cc:4572
bool is_showhiddenhandles(void) const
Definition: graphics.h:3498
ColumnVector transform(double x, double y, double z, bool use_scale=true) const
Definition: graphics.cc:6622
octave_scalar_map as_struct(const std::string &prefix_arg) const
Definition: graphics.cc:2171
static double convert_font_size(double font_size, const caseless_str &from_units, const caseless_str &to_units, double parent_height=0)
Definition: graphics.cc:556
void set_positionmode(const octave_value &val)
Definition: graphics.h:8433
#define OCTAVE_QUIT
Definition: quit.h:212
double double_value(bool frc_str_conv=false) const
Definition: ov.h:775
static Matrix screen_size_pixels(void)
Definition: graphics.cc:851
static octave_value_list waitfor_del_listener(const octave_value_list &args, int)
Definition: graphics.cc:11523
gh_manager(void)
Definition: graphics.cc:9244
graphics_handle get_handle(void) const
Definition: graphics.h:2998
bool is_uint32_type(void) const
Definition: ov.h:653
virtual octave_scalar_map values_as_struct(void)
Definition: graphics.cc:3352
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
static bool delete_executing
Definition: graphics.cc:2686
std::string get_name(void) const
Definition: graphics.h:289
base_properties & get_properties(void)
Definition: graphics.h:4831
OCTINTERP_API bool validate(const octave_value &v) const
Definition: graphics.cc:1651
bool discard_error_messages
Definition: error.cc:118
virtual bool has_property(const caseless_str &) const
Definition: graphics.h:2472
static bool has_core_property(const caseless_str &pname)
octave_value as_octave_value(void) const
Definition: oct-handle.h:76
endfunction addlistener(gcf,"position",@my_listener,"my string") nd group nd example eealso
Definition: graphics.cc:11196
static void clear(octave::dynamic_library &oct_file)
Definition: dynamic-ld.cc:230
Matrix get_ticklabel_extents(const Matrix &ticks, const string_vector &ticklabels, const Matrix &limits)
Definition: graphics.cc:7061
uint32NDArray uint32_array_value(void) const
Definition: ov.h:902
void stamp(void)
Definition: oct-time.cc:92
octave_value callback
Definition: graphics.h:1822
bool is_zliminclude(void) const
Definition: graphics.h:3344
set(hf,"paperorientation") esult
Definition: graphics.cc:10111
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
void build_user_defaults_map(property_list::pval_map_type &def, const std::string go_name) const
Definition: graphics.h:3186
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:3693
static bool updating_title_position
Definition: graphics.cc:6045
virtual std::string values_as_string(void)
Definition: graphics.cc:3293
static property_list::pval_map_type factory_defaults(void)
static Matrix default_surface_zdata(void)
Definition: graphics.cc:346
dim_vector dv
Definition: sub2ind.cc:263
static int width(void)
Definition: display.h:52
static void lock(void)
Definition: graphics.h:13850
uint16NDArray uint16_array_value(void) const
Definition: ov.h:899
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:3550
static void xcreatefcn(const graphics_handle &h)
Definition: graphics.cc:2816
octave_idx_type columns(void) const
Definition: Array.h:410
static bool is_handle_visible(const graphics_handle &h)
Definition: graphics.cc:9852
static bool has_core_property(const caseless_str &pname)
void update_fontunits(void)
static bool has_core_property(const caseless_str &pname)
bool is_xliminclude(void) const
Definition: graphics.h:3338
plist_map_type::const_iterator plist_map_const_iterator
Definition: graphics.h:2030
void update_vertex_normals(void)
Definition: graphics.cc:8385
T x_nint(T x)
Definition: lo-mappers.h:299
void set_parent(const octave_value &val)
Definition: graphics.cc:3017
void xform(ColumnVector &v, const Matrix &m)
Definition: graphics.cc:5162
static graphics_handle current_figure(void)
Definition: graphics.h:13838
static void finalize_r(const graphics_handle &h)
Definition: graphics.cc:1831
void set_from_list(base_graphics_object &obj, property_list &defaults)
Definition: graphics.cc:2902
void translate(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5156
graphics_handle get_ylabel(void) const
Definition: graphics.h:5637
where the brackets indicate optional arguments and and character or cell array For character arrays the conversion is repeated for every row
Definition: str2double.cc:342
static double x_dpi(void)
Definition: display.h:62
bool set_property_in_handle(double handle, const std::string &property, const octave_value &arg, const std::string &func)
graphics_handle handle_value(void) const
Definition: graphics.h:1524
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
static ColumnVector convert_label_position(const ColumnVector &p, const text::properties &props, const graphics_xform &xform, const Matrix &bbox)
Definition: graphics.cc:5682
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
Matrix inverse(void) const
Definition: dMatrix.cc:429
static void delete_graphics_objects(const NDArray vals)
Definition: graphics.cc:2689
bool horizontalalignmentmode_is(const std::string &v) const
Definition: graphics.h:8124
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:205
static property_list::pval_map_type factory_defaults(void)
void update_papersize(void)
Definition: graphics.cc:4177
static Matrix default_patch_faces(void)
Definition: graphics.cc:363
static void create_instance(void)
Definition: graphics.cc:9257
void resize(octave_idx_type n, const double &rfv=0)
Definition: dColVector.h:108
OCTINTERP_API bool do_set(const octave_value &v)
Definition: graphics.cc:1566
OCTINTERP_API void get_data_limits(void)
Definition: graphics.cc:1526
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:6280
static void xreset_default_properties(graphics_handle h, property_list::pval_map_type factory_pval)
Definition: graphics.cc:2858
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:719
static bool has_core_property(const caseless_str &pname)
static int process_events(void)
Definition: graphics.h:13931
bool is_integer_type(void) const
Definition: ov.h:664
static property_list::plist_map_type init_factory_properties(void)
Definition: graphics.cc:9805