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.in.h
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 (octave_graphics_h)
24 #define octave_graphics_h 1
25 
26 #include "octave-config.h"
27 
28 #include <cctype>
29 
30 #include <algorithm>
31 #include <list>
32 #include <map>
33 #include <set>
34 #include <sstream>
35 #include <string>
36 
37 #include "caseless-str.h"
38 
39 #include "errwarn.h"
40 #include "oct-handle.h"
41 #include "oct-map.h"
42 #include "oct-mutex.h"
43 #include "oct-refcount.h"
44 #include "ov.h"
45 #include "text-renderer.h"
46 
47 // FIXME: maybe this should be a configure option?
48 // Matlab defaults to "Helvetica", but that causes problems for many
49 // gnuplot users.
50 #if ! defined (OCTAVE_DEFAULT_FONTNAME)
51 #define OCTAVE_DEFAULT_FONTNAME "*"
52 #endif
53 
55 
56 // ---------------------------------------------------------------------
57 
58 class base_scaler
59 {
60 public:
61  base_scaler (void) { }
62 
63  virtual ~base_scaler (void) { }
64 
65  virtual Matrix scale (const Matrix&) const
66  {
67  error ("invalid axis scale");
68  }
69 
70  virtual NDArray scale (const NDArray&) const
71  {
72  error ("invalid axis scale");
73  }
74 
75  virtual double scale (double) const
76  {
77  error ("invalid axis scale");
78  }
79 
80  virtual double unscale (double) const
81  {
82  error ("invalid axis scale");
83  }
84 
85  virtual base_scaler* clone () const
86  { return new base_scaler (); }
87 
88  virtual bool is_linear (void) const
89  { return false; }
90 };
91 
92 class lin_scaler : public base_scaler
93 {
94 public:
95  lin_scaler (void) { }
96 
97  Matrix scale (const Matrix& m) const { return m; }
98 
99  NDArray scale (const NDArray& m) const { return m; }
100 
101  double scale (double d) const { return d; }
102 
103  double unscale (double d) const { return d; }
104 
105  base_scaler* clone (void) const { return new lin_scaler (); }
106 
107  bool is_linear (void) const { return true; }
108 };
109 
110 class log_scaler : public base_scaler
111 {
112 public:
113  log_scaler (void) { }
114 
115  Matrix scale (const Matrix& m) const
116  {
117  Matrix retval (m.rows (), m.cols ());
118 
119  do_scale (m.data (), retval.fortran_vec (), m.numel ());
120 
121  return retval;
122  }
123 
124  NDArray scale (const NDArray& m) const
125  {
126  NDArray retval (m.dims ());
127 
128  do_scale (m.data (), retval.fortran_vec (), m.numel ());
129 
130  return retval;
131  }
132 
133  double scale (double d) const
134  { return log10 (d); }
135 
136  double unscale (double d) const
137  { return pow (10.0, d); }
138 
139  base_scaler* clone (void) const
140  { return new log_scaler (); }
141 
142 private:
143  void do_scale (const double *src, double *dest, int n) const
144  {
145  for (int i = 0; i < n; i++)
146  dest[i] = log10 (src[i]);
147  }
148 };
149 
150 class neg_log_scaler : public base_scaler
151 {
152 public:
153  neg_log_scaler (void) { }
154 
155  Matrix scale (const Matrix& m) const
156  {
157  Matrix retval (m.rows (), m.cols ());
158 
159  do_scale (m.data (), retval.fortran_vec (), m.numel ());
160 
161  return retval;
162  }
163 
164  NDArray scale (const NDArray& m) const
165  {
166  NDArray retval (m.dims ());
167 
168  do_scale (m.data (), retval.fortran_vec (), m.numel ());
169 
170  return retval;
171  }
172 
173  double scale (double d) const
174  { return -log10 (-d); }
175 
176  double unscale (double d) const
177  { return -pow (10.0, -d); }
178 
179  base_scaler* clone (void) const
180  { return new neg_log_scaler (); }
181 
182 private:
183  void do_scale (const double *src, double *dest, int n) const
184  {
185  for (int i = 0; i < n; i++)
186  dest[i] = -log10 (-src[i]);
187  }
188 };
189 
190 class scaler
191 {
192 public:
193  scaler (void) : rep (new base_scaler ()) { }
194 
195  scaler (const scaler& s) : rep (s.rep->clone ()) { }
196 
198  : rep (s == "log"
199  ? new log_scaler ()
200  : (s == "neglog" ? new neg_log_scaler ()
201  : (s == "linear" ? new lin_scaler () : new base_scaler ())))
202  { }
203 
204  ~scaler (void) { delete rep; }
205 
206  Matrix scale (const Matrix& m) const
207  { return rep->scale (m); }
208 
209  NDArray scale (const NDArray& m) const
210  { return rep->scale (m); }
211 
212  double scale (double d) const
213  { return rep->scale (d); }
214 
215  double unscale (double d) const
216  { return rep->unscale (d); }
217 
218  bool is_linear (void) const
219  { return rep->is_linear (); }
220 
222  {
223  if (rep)
224  {
225  delete rep;
226  rep = 0;
227  }
228 
229  rep = s.rep->clone ();
230 
231  return *this;
232  }
233 
235  {
236  if (rep)
237  {
238  delete rep;
239  rep = 0;
240  }
241 
242  if (s == "log")
243  rep = new log_scaler ();
244  else if (s == "neglog")
245  rep = new neg_log_scaler ();
246  else if (s == "linear")
247  rep = new lin_scaler ();
248  else
249  rep = new base_scaler ();
250 
251  return *this;
252  }
253 
254 private:
255  base_scaler *rep;
256 };
257 
258 // ---------------------------------------------------------------------
259 
260 class property;
261 
263 
264 class base_property
265 {
266 public:
267  friend class property;
268 
269 public:
271  : id (-1), count (1), name (), parent (), hidden (), listeners ()
272  { }
273 
275  : id (-1), count (1), name (s), parent (h), hidden (false), listeners ()
276  { }
277 
279  : id (-1), count (1), name (p.name), parent (p.parent),
280  hidden (p.hidden), listeners ()
281  { }
282 
283  virtual ~base_property (void) { }
284 
285  bool ok (void) const { return parent.ok (); }
286 
287  std::string get_name (void) const { return name; }
288 
289  void set_name (const std::string& s) { name = s; }
290 
291  graphics_handle get_parent (void) const { return parent; }
292 
293  void set_parent (const graphics_handle& h) { parent = h; }
294 
295  bool is_hidden (void) const { return hidden; }
296 
297  void set_hidden (bool flag) { hidden = flag; }
298 
299  virtual bool is_radio (void) const { return false; }
300 
301  int get_id (void) const { return id; }
302 
303  void set_id (int d) { id = d; }
304 
305  // Sets property value, notifies graphics toolkit.
306  // If do_run is true, runs associated listeners.
307  OCTINTERP_API bool set (const octave_value& v, bool do_run = true,
308  bool do_notify_toolkit = true);
309 
310  virtual octave_value get (void) const
311  {
312  error ("get: invalid property \"%s\"", name.c_str ());
313  }
314 
315  virtual std::string values_as_string (void) const
316  {
317  error ("values_as_string: invalid property \"%s\"", name.c_str ());
318  }
319 
320  virtual Cell values_as_cell (void) const
321  {
322  error ("values_as_cell: invalid property \"%s\"", name.c_str ());
323  }
324 
326  {
327  set (val);
328  return *this;
329  }
330 
332  {
334  l.resize (l.length () + 1, v);
335  }
336 
339  {
341 
342  if (v.is_defined ())
343  {
344  bool found = false;
345  int i;
346 
347  for (i = 0; i < l.length (); i++)
348  {
349  if (v.internal_rep () == l(i).internal_rep ())
350  {
351  found = true;
352  break;
353  }
354  }
355  if (found)
356  {
357  for (int j = i; j < l.length () - 1; j++)
358  l(j) = l(j + 1);
359 
360  l.resize (l.length () - 1);
361  }
362  }
363  else
364  {
365  if (mode == PERSISTENT)
366  l.resize (0);
367  else
368  {
369  octave_value_list lnew (0);
371  for (int i = l.length () - 1; i >= 0 ; i--)
372  {
373  for (int j = 0; j < lp.length (); j++)
374  {
375  if (l(i).internal_rep () == lp(j).internal_rep ())
376  {
377  lnew.resize (lnew.length () + 1, l(i));
378  break;
379  }
380  }
381  }
382  l = lnew;
383  }
384  }
385 
386  }
387 
389 
390  virtual base_property* clone (void) const
391  { return new base_property (*this); }
392 
393 protected:
394  virtual bool do_set (const octave_value&)
395  {
396  error ("set: invalid property \"%s\"", name.c_str ());
397  }
398 
399 private:
400  typedef std::map<listener_mode, octave_value_list> listener_map;
401  typedef std::map<listener_mode, octave_value_list>::iterator
403  typedef std::map<listener_mode, octave_value_list>::const_iterator
405 
406 private:
407  int id;
411  bool hidden;
412  listener_map listeners;
413 };
414 
415 // ---------------------------------------------------------------------
416 
417 class string_property : public base_property
418 {
419 public:
421  const std::string& val = "")
422  : base_property (s, h), str (val) { }
423 
425  : base_property (p), str (p.str) { }
426 
427  octave_value get (void) const
428  { return octave_value (str); }
429 
430  std::string string_value (void) const { return str; }
431 
433  {
434  set (val);
435  return *this;
436  }
437 
438  base_property* clone (void) const { return new string_property (*this); }
439 
440 protected:
441  bool do_set (const octave_value& val)
442  {
443  if (! val.is_string ())
444  error ("set: invalid string property value for \"%s\"",
445  get_name ().c_str ());
446 
447  std::string new_str = val.string_value ();
448 
449  if (new_str != str)
450  {
451  str = new_str;
452  return true;
453  }
454  return false;
455  }
456 
457 private:
459 };
460 
461 // ---------------------------------------------------------------------
462 
464 {
465 public:
467 
469  const std::string& val = "", const char& sep = '|',
470  const desired_enum& typ = string_t)
471  : base_property (s, h), desired_type (typ), separator (sep), str ()
472  {
473  size_t pos = 0;
474 
475  while (true)
476  {
477  size_t new_pos = val.find_first_of (separator, pos);
478 
479  if (new_pos == std::string::npos)
480  {
481  str.append (val.substr (pos));
482  break;
483  }
484  else
485  str.append (val.substr (pos, new_pos - pos));
486 
487  pos = new_pos + 1;
488  }
489  }
490 
492  const Cell& c, const char& sep = '|',
493  const desired_enum& typ = string_t)
494  : base_property (s, h), desired_type (typ), separator (sep), str ()
495  {
496  if (! c.is_cellstr ())
497  error ("set: invalid order property value for \"%s\"",
498  get_name ().c_str ());
499 
500  string_vector strings (c.numel ());
501 
502  for (octave_idx_type i = 0; i < c.numel (); i++)
503  strings[i] = c(i).string_value ();
504 
505  str = strings;
506  }
507 
510  separator (p.separator), str (p.str) { }
511 
512  octave_value get (void) const
513  {
514  if (desired_type == string_t)
515  return octave_value (string_value ());
516  else
517  return octave_value (cell_value ());
518  }
519 
521  {
522  std::string s;
523 
524  for (octave_idx_type i = 0; i < str.numel (); i++)
525  {
526  s += str[i];
527  if (i != str.numel () - 1)
528  s += separator;
529  }
530 
531  return s;
532  }
533 
534  Cell cell_value (void) const {return Cell (str);}
535 
536  string_vector string_vector_value (void) const { return str; }
537 
539  {
540  set (val);
541  return *this;
542  }
543 
544  base_property* clone (void) const
545  { return new string_array_property (*this); }
546 
547 protected:
548  bool do_set (const octave_value& val)
549  {
550  if (val.is_string () && val.rows () == 1)
551  {
552  bool replace = false;
553  std::string new_str = val.string_value ();
554  string_vector strings;
555  size_t pos = 0;
556 
557  // Split single string on delimiter (usually '|')
558  while (pos != std::string::npos)
559  {
560  size_t new_pos = new_str.find_first_of (separator, pos);
561 
562  if (new_pos == std::string::npos)
563  {
564  strings.append (new_str.substr (pos));
565  break;
566  }
567  else
568  strings.append (new_str.substr (pos, new_pos - pos));
569 
570  pos = new_pos + 1;
571  }
572 
573  if (str.numel () == strings.numel ())
574  {
575  for (octave_idx_type i = 0; i < str.numel (); i++)
576  if (strings[i] != str[i])
577  {
578  replace = true;
579  break;
580  }
581  }
582  else
583  replace = true;
584 
586 
587  if (replace)
588  {
589  str = strings;
590  return true;
591  }
592  }
593  else if (val.is_string ()) // multi-row character matrix
594  {
595  bool replace = false;
596  charMatrix chm = val.char_matrix_value ();
597  octave_idx_type nel = chm.rows ();
598  string_vector strings (nel);
599 
600  if (nel != str.numel ())
601  replace = true;
602  for (octave_idx_type i = 0; i < nel; i++)
603  {
604  strings[i] = chm.row_as_string (i);
605  if (! replace && strings[i] != str[i])
606  replace = true;
607  }
608 
610 
611  if (replace)
612  {
613  str = strings;
614  return true;
615  }
616  }
617  else if (val.is_cellstr ())
618  {
619  bool replace = false;
620  Cell new_cell = val.cell_value ();
621 
622  string_vector strings = new_cell.cellstr_value ();
623 
624  octave_idx_type nel = strings.numel ();
625 
626  if (nel != str.numel ())
627  replace = true;
628  else
629  {
630  for (octave_idx_type i = 0; i < nel; i++)
631  {
632  if (strings[i] != str[i])
633  {
634  replace = true;
635  break;
636  }
637  }
638  }
639 
641 
642  if (replace)
643  {
644  str = strings;
645  return true;
646  }
647  }
648  else
649  error ("set: invalid string property value for \"%s\"",
650  get_name ().c_str ());
651 
652  return false;
653  }
654 
655 private:
657  char separator;
659 };
660 
661 // ---------------------------------------------------------------------
662 
663 class text_label_property : public base_property
664 {
665 public:
666  enum type { char_t, cellstr_t };
667 
669  const std::string& val = "")
670  : base_property (s, h), value (val), stored_type (char_t)
671  { }
672 
674  const NDArray& nda)
675  : base_property (s, h), stored_type (char_t)
676  {
677  octave_idx_type nel = nda.numel ();
678 
679  value.resize (nel);
680 
681  for (octave_idx_type i = 0; i < nel; i++)
682  {
683  std::ostringstream buf;
684  buf << nda(i);
685  value[i] = buf.str ();
686  }
687  }
688 
690  const Cell& c)
692  {
693  octave_idx_type nel = c.numel ();
694 
695  value.resize (nel);
696 
697  for (octave_idx_type i = 0; i < nel; i++)
698  {
699  octave_value tmp = c(i);
700 
701  if (tmp.is_string ())
702  value[i] = c(i).string_value ();
703  else
704  {
705  double d = c(i).double_value ();
706 
707  std::ostringstream buf;
708  buf << d;
709  value[i] = buf.str ();
710  }
711  }
712  }
713 
716  { }
717 
718  bool empty (void) const
719  {
720  octave_value tmp = get ();
721  return tmp.is_empty ();
722  }
723 
724  octave_value get (void) const
725  {
726  if (stored_type == char_t)
727  return octave_value (char_value ());
728  else
729  return octave_value (cell_value ());
730  }
731 
733  {
734  return value.empty () ? "" : value[0];
735  }
736 
737  string_vector string_vector_value (void) const { return value; }
738 
739  charMatrix char_value (void) const { return charMatrix (value, ' '); }
740 
741  Cell cell_value (void) const {return Cell (value); }
742 
744  {
745  set (val);
746  return *this;
747  }
748 
749  base_property* clone (void) const { return new text_label_property (*this); }
750 
751 protected:
752 
753  bool do_set (const octave_value& val)
754  {
755  if (val.is_string ())
756  {
757  value = val.string_vector_value ();
758 
760  }
761  else if (val.is_cell ())
762  {
763  Cell c = val.cell_value ();
764 
765  octave_idx_type nel = c.numel ();
766 
767  value.resize (nel);
768 
769  for (octave_idx_type i = 0; i < nel; i++)
770  {
771  octave_value tmp = c(i);
772 
773  if (tmp.is_string ())
774  value[i] = c(i).string_value ();
775  else
776  {
777  double d = c(i).double_value ();
778 
779  std::ostringstream buf;
780  buf << d;
781  value[i] = buf.str ();
782  }
783  }
784 
786  }
787  else
788  {
789  NDArray nda;
790 
791  try
792  {
793  nda = val.array_value ();
794  }
795  catch (octave::execution_exception& e)
796  {
797  error (e, "set: invalid string property value for \"%s\"",
798  get_name ().c_str ());
799  }
800 
801  octave_idx_type nel = nda.numel ();
802 
803  value.resize (nel);
804 
805  for (octave_idx_type i = 0; i < nel; i++)
806  {
807  std::ostringstream buf;
808  buf << nda(i);
809  value[i] = buf.str ();
810  }
811 
813  }
814 
815  return true;
816  }
817 
818 private:
821 };
822 
823 // ---------------------------------------------------------------------
824 
825 class radio_values
826 {
827 public:
828  OCTINTERP_API radio_values (const std::string& opt_string = "");
829 
832 
834  {
835  if (&a != this)
836  {
839  }
840 
841  return *this;
842  }
843 
844  std::string default_value (void) const { return default_val; }
845 
846  bool validate (const std::string& val, std::string& match)
847  {
848  bool retval = true;
849 
850  if (! contains (val, match))
851  error ("invalid value = %s", val.c_str ());
852 
853  return retval;
854  }
855 
856  bool contains (const std::string& val, std::string& match)
857  {
858  size_t k = 0;
859 
860  size_t len = val.length ();
861 
862  std::string first_match;
863 
864  for (const auto& possible_val : possible_vals)
865  {
866  if (possible_val.compare (val, len))
867  {
868  if (len == possible_val.length ())
869  {
870  // We found a full match (consider the case of val == "replace"
871  // with possible values "replace" and "replacechildren"). Any
872  // other matches are irrelevant, so set match and return now.
873  match = possible_val;
874  return true;
875  }
876  else
877  {
878  if (k == 0)
879  first_match = possible_val;
880 
881  k++;
882  }
883  }
884  }
885 
886  if (k == 1)
887  {
888  match = first_match;
889  return true;
890  }
891  else
892  return false;
893  }
894 
895  std::string values_as_string (void) const;
896 
897  Cell values_as_cell (void) const;
898 
899  octave_idx_type nelem (void) const { return possible_vals.size (); }
900 
901 private:
902  // Might also want to cache
904  std::set<caseless_str> possible_vals;
905 };
906 
907 class radio_property : public base_property
908 {
909 public:
911  const radio_values& v = radio_values ())
912  : base_property (nm, h),
913  vals (v), current_val (v.default_value ()) { }
914 
916  const std::string& v)
917  : base_property (nm, h),
918  vals (v), current_val (vals.default_value ()) { }
919 
921  const radio_values& v, const std::string& def)
922  : base_property (nm, h),
923  vals (v), current_val (def) { }
924 
926  : base_property (p), vals (p.vals), current_val (p.current_val) { }
927 
928  octave_value get (void) const { return octave_value (current_val); }
929 
930  const std::string& current_value (void) const { return current_val; }
931 
932  std::string values_as_string (void) const { return vals.values_as_string (); }
933 
934  Cell values_as_cell (void) const { return vals.values_as_cell (); }
935 
936  bool is (const caseless_str& v) const
937  { return v.compare (current_val); }
938 
939  bool is_radio (void) const { return true; }
940 
942  {
943  set (val);
944  return *this;
945  }
946 
947  base_property* clone (void) const { return new radio_property (*this); }
948 
949 protected:
950  bool do_set (const octave_value& newval)
951  {
952  if (! newval.is_string ())
953  error ("set: invalid value for radio property \"%s\"",
954  get_name ().c_str ());
955 
956  std::string s = newval.string_value ();
957 
958  std::string match;
959 
960  if (! vals.validate (s, match))
961  error ("set: invalid value for radio property \"%s\" (value = %s)",
962  get_name ().c_str (), s.c_str ());
963 
964  if (match != current_val)
965  {
966  if (s.length () != match.length ())
967  warning_with_id ("Octave:abbreviated-property-match",
968  "%s: allowing %s to match %s value %s",
969  "set", s.c_str (), get_name ().c_str (),
970  match.c_str ());
971  current_val = match;
972  return true;
973  }
974  return false;
975  }
976 
977 private:
980 };
981 
982 // ---------------------------------------------------------------------
983 
984 class color_values
985 {
986 public:
987  color_values (double r = 0, double g = 0, double b = 1)
988  : xrgb (1, 3)
989  {
990  xrgb(0) = r;
991  xrgb(1) = g;
992  xrgb(2) = b;
993 
994  validate ();
995  }
996 
998  : xrgb (1, 3)
999  {
1000  if (! str2rgb (str))
1001  error ("invalid color specification: %s", str.c_str ());
1002  }
1003 
1005  : xrgb (c.xrgb)
1006  { }
1007 
1009  {
1010  if (&c != this)
1011  xrgb = c.xrgb;
1012 
1013  return *this;
1014  }
1015 
1016  bool operator == (const color_values& c) const
1017  {
1018  return (xrgb(0) == c.xrgb(0)
1019  && xrgb(1) == c.xrgb(1)
1020  && xrgb(2) == c.xrgb(2));
1021  }
1022 
1023  bool operator != (const color_values& c) const
1024  { return ! (*this == c); }
1025 
1026  Matrix rgb (void) const { return xrgb; }
1027 
1028  operator octave_value (void) const { return xrgb; }
1029 
1030  void validate (void) const
1031  {
1032  for (int i = 0; i < 3; i++)
1033  {
1034  if (xrgb(i) < 0 || xrgb(i) > 1)
1035  error ("invalid RGB color specification");
1036  }
1037  }
1038 
1039 private:
1040  Matrix xrgb;
1041 
1042  OCTINTERP_API bool str2rgb (const std::string& str);
1043 };
1044 
1045 class color_property : public base_property
1046 {
1047 public:
1049  : base_property ("", graphics_handle ()),
1051  current_val (v.default_value ())
1052  { }
1053 
1055  : base_property ("", graphics_handle ()),
1057  current_val (v.default_value ())
1058  { }
1059 
1061  const color_values& c = color_values (),
1062  const radio_values& v = radio_values ())
1063  : base_property (nm, h),
1065  current_val (v.default_value ())
1066  { }
1067 
1069  const radio_values& v)
1070  : base_property (nm, h),
1072  current_val (v.default_value ())
1073  { }
1074 
1076  const std::string& v)
1077  : base_property (nm, h),
1079  current_val (radio_val.default_value ())
1080  { }
1081 
1083  const color_property& v)
1084  : base_property (nm, h),
1087  { }
1088 
1092  current_val (p.current_val) { }
1093 
1094  octave_value get (void) const
1095  {
1096  if (current_type == color_t)
1097  return color_val.rgb ();
1098 
1099  return current_val;
1100  }
1101 
1102  bool is_rgb (void) const { return (current_type == color_t); }
1103 
1104  bool is_radio (void) const { return (current_type == radio_t); }
1105 
1106  bool is (const std::string& v) const
1107  { return (is_radio () && current_val == v); }
1108 
1109  Matrix rgb (void) const
1110  {
1111  if (current_type != color_t)
1112  error ("color has no RGB value");
1113 
1114  return color_val.rgb ();
1115  }
1116 
1117  const std::string& current_value (void) const
1118  {
1119  if (current_type != radio_t)
1120  error ("color has no radio value");
1121 
1122  return current_val;
1123  }
1124 
1126  {
1127  set (val);
1128  return *this;
1129  }
1130 
1131  operator octave_value (void) const { return get (); }
1132 
1133  base_property* clone (void) const { return new color_property (*this); }
1134 
1136  { return radio_val.values_as_string (); }
1137 
1138  Cell values_as_cell (void) const { return radio_val.values_as_cell (); }
1139 
1140 protected:
1141  OCTINTERP_API bool do_set (const octave_value& newval);
1142 
1143 private:
1148 };
1149 
1150 // ---------------------------------------------------------------------
1151 
1152 class double_property : public base_property
1153 {
1154 public:
1156  double d = 0)
1157  : base_property (nm, h),
1158  current_val (d) { }
1159 
1161  : base_property (p), current_val (p.current_val) { }
1162 
1163  octave_value get (void) const { return octave_value (current_val); }
1164 
1165  double double_value (void) const { return current_val; }
1166 
1168  {
1169  set (val);
1170  return *this;
1171  }
1172 
1173  base_property* clone (void) const { return new double_property (*this); }
1174 
1175 protected:
1176  bool do_set (const octave_value& v)
1177  {
1178  if (! v.is_scalar_type () || ! v.is_real_type ())
1179  error ("set: invalid value for double property \"%s\"",
1180  get_name ().c_str ());
1181 
1182  double new_val = v.double_value ();
1183 
1184  if (new_val != current_val)
1185  {
1186  current_val = new_val;
1187  return true;
1188  }
1189 
1190  return false;
1191  }
1192 
1193 private:
1194  double current_val;
1195 };
1196 
1197 // ---------------------------------------------------------------------
1198 
1199 class double_radio_property : public base_property
1200 {
1201 public:
1203  : base_property ("", graphics_handle ()),
1204  current_type (double_t), dval (d), radio_val (v),
1205  current_val (v.default_value ())
1206  { }
1207 
1209  const std::string& v)
1210  : base_property (nm, h),
1211  current_type (radio_t), dval (0), radio_val (v),
1212  current_val (radio_val.default_value ())
1213  { }
1214 
1216  const double_radio_property& v)
1217  : base_property (nm, h),
1220  { }
1221 
1224  dval (p.dval), radio_val (p.radio_val),
1225  current_val (p.current_val) { }
1226 
1227  octave_value get (void) const
1228  {
1229  if (current_type == double_t)
1230  return dval;
1231 
1232  return current_val;
1233  }
1234 
1235  bool is_double (void) const { return (current_type == double_t); }
1236 
1237  bool is_radio (void) const { return (current_type == radio_t); }
1238 
1239  bool is (const std::string& v) const
1240  { return (is_radio () && current_val == v); }
1241 
1242  double double_value (void) const
1243  {
1244  if (current_type != double_t)
1245  error ("%s: property has no double", get_name ().c_str ());
1246 
1247  return dval;
1248  }
1249 
1250  const std::string& current_value (void) const
1251  {
1252  if (current_type != radio_t)
1253  error ("%s: property has no radio value");
1254 
1255  return current_val;
1256  }
1257 
1259  {
1260  set (val);
1261  return *this;
1262  }
1263 
1264  operator octave_value (void) const { return get (); }
1265 
1266  base_property* clone (void) const
1267  { return new double_radio_property (*this); }
1268 
1269 protected:
1270  OCTINTERP_API bool do_set (const octave_value& v);
1271 
1272 private:
1274  double dval;
1277 };
1278 
1279 // ---------------------------------------------------------------------
1280 
1281 class array_property : public base_property
1282 {
1283 public:
1285  : base_property ("", graphics_handle ()), data (Matrix ()),
1286  xmin (), xmax (), xminp (), xmaxp (),
1288  {
1289  get_data_limits ();
1290  }
1291 
1293  const octave_value& m)
1294  : base_property (nm, h), data (m.is_sparse_type () ? m.full_value () : m),
1295  xmin (), xmax (), xminp (), xmaxp (),
1297  {
1298  get_data_limits ();
1299  }
1300 
1301  // This copy constructor is only intended to be used
1302  // internally to access min/max values; no need to
1303  // copy constraints.
1305  : base_property (p), data (p.data),
1306  xmin (p.xmin), xmax (p.xmax), xminp (p.xminp), xmaxp (p.xmaxp),
1308  { }
1309 
1310  octave_value get (void) const { return data; }
1311 
1313  { type_constraints.insert (type); }
1314 
1316  { size_constraints.push_back (dims); }
1317 
1318  double min_val (void) const { return xmin; }
1319  double max_val (void) const { return xmax; }
1320  double min_pos (void) const { return xminp; }
1321  double max_neg (void) const { return xmaxp; }
1322 
1323  Matrix get_limits (void) const
1324  {
1325  Matrix m (1, 4);
1326 
1327  m(0) = min_val ();
1328  m(1) = max_val ();
1329  m(2) = min_pos ();
1330  m(3) = max_neg ();
1331 
1332  return m;
1333  }
1334 
1336  {
1337  set (val);
1338  return *this;
1339  }
1340 
1341  base_property* clone (void) const
1342  {
1343  array_property *p = new array_property (*this);
1344 
1347 
1348  return p;
1349  }
1350 
1351 protected:
1352  bool do_set (const octave_value& v)
1353  {
1354  octave_value tmp = v.is_sparse_type () ? v.full_value () : v;
1355 
1356  if (! validate (tmp))
1357  error ("invalid value for array property \"%s\"",
1358  get_name ().c_str ());
1359 
1360  // FIXME: should we check for actual data change?
1361  if (! is_equal (tmp))
1362  {
1363  data = tmp;
1364 
1365  get_data_limits ();
1366 
1367  return true;
1368  }
1369 
1370  return false;
1371  }
1372 
1373 private:
1374  OCTINTERP_API bool validate (const octave_value& v);
1375 
1376  OCTINTERP_API bool is_equal (const octave_value& v) const;
1377 
1378  OCTINTERP_API void get_data_limits (void);
1379 
1380 protected:
1382  double xmin;
1383  double xmax;
1384  double xminp;
1385  double xmaxp;
1386  std::set<std::string> type_constraints;
1387  std::list<dim_vector> size_constraints;
1388 };
1389 
1390 class row_vector_property : public array_property
1391 {
1392 public:
1394  const octave_value& m)
1395  : array_property (nm, h, m)
1396  {
1397  add_constraint (dim_vector (-1, 1));
1398  add_constraint (dim_vector (1, -1));
1399  add_constraint (dim_vector (0, 0));
1400  }
1401 
1403  : array_property (p)
1404  {
1405  add_constraint (dim_vector (-1, 1));
1406  add_constraint (dim_vector (1, -1));
1407  add_constraint (dim_vector (0, 0));
1408  }
1409 
1411  {
1413  }
1414 
1416  {
1418  }
1419 
1421  {
1422  size_constraints.remove (dim_vector (1, -1));
1423  size_constraints.remove (dim_vector (-1, 1));
1424  size_constraints.remove (dim_vector (0, 0));
1425 
1426  add_constraint (dim_vector (1, len));
1427  add_constraint (dim_vector (len, 1));
1428  }
1429 
1431  {
1432  set (val);
1433  return *this;
1434  }
1435 
1436  base_property* clone (void) const
1437  {
1438  row_vector_property *p = new row_vector_property (*this);
1439 
1442 
1443  return p;
1444  }
1445 
1446 protected:
1447  bool do_set (const octave_value& v)
1448  {
1449  bool retval = array_property::do_set (v);
1450 
1451  dim_vector dv = data.dims ();
1452 
1453  if (dv(0) > 1 && dv(1) == 1)
1454  {
1455  int tmp = dv(0);
1456  dv(0) = dv(1);
1457  dv(1) = tmp;
1458 
1459  data = data.reshape (dv);
1460  }
1461 
1462  return retval;
1463  }
1464 
1465 private:
1466  OCTINTERP_API bool validate (const octave_value& v);
1467 };
1468 
1469 // ---------------------------------------------------------------------
1470 
1471 class bool_property : public radio_property
1472 {
1473 public:
1475  bool val)
1476  : radio_property (nm, h, radio_values (val ? "{on}|off" : "on|{off}"))
1477  { }
1478 
1480  const char* val)
1481  : radio_property (nm, h, radio_values ("on|off"), val)
1482  { }
1483 
1485  : radio_property (p) { }
1486 
1487  bool is_on (void) const { return is ("on"); }
1488 
1490  {
1491  set (val);
1492  return *this;
1493  }
1494 
1495  base_property* clone (void) const { return new bool_property (*this); }
1496 
1497 protected:
1498  bool do_set (const octave_value& val)
1499  {
1500  if (val.is_bool_scalar ())
1501  return radio_property::do_set (val.bool_value () ? "on" : "off");
1502  else
1503  return radio_property::do_set (val);
1504  }
1505 };
1506 
1507 // ---------------------------------------------------------------------
1508 
1509 class handle_property : public base_property
1510 {
1511 public:
1513  const graphics_handle& val = graphics_handle ())
1514  : base_property (nm, h),
1515  current_val (val) { }
1516 
1518  : base_property (p), current_val (p.current_val) { }
1519 
1520  octave_value get (void) const { return current_val.as_octave_value (); }
1521 
1522  graphics_handle handle_value (void) const { return current_val; }
1523 
1525  {
1526  set (val);
1527  return *this;
1528  }
1529 
1531  {
1532  set (octave_value (h.value ()));
1533  return *this;
1534  }
1535 
1537 
1538  base_property* clone (void) const { return new handle_property (*this); }
1539 
1540 protected:
1541  OCTINTERP_API bool do_set (const octave_value& v);
1542 
1543 private:
1545 };
1546 
1547 // ---------------------------------------------------------------------
1548 
1549 class any_property : public base_property
1550 {
1551 public:
1553  const octave_value& m = Matrix ())
1554  : base_property (nm, h), data (m) { }
1555 
1557  : base_property (p), data (p.data) { }
1558 
1559  octave_value get (void) const { return data; }
1560 
1562  {
1563  set (val);
1564  return *this;
1565  }
1566 
1567  base_property* clone (void) const { return new any_property (*this); }
1568 
1569 protected:
1570  bool do_set (const octave_value& v)
1571  {
1572  data = v;
1573  return true;
1574  }
1575 
1576 private:
1578 };
1579 
1580 // ---------------------------------------------------------------------
1581 
1582 class children_property : public base_property
1583 {
1584 public:
1587  {
1588  do_init_children (Matrix ());
1589  }
1590 
1592  const Matrix& val)
1593  : base_property (nm, h), children_list ()
1594  {
1595  do_init_children (val);
1596  }
1597 
1599  : base_property (p), children_list ()
1600  {
1602  }
1603 
1605  {
1606  set (val);
1607  return *this;
1608  }
1609 
1610  base_property* clone (void) const { return new children_property (*this); }
1611 
1612  bool remove_child (double val)
1613  {
1614  return do_remove_child (val);
1615  }
1616 
1617  void adopt (double val)
1618  {
1619  do_adopt_child (val);
1620  }
1621 
1622  Matrix get_children (void) const
1623  {
1624  return do_get_children (false);
1625  }
1626 
1627  Matrix get_hidden (void) const
1628  {
1629  return do_get_children (true);
1630  }
1631 
1632  Matrix get_all (void) const
1633  {
1634  return do_get_all_children ();
1635  }
1636 
1637  octave_value get (void) const
1638  {
1639  return octave_value (get_children ());
1640  }
1641 
1642  void delete_children (bool clear = false)
1643  {
1645  }
1646 
1648  {
1649  for (auto& hchild : children_list)
1650  {
1651  if (hchild == old_gh)
1652  {
1653  hchild = new_gh.value ();
1654  return;
1655  }
1656  }
1657 
1658  error ("children_list::renumber: child not found!");
1659  }
1660 
1661 private:
1662  typedef std::list<double>::iterator children_list_iterator;
1663  typedef std::list<double>::const_iterator const_children_list_iterator;
1664  std::list<double> children_list;
1665 
1666 protected:
1667  bool do_set (const octave_value& val)
1668  {
1669  Matrix new_kids;
1670 
1671  try
1672  {
1673  new_kids = val.matrix_value ();
1674  }
1675  catch (octave::execution_exception& e)
1676  {
1677  error (e, "set: children must be an array of graphics handles");
1678  }
1679 
1680  octave_idx_type nel = new_kids.numel ();
1681 
1682  const Matrix new_kids_column = new_kids.reshape (dim_vector (nel, 1));
1683 
1684  bool is_ok = true;
1685  bool add_hidden = true;
1686 
1687  const Matrix visible_kids = do_get_children (false);
1688 
1689  if (visible_kids.numel () == new_kids.numel ())
1690  {
1691  Matrix t1 = visible_kids.sort ();
1692  Matrix t2 = new_kids_column.sort ();
1693  Matrix t3 = get_hidden ().sort ();
1694 
1695  if (t1 != t2)
1696  is_ok = false;
1697 
1698  if (t1 == t3)
1699  add_hidden = false;
1700  }
1701  else
1702  is_ok = false;
1703 
1704  if (! is_ok)
1705  error ("set: new children must be a permutation of existing children");
1706 
1707  if (is_ok)
1708  {
1709  Matrix tmp = new_kids_column;
1710 
1711  if (add_hidden)
1712  tmp.stack (get_hidden ());
1713 
1714  children_list.clear ();
1715 
1716  // Don't use do_init_children here, as that reverses the
1717  // order of the list, and we don't want to do that if setting
1718  // the child list directly.
1719 
1720  for (octave_idx_type i = 0; i < tmp.numel (); i++)
1721  children_list.push_back (tmp.xelem (i));
1722  }
1723 
1724  return is_ok;
1725  }
1726 
1727 private:
1729  {
1730  children_list.clear ();
1731  for (octave_idx_type i = 0; i < val.numel (); i++)
1732  children_list.push_front (val.xelem (i));
1733  }
1734 
1735  void do_init_children (const std::list<double>& val)
1736  {
1737  children_list.clear ();
1738  children_list = val;
1739  }
1740 
1741  Matrix do_get_children (bool return_hidden) const;
1742 
1744  {
1745  Matrix retval (children_list.size (), 1);
1746  octave_idx_type i = 0;
1747 
1748  for (const auto& hchild : children_list)
1749  retval(i++) = hchild;
1750 
1751  return retval;
1752  }
1753 
1754  bool do_remove_child (double child)
1755  {
1756  for (auto it = children_list.begin (); it != children_list.end (); it++)
1757  {
1758  if (*it == child)
1759  {
1760  children_list.erase (it);
1761  return true;
1762  }
1763  }
1764  return false;
1765  }
1766 
1767  void do_adopt_child (double val)
1768  {
1769  children_list.push_front (val);
1770  }
1771 
1772  void do_delete_children (bool clear);
1773 };
1774 
1775 // ---------------------------------------------------------------------
1776 
1777 class callback_property : public base_property
1778 {
1779 public:
1781  const octave_value& m)
1782  : base_property (nm, h), callback (m), executing (false) { }
1783 
1785  : base_property (p), callback (p.callback), executing (false) { }
1786 
1787  octave_value get (void) const { return callback; }
1788 
1789  OCTINTERP_API void execute (const octave_value& data = octave_value ()) const;
1790 
1791  bool is_defined (void) const
1792  {
1793  return (callback.is_defined () && ! callback.is_empty ());
1794  }
1795 
1797  {
1798  set (val);
1799  return *this;
1800  }
1801 
1802  base_property* clone (void) const { return new callback_property (*this); }
1803 
1804 protected:
1805  bool do_set (const octave_value& v)
1806  {
1807  if (! validate (v))
1808  error ("invalid value for callback property \"%s\"",
1809  get_name ().c_str ());
1810 
1811  callback = v;
1812  return true;
1813  return false;
1814  }
1815 
1816 private:
1817  OCTINTERP_API bool validate (const octave_value& v) const;
1818 
1819 private:
1821 
1822  // If TRUE, we are executing this callback.
1823  mutable bool executing;
1824 };
1825 
1826 // ---------------------------------------------------------------------
1827 
1828 class property
1829 {
1830 public:
1831  property (void) : rep (new base_property ("", graphics_handle ()))
1832  { }
1833 
1834  property (base_property *bp, bool persist = false) : rep (bp)
1835  { if (persist) rep->count++; }
1836 
1837  property (const property& p) : rep (p.rep)
1838  {
1839  rep->count++;
1840  }
1841 
1842  ~property (void)
1843  {
1844  if (--rep->count == 0)
1845  delete rep;
1846  }
1847 
1848  bool ok (void) const
1849  { return rep->ok (); }
1850 
1851  std::string get_name (void) const
1852  { return rep->get_name (); }
1853 
1854  void set_name (const std::string& name)
1855  { rep->set_name (name); }
1856 
1858  { return rep->get_parent (); }
1859 
1860  void set_parent (const graphics_handle& h)
1861  { rep->set_parent (h); }
1862 
1863  bool is_hidden (void) const
1864  { return rep->is_hidden (); }
1865 
1866  void set_hidden (bool flag)
1867  { rep->set_hidden (flag); }
1868 
1869  bool is_radio (void) const
1870  { return rep->is_radio (); }
1871 
1872  int get_id (void) const
1873  { return rep->get_id (); }
1874 
1875  void set_id (int d)
1876  { rep->set_id (d); }
1877 
1878  octave_value get (void) const
1879  { return rep->get (); }
1880 
1881  bool set (const octave_value& val, bool do_run = true,
1882  bool do_notify_toolkit = true)
1883  { return rep->set (val, do_run, do_notify_toolkit); }
1884 
1886  { return rep->values_as_string (); }
1887 
1888  Cell values_as_cell (void) const
1889  { return rep->values_as_cell (); }
1890 
1891  property& operator = (const octave_value& val)
1892  {
1893  *rep = val;
1894  return *this;
1895  }
1896 
1897  property& operator = (const property& p)
1898  {
1899  if (rep && --rep->count == 0)
1900  delete rep;
1901 
1902  rep = p.rep;
1903  rep->count++;
1904 
1905  return *this;
1906  }
1907 
1909  { rep->add_listener (v, mode); }
1910 
1913  { rep->delete_listener (v, mode); }
1914 
1916  { rep->run_listeners (mode); }
1917 
1918  OCTINTERP_API static
1919  property create (const std::string& name, const graphics_handle& parent,
1920  const caseless_str& type,
1921  const octave_value_list& args);
1922 
1923  property clone (void) const
1924  { return property (rep->clone ()); }
1925 
1926 #if 0
1927  const string_property& as_string_property (void) const
1928  { return *(dynamic_cast<string_property*> (rep)); }
1929 
1930  const radio_property& as_radio_property (void) const
1931  { return *(dynamic_cast<radio_property*> (rep)); }
1932 
1933  const color_property& as_color_property (void) const
1934  { return *(dynamic_cast<color_property*> (rep)); }
1935 
1936  const double_property& as_double_property (void) const
1937  { return *(dynamic_cast<double_property*> (rep)); }
1938 
1939  const bool_property& as_bool_property (void) const
1940  { return *(dynamic_cast<bool_property*> (rep)); }
1941 
1942  const handle_property& as_handle_property (void) const
1943  { return *(dynamic_cast<handle_property*> (rep)); }
1944 #endif
1945 
1946 private:
1947  base_property *rep;
1948 };
1949 
1950 // ---------------------------------------------------------------------
1951 
1952 typedef std::pair<std::string, octave_value> pval_pair;
1953 
1954 class pval_vector : public std::vector<pval_pair>
1955 {
1956 public:
1957  const_iterator find (const std::string pname) const
1958  {
1959  const_iterator it;
1960 
1961  for (it = (*this).begin (); it != (*this).end (); it++)
1962  if (pname == (*it).first)
1963  return it;
1964 
1965  return (*this).end ();
1966  }
1967 
1968  iterator find (const std::string pname)
1969  {
1970  iterator it;
1971 
1972  for (it = (*this).begin (); it != (*this).end (); it++)
1973  if (pname == (*it).first)
1974  return it;
1975 
1976  return (*this).end ();
1977  }
1978 
1980  {
1982 
1983  const_iterator it = find (pname);
1984 
1985  if (it != (*this).end ())
1986  retval = (*it).second;
1987 
1988  return retval;
1989  }
1990 
1992  {
1993  iterator it = find (pname);
1994 
1995  if (it == (*this).end ())
1996  {
1997  push_back (pval_pair (pname, octave_value ()));
1998  return (*this).back ().second;
1999  }
2000 
2001  return (*it).second;
2002  }
2003 
2004  void erase (const std::string pname)
2005  {
2006  iterator it = find (pname);
2007  if (it != (*this).end ())
2008  erase (it);
2009  }
2010 
2011  void erase (iterator it)
2012  {
2013  std::vector<pval_pair>::erase (it);
2014  }
2015 
2016 };
2017 
2018 class property_list
2019 {
2020 public:
2022  typedef std::map<std::string, pval_map_type> plist_map_type;
2023 
2024  typedef pval_map_type::iterator pval_map_iterator;
2025  typedef pval_map_type::const_iterator pval_map_const_iterator;
2026 
2027  typedef plist_map_type::iterator plist_map_iterator;
2028  typedef plist_map_type::const_iterator plist_map_const_iterator;
2029 
2030  property_list (const plist_map_type& m = plist_map_type ())
2031  : plist_map (m) { }
2032 
2033  ~property_list (void) { }
2034 
2035  void set (const caseless_str& name, const octave_value& val);
2036 
2037  octave_value lookup (const caseless_str& name) const;
2038 
2039  plist_map_iterator begin (void) { return plist_map.begin (); }
2040  plist_map_const_iterator begin (void) const { return plist_map.begin (); }
2041 
2042  plist_map_iterator end (void) { return plist_map.end (); }
2043  plist_map_const_iterator end (void) const { return plist_map.end (); }
2044 
2045  plist_map_iterator find (const std::string& go_name)
2046  {
2047  return plist_map.find (go_name);
2048  }
2049 
2050  plist_map_const_iterator find (const std::string& go_name) const
2051  {
2052  return plist_map.find (go_name);
2053  }
2054 
2055  octave_scalar_map as_struct (const std::string& prefix_arg) const;
2056 
2057 private:
2058  plist_map_type plist_map;
2059 };
2060 
2061 // ---------------------------------------------------------------------
2062 
2063 class graphics_toolkit;
2064 class graphics_object;
2065 
2067 {
2068 public:
2069  friend class graphics_toolkit;
2070 
2071 public:
2073  : name (nm), count (0) { }
2074 
2075  virtual ~base_graphics_toolkit (void) { }
2076 
2077  std::string get_name (void) const { return name; }
2078 
2079  virtual bool is_valid (void) const { return false; }
2080 
2081  virtual void redraw_figure (const graphics_object&) const
2082  { gripe_if_tkit_invalid ("redraw_figure"); }
2083 
2084  virtual void print_figure (const graphics_object&, const std::string&,
2085  const std::string&,
2086  const std::string& = "") const
2087  { gripe_if_tkit_invalid ("print_figure"); }
2088 
2089  virtual Matrix get_canvas_size (const graphics_handle&) const
2090  {
2091  gripe_if_tkit_invalid ("get_canvas_size");
2092  return Matrix (1, 2, 0.0);
2093  }
2094 
2095  virtual double get_screen_resolution (void) const
2096  {
2097  gripe_if_tkit_invalid ("get_screen_resolution");
2098  return 72.0;
2099  }
2100 
2101  virtual Matrix get_screen_size (void) const
2102  {
2103  gripe_if_tkit_invalid ("get_screen_size");
2104  return Matrix (1, 2, 0.0);
2105  }
2106 
2107  // Callback function executed when the given graphics object
2108  // changes. This allows the graphics toolkit to act on property
2109  // changes if needed.
2110  virtual void update (const graphics_object&, int)
2111  { gripe_if_tkit_invalid ("base_graphics_toolkit::update"); }
2112 
2113  void update (const graphics_handle&, int);
2114 
2115  // Callback function executed when the given graphics object is
2116  // created. This allows the graphics toolkit to do toolkit-specific
2117  // initializations for a newly created object.
2118  virtual bool initialize (const graphics_object&)
2119  {
2120  gripe_if_tkit_invalid ("base_graphics_toolkit::initialize");
2121  return false;
2122  }
2123 
2124  bool initialize (const graphics_handle&);
2125 
2126  // Callback function executed just prior to deleting the given
2127  // graphics object. This allows the graphics toolkit to perform
2128  // toolkit-specific cleanup operations before an object is deleted.
2129  virtual void finalize (const graphics_object&)
2130  { gripe_if_tkit_invalid ("base_graphics_toolkit::finalize"); }
2131 
2132  void finalize (const graphics_handle&);
2133 
2134  // Close the graphics toolkit.
2135  virtual void close (void)
2136  { gripe_if_tkit_invalid ("base_graphics_toolkit::close"); }
2137 
2138 private:
2139  std::string name;
2141 
2142 private:
2144  {
2145  if (! is_valid ())
2146  error ("%s: invalid graphics toolkit", fname.c_str ());
2147  }
2148 };
2149 
2150 class graphics_toolkit
2151 {
2152 public:
2154  : rep (new base_graphics_toolkit ("unknown"))
2155  {
2156  rep->count++;
2157  }
2158 
2160  : rep (b)
2161  {
2162  rep->count++;
2163  }
2164 
2166  : rep (b.rep)
2167  {
2168  rep->count++;
2169  }
2170 
2172  {
2173  if (--rep->count == 0)
2174  delete rep;
2175  }
2176 
2178  {
2179  if (rep != b.rep)
2180  {
2181  if (--rep->count == 0)
2182  delete rep;
2183 
2184  rep = b.rep;
2185  rep->count++;
2186  }
2187 
2188  return *this;
2189  }
2190 
2191  operator bool (void) const { return rep->is_valid (); }
2192 
2193  std::string get_name (void) const { return rep->get_name (); }
2194 
2195  void redraw_figure (const graphics_object& go) const
2196  { rep->redraw_figure (go); }
2197 
2198  void print_figure (const graphics_object& go, const std::string& term,
2199  const std::string& file,
2200  const std::string& debug_file = "") const
2201  { rep->print_figure (go, term, file, debug_file); }
2202 
2204  { return rep->get_canvas_size (fh); }
2205 
2206  double get_screen_resolution (void) const
2207  { return rep->get_screen_resolution (); }
2208 
2210  { return rep->get_screen_size (); }
2211 
2212  // Notifies graphics toolkit that object't property has changed.
2213  void update (const graphics_object& go, int id)
2214  { rep->update (go, id); }
2215 
2216  void update (const graphics_handle& h, int id)
2217  { rep->update (h, id); }
2218 
2219  // Notifies graphics toolkit that new object was created.
2220  bool initialize (const graphics_object& go)
2221  { return rep->initialize (go); }
2222 
2223  bool initialize (const graphics_handle& h)
2224  { return rep->initialize (h); }
2225 
2226  // Notifies graphics toolkit that object was destroyed.
2227  // This is called only for explicitly deleted object.
2228  // Children are deleted implicitly and graphics toolkit isn't notified.
2229  void finalize (const graphics_object& go)
2230  { rep->finalize (go); }
2231 
2232  void finalize (const graphics_handle& h)
2233  { rep->finalize (h); }
2234 
2235  // Close the graphics toolkit.
2236  void close (void) { rep->close (); }
2237 
2238 private:
2239 
2241 };
2242 
2243 class gtk_manager
2244 {
2245 public:
2246 
2248  {
2249  return instance_ok () ? instance->do_get_toolkit () : graphics_toolkit ();
2250  }
2251 
2252  static void register_toolkit (const std::string& name)
2253  {
2254  if (instance_ok ())
2255  instance->do_register_toolkit (name);
2256  }
2257 
2258  static void unregister_toolkit (const std::string& name)
2259  {
2260  if (instance_ok ())
2262  }
2263 
2264  static void load_toolkit (const graphics_toolkit& tk)
2265  {
2266  if (instance_ok ())
2267  instance->do_load_toolkit (tk);
2268  }
2269 
2270  static void unload_toolkit (const std::string& name)
2271  {
2272  if (instance_ok ())
2273  instance->do_unload_toolkit (name);
2274  }
2275 
2277  {
2278  return instance_ok ()
2279  ? instance->do_find_toolkit (name) : graphics_toolkit ();
2280  }
2281 
2283  {
2284  return instance_ok () ? instance->do_available_toolkits_list () : Cell ();
2285  }
2286 
2288  {
2289  return instance_ok () ? instance->do_loaded_toolkits_list () : Cell ();
2290  }
2291 
2292  static void unload_all_toolkits (void)
2293  {
2294  if (instance_ok ())
2296  }
2297 
2299  {
2300  return instance_ok () ? instance->do_default_toolkit () : "";
2301  }
2302 
2303 private:
2304 
2305  gtk_manager (void) { }
2306 
2307  ~gtk_manager (void) { }
2308 
2309  OCTINTERP_API static void create_instance (void);
2310 
2311  static bool instance_ok (void)
2312  {
2313  bool retval = true;
2314 
2315  if (! instance)
2316  create_instance ();
2317 
2318  if (! instance)
2319  error ("unable to create gh_manager!");
2320 
2321  return retval;
2322  }
2323 
2324  static void cleanup_instance (void) { delete instance; instance = 0; }
2325 
2327 
2328  // The name of the default toolkit.
2329  std::string dtk;
2330 
2331  // The list of toolkits that we know about.
2332  std::set<std::string> available_toolkits;
2333 
2334  // The list of toolkits we have actually loaded.
2335  std::map<std::string, graphics_toolkit> loaded_toolkits;
2336 
2337  typedef std::set<std::string>::iterator available_toolkits_iterator;
2338 
2339  typedef std::set<std::string>::const_iterator
2341 
2342  typedef std::map<std::string, graphics_toolkit>::iterator
2344 
2345  typedef std::map<std::string, graphics_toolkit>::const_iterator
2347 
2348  graphics_toolkit do_get_toolkit (void) const;
2349 
2350  void do_register_toolkit (const std::string& name);
2351 
2352  void do_unregister_toolkit (const std::string& name);
2353 
2355  {
2356  loaded_toolkits[tk.get_name ()] = tk;
2357  }
2358 
2360  {
2361  loaded_toolkits.erase (name);
2362  }
2363 
2365  {
2366  const_loaded_toolkits_iterator p = loaded_toolkits.find (name);
2367 
2368  if (p != loaded_toolkits.end ())
2369  return p->second;
2370  else
2371  return graphics_toolkit ();
2372  }
2373 
2375  {
2376  Cell m (1, available_toolkits.size ());
2377 
2378  octave_idx_type i = 0;
2379  for (const auto& tkit : available_toolkits)
2380  m(i++) = tkit;
2381 
2382  return m;
2383  }
2384 
2386  {
2387  Cell m (1, loaded_toolkits.size ());
2388 
2389  octave_idx_type i = 0;
2390  for (const auto& nm_tkit_p : loaded_toolkits)
2391  m(i++) = nm_tkit_p.first;
2392 
2393  return m;
2394  }
2395 
2397  {
2398  while (! loaded_toolkits.empty ())
2399  {
2400  loaded_toolkits_iterator p = loaded_toolkits.begin ();
2401 
2402  std::string name = p->first;
2403 
2404  p->second.close ();
2405 
2406  // The toolkit may have unloaded itself. If not, we'll do it here.
2407  if (loaded_toolkits.find (name) != loaded_toolkits.end ())
2408  unload_toolkit (name);
2409  }
2410  }
2411 
2413 };
2414 
2415 // ---------------------------------------------------------------------
2416 
2417 class base_graphics_object;
2418 class graphics_object;
2419 
2421 {
2422 public:
2423  base_properties (const std::string& ty = "unknown",
2424  const graphics_handle& mh = graphics_handle (),
2425  const graphics_handle& p = graphics_handle ());
2426 
2427  virtual ~base_properties (void) { }
2428 
2429  virtual std::string graphics_object_name (void) const { return "unknown"; }
2430 
2431  void mark_modified (void);
2432 
2433  void override_defaults (base_graphics_object& obj);
2434 
2435  virtual void init_integerhandle (const octave_value&)
2436  {
2437  panic_impossible ();
2438  }
2439 
2440  // Look through DEFAULTS for properties with given CLASS_NAME, and
2441  // apply them to the current object with set (virtual method).
2442 
2443  void set_from_list (base_graphics_object& obj, property_list& defaults);
2444 
2446  {
2447  p.set_name (name);
2448  p.set_parent (__myhandle__);
2449  all_props[name] = p;
2450  }
2451 
2452  virtual void set (const caseless_str&, const octave_value&);
2453 
2454  virtual octave_value get (const caseless_str& pname) const;
2455 
2456  virtual octave_value get (const std::string& pname) const
2457  {
2458  return get (caseless_str (pname));
2459  }
2460 
2461  virtual octave_value get (const char *pname) const
2462  {
2463  return get (caseless_str (pname));
2464  }
2465 
2466  virtual octave_value get (bool all = false) const;
2467 
2468  virtual property get_property (const caseless_str& pname);
2469 
2470  virtual bool has_property (const caseless_str&) const
2471  {
2472  panic_impossible ();
2473  return false;
2474  }
2475 
2476  bool is_modified (void) const { return is___modified__ (); }
2477 
2478  virtual void remove_child (const graphics_handle& h)
2479  {
2480  if (children.remove_child (h.value ()))
2481  {
2482  children.run_listeners ();
2483  mark_modified ();
2484  }
2485  }
2486 
2487  virtual void adopt (const graphics_handle& h)
2488  {
2489  children.adopt (h.value ());
2490  children.run_listeners ();
2491  mark_modified ();
2492  }
2493 
2494  virtual graphics_toolkit get_toolkit (void) const;
2495 
2496  virtual Matrix
2497  get_boundingbox (bool /* finternal */ = false,
2498  const Matrix& /* parent_pix_size */ = Matrix ()) const
2499  { return Matrix (1, 4, 0.0); }
2500 
2501  virtual void update_boundingbox (void);
2502 
2503  virtual void update_autopos (const std::string& elem_type);
2504 
2505  virtual void add_listener (const caseless_str&, const octave_value&,
2507 
2508  virtual void delete_listener (const caseless_str&, const octave_value&,
2510 
2511  void set_tag (const octave_value& val) { tag = val; }
2512 
2513  void set_parent (const octave_value& val);
2514 
2515  Matrix get_children (void) const
2516  {
2517  return children.get_children ();
2518  }
2519 
2521  {
2522  return children.get_all ();
2523  }
2524 
2526  {
2527  return children.get_hidden ();
2528  }
2529 
2530  void set_modified (const octave_value& val) { set___modified__ (val); }
2531 
2532  void set___modified__ (const octave_value& val) { __modified__ = val; }
2533 
2534  void reparent (const graphics_handle& new_parent) { parent = new_parent; }
2535 
2536  // Update data limits for AXIS_TYPE (xdata, ydata, etc.) in the parent
2537  // axes object.
2538 
2539  virtual void update_axis_limits (const std::string& axis_type) const;
2540 
2541  virtual void update_axis_limits (const std::string& axis_type,
2542  const graphics_handle& h) const;
2543 
2544  virtual void update_uicontextmenu (void) const;
2545 
2546  virtual void delete_children (bool clear = false)
2547  {
2548  children.delete_children (clear);
2549  }
2550 
2552  {
2553  children.renumber (old_gh, new_gh);
2554  }
2555 
2557  {
2558  parent = new_gh;
2559  }
2560 
2561  static property_list::pval_map_type factory_defaults (void);
2562 
2563  // FIXME: these functions should be generated automatically by the
2564  // genprops.awk script.
2565  //
2566  // EMIT_BASE_PROPERTIES_GET_FUNCTIONS
2567 
2568  virtual octave_value get_alim (void) const { return octave_value (); }
2569  virtual octave_value get_clim (void) const { return octave_value (); }
2570  virtual octave_value get_xlim (void) const { return octave_value (); }
2571  virtual octave_value get_ylim (void) const { return octave_value (); }
2572  virtual octave_value get_zlim (void) const { return octave_value (); }
2573 
2574  virtual bool is_aliminclude (void) const { return false; }
2575  virtual bool is_climinclude (void) const { return false; }
2576  virtual bool is_xliminclude (void) const { return false; }
2577  virtual bool is_yliminclude (void) const { return false; }
2578  virtual bool is_zliminclude (void) const { return false; }
2579 
2580  bool is_handle_visible (void) const;
2581 
2582  std::set<std::string> dynamic_property_names (void) const;
2583 
2584  bool has_dynamic_property (const std::string& pname);
2585 
2586 protected:
2587  std::set<std::string> dynamic_properties;
2588 
2589  void set_dynamic (const caseless_str& pname, const octave_value& val);
2590 
2591  octave_value get_dynamic (const caseless_str& pname) const;
2592 
2593  octave_value get_dynamic (bool all = false) const;
2594 
2595  property get_property_dynamic (const caseless_str& pname);
2596 
2597  BEGIN_BASE_PROPERTIES
2598  // properties common to all objects
2599  bool_property beingdeleted , "off"
2600  radio_property busyaction , "{queue}|cancel"
2601  callback_property buttondownfcn , Matrix ()
2602  children_property children gf , Matrix ()
2603  bool_property clipping , "on"
2604  callback_property createfcn , Matrix ()
2605  callback_property deletefcn , Matrix ()
2606  radio_property handlevisibility , "{on}|callback|off"
2607  bool_property hittest , "on"
2608  bool_property interruptible , "on"
2609  handle_property parent fs , p
2610  bool_property selected , "off"
2611  bool_property selectionhighlight , "on"
2612  string_property tag s , ""
2613  string_property type frs , ty
2614  handle_property uicontextmenu u , graphics_handle ()
2615  any_property userdata , Matrix ()
2616  bool_property visible , "on"
2617  // additional (Octave-specific) properties
2618  bool_property __modified__ s , "on"
2619  graphics_handle __myhandle__ fhrs , mh
2620  END_PROPERTIES
2621 
2622 protected:
2623  struct cmp_caseless_str
2624  {
2625  bool operator () (const caseless_str& a, const caseless_str& b) const
2626  {
2627  std::string a1 = a;
2628  std::transform (a1.begin (), a1.end (), a1.begin (), tolower);
2629  std::string b1 = b;
2630  std::transform (b1.begin (), b1.end (), b1.begin (), tolower);
2631 
2632  return a1 < b1;
2633  }
2634  };
2635 
2636  std::map<caseless_str, property, cmp_caseless_str> all_props;
2637 
2638 protected:
2639  void insert_static_property (const std::string& name, base_property& p)
2640  { insert_property (name, property (&p, true)); }
2641 
2642  virtual void init (void) { }
2643 };
2644 
2645 class OCTINTERP_API base_graphics_object
2646 {
2647 public:
2648  friend class graphics_object;
2649 
2650  base_graphics_object (void) : count (1), toolkit_flag (false) { }
2651 
2652  virtual ~base_graphics_object (void) { }
2653 
2654  virtual void mark_modified (void)
2655  {
2656  if (! valid_object ())
2657  error ("base_graphics_object::mark_modified: invalid graphics object");
2658 
2659  get_properties ().mark_modified ();
2660  }
2661 
2662  virtual void override_defaults (base_graphics_object& obj)
2663  {
2664  if (! valid_object ())
2665  error ("base_graphics_object::override_defaults: invalid graphics object");
2666  get_properties ().override_defaults (obj);
2667  }
2668 
2669  void build_user_defaults_map (property_list::pval_map_type &def,
2670  const std::string go_name) const;
2671 
2672  virtual void set_from_list (property_list& plist)
2673  {
2674  if (! valid_object ())
2675  error ("base_graphics_object::set_from_list: invalid graphics object");
2676 
2677  get_properties ().set_from_list (*this, plist);
2678  }
2679 
2680  virtual void set (const caseless_str& pname, const octave_value& pval)
2681  {
2682  if (! valid_object ())
2683  error ("base_graphics_object::set: invalid graphics object");
2684 
2685  get_properties ().set (pname, pval);
2686  }
2687 
2688  virtual void set_defaults (const std::string&)
2689  {
2690  error ("base_graphics_object::set_defaults: invalid graphics object");
2691  }
2692 
2693  virtual octave_value get (bool all = false) const
2694  {
2695  if (! valid_object ())
2696  error ("base_graphics_object::get: invalid graphics object");
2697 
2698  return get_properties ().get (all);
2699  }
2700 
2701  virtual octave_value get (const caseless_str& pname) const
2702  {
2703  if (! valid_object ())
2704  error ("base_graphics_object::get: invalid graphics object");
2705 
2706  return get_properties ().get (pname);
2707  }
2708 
2709  virtual octave_value get_default (const caseless_str&) const;
2710 
2711  virtual octave_value get_factory_default (const caseless_str&) const;
2712 
2713  virtual octave_value get_defaults (void) const
2714  {
2715  error ("base_graphics_object::get_defaults: invalid graphics object");
2716  }
2717 
2718  virtual property_list get_defaults_list (void) const
2719  {
2720  if (! valid_object ())
2721  error ("base_graphics_object::get_defaults_list: invalid graphics object");
2722 
2723  return property_list ();
2724  }
2725 
2726  virtual octave_value get_factory_defaults (void) const
2727  {
2728  error ("base_graphics_object::get_factory_defaults: invalid graphics object");
2729  }
2730 
2731  virtual property_list get_factory_defaults_list (void) const
2732  {
2733  error ("base_graphics_object::get_factory_defaults_list: invalid graphics object");
2734  }
2735 
2736  virtual bool has_readonly_property (const caseless_str& pname) const
2737  {
2738  return base_properties::has_readonly_property (pname);
2739  }
2740 
2741  virtual std::string values_as_string (void);
2742 
2743  virtual std::string value_as_string (const std::string& prop);
2744 
2745  virtual octave_scalar_map values_as_struct (void);
2746 
2747  virtual graphics_handle get_parent (void) const
2748  {
2749  if (! valid_object ())
2750  error ("base_graphics_object::get_parent: invalid graphics object");
2751 
2752  return get_properties ().get_parent ();
2753  }
2754 
2755  graphics_handle get_handle (void) const
2756  {
2757  if (! valid_object ())
2758  error ("base_graphics_object::get_handle: invalid graphics object");
2759 
2760  return get_properties ().get___myhandle__ ();
2761  }
2762 
2763  virtual void remove_child (const graphics_handle& h)
2764  {
2765  if (! valid_object ())
2766  error ("base_graphics_object::remove_child: invalid graphics object");
2767 
2768  get_properties ().remove_child (h);
2769  }
2770 
2771  virtual void adopt (const graphics_handle& h)
2772  {
2773  if (! valid_object ())
2774  error ("base_graphics_object::adopt: invalid graphics object");
2775 
2776  get_properties ().adopt (h);
2777  }
2778 
2779  virtual void reparent (const graphics_handle& np)
2780  {
2781  if (! valid_object ())
2782  error ("base_graphics_object::reparent: invalid graphics object");
2783 
2784  get_properties ().reparent (np);
2785  }
2786 
2787  virtual void defaults (void) const
2788  {
2789  if (! valid_object ())
2790  error ("base_graphics_object::default: invalid graphics object");
2791 
2792  std::string msg = (type () + "::defaults");
2793  err_not_implemented (msg.c_str ());
2794  }
2795 
2796  virtual base_properties& get_properties (void)
2797  {
2798  static base_properties properties;
2799  warning ("base_graphics_object::get_properties: invalid graphics object");
2800  return properties;
2801  }
2802 
2803  virtual const base_properties& get_properties (void) const
2804  {
2805  static base_properties properties;
2806  warning ("base_graphics_object::get_properties: invalid graphics object");
2807  return properties;
2808  }
2809 
2810  virtual void update_axis_limits (const std::string& axis_type);
2811 
2812  virtual void update_axis_limits (const std::string& axis_type,
2813  const graphics_handle& h);
2814 
2815  virtual bool valid_object (void) const { return false; }
2816 
2817  bool valid_toolkit_object (void) const { return toolkit_flag; }
2818 
2819  virtual std::string type (void) const
2820  {
2821  return (valid_object () ? get_properties ().graphics_object_name ()
2822  : "unknown");
2823  }
2824 
2825  bool isa (const std::string& go_name) const
2826  {
2827  return type () == go_name;
2828  }
2829 
2830  virtual graphics_toolkit get_toolkit (void) const
2831  {
2832  if (! valid_object ())
2833  error ("base_graphics_object::get_toolkit: invalid graphics object");
2834 
2835  return get_properties ().get_toolkit ();
2836  }
2837 
2838  virtual void add_property_listener (const std::string& nm,
2839  const octave_value& v,
2840  listener_mode mode = POSTSET)
2841  {
2842  if (valid_object ())
2843  get_properties ().add_listener (nm, v, mode);
2844  }
2845 
2846  virtual void delete_property_listener (const std::string& nm,
2847  const octave_value& v,
2848  listener_mode mode = POSTSET)
2849  {
2850  if (valid_object ())
2851  get_properties ().delete_listener (nm, v, mode);
2852  }
2853 
2854  virtual void remove_all_listeners (void);
2855 
2856  virtual void reset_default_properties (void);
2857 
2858 protected:
2859  virtual void initialize (const graphics_object& go)
2860  {
2861  if (! toolkit_flag)
2862  toolkit_flag = get_toolkit ().initialize (go);
2863  }
2864 
2865  virtual void finalize (const graphics_object& go)
2866  {
2867  if (toolkit_flag)
2868  {
2869  get_toolkit ().finalize (go);
2870  toolkit_flag = false;
2871  }
2872  }
2873 
2874  virtual void update (const graphics_object& go, int id)
2875  {
2876  if (toolkit_flag)
2877  get_toolkit ().update (go, id);
2878  }
2879 
2880 protected:
2881  // A reference count.
2882  octave_refcount<int> count;
2883 
2884  // A flag telling whether this object is a valid object
2885  // in the backend context.
2886  bool toolkit_flag;
2887 
2888  // No copying!
2889 
2890  base_graphics_object (const base_graphics_object&) : count (0) { }
2891 
2892  base_graphics_object& operator = (const base_graphics_object&)
2893  {
2894  return *this;
2895  }
2896 };
2897 
2898 class OCTINTERP_API graphics_object
2899 {
2900 public:
2901  graphics_object (void) : rep (new base_graphics_object ()) { }
2902 
2903  graphics_object (base_graphics_object *new_rep)
2904  : rep (new_rep) { }
2905 
2906  graphics_object (const graphics_object& obj) : rep (obj.rep)
2907  {
2908  rep->count++;
2909  }
2910 
2911  graphics_object& operator = (const graphics_object& obj)
2912  {
2913  if (rep != obj.rep)
2914  {
2915  if (--rep->count == 0)
2916  delete rep;
2917 
2918  rep = obj.rep;
2919  rep->count++;
2920  }
2921 
2922  return *this;
2923  }
2924 
2925  ~graphics_object (void)
2926  {
2927  if (--rep->count == 0)
2928  delete rep;
2929  }
2930 
2931  void mark_modified (void) { rep->mark_modified (); }
2932 
2933  void override_defaults (base_graphics_object& obj)
2934  {
2935  rep->override_defaults (obj);
2936  }
2937 
2938  void override_defaults (void)
2939  {
2940  rep->override_defaults (*rep);
2941  }
2942 
2943  void build_user_defaults_map (property_list::pval_map_type &def,
2944  const std::string go_name) const
2945  {
2946  rep->build_user_defaults_map (def, go_name);
2947  }
2948 
2949  void set_from_list (property_list& plist) { rep->set_from_list (plist); }
2950 
2951  void set (const caseless_str& name, const octave_value& val)
2952  {
2953  rep->set (name, val);
2954  }
2955 
2956  void set (const octave_value_list& args);
2957 
2958  void set (const Array<std::string>& names, const Cell& values,
2959  octave_idx_type row);
2960 
2961  void set (const octave_map& m);
2962 
2963  void set_value_or_default (const caseless_str& name,
2964  const octave_value& val);
2965 
2966  void set_defaults (const std::string& mode) { rep->set_defaults (mode); }
2967 
2968  octave_value get (bool all = false) const { return rep->get (all); }
2969 
2970  octave_value get (const caseless_str& name) const
2971  {
2972  return name.compare ("default")
2973  ? get_defaults ()
2974  : (name.compare ("factory")
2975  ? get_factory_defaults () : rep->get (name));
2976  }
2977 
2978  octave_value get (const std::string& name) const
2979  {
2980  return get (caseless_str (name));
2981  }
2982 
2983  octave_value get (const char *name) const
2984  {
2985  return get (caseless_str (name));
2986  }
2987 
2988  octave_value get_default (const caseless_str& name) const
2989  {
2990  return rep->get_default (name);
2991  }
2992 
2993  octave_value get_factory_default (const caseless_str& name) const
2994  {
2995  return rep->get_factory_default (name);
2996  }
2997 
2998  octave_value get_defaults (void) const { return rep->get_defaults (); }
2999 
3000  property_list get_defaults_list (void) const
3001  {
3002  return rep->get_defaults_list ();
3003  }
3004 
3005  octave_value get_factory_defaults (void) const
3006  {
3007  return rep->get_factory_defaults ();
3008  }
3009 
3010  property_list get_factory_defaults_list (void) const
3011  {
3012  return rep->get_factory_defaults_list ();
3013  }
3014 
3015  bool has_readonly_property (const caseless_str& pname) const
3016  {
3017  return rep->has_readonly_property (pname);
3018  }
3019 
3020  std::string values_as_string (void) { return rep->values_as_string (); }
3021 
3022  std::string value_as_string (const std::string& prop)
3023  {
3024  return rep->value_as_string (prop);
3025  }
3026 
3027  octave_map values_as_struct (void) { return rep->values_as_struct (); }
3028 
3029  graphics_handle get_parent (void) const { return rep->get_parent (); }
3030 
3031  graphics_handle get_handle (void) const { return rep->get_handle (); }
3032 
3033  graphics_object get_ancestor (const std::string& type) const;
3034 
3035  void remove_child (const graphics_handle& h) { rep->remove_child (h); }
3036 
3037  void adopt (const graphics_handle& h) { rep->adopt (h); }
3038 
3039  void reparent (const graphics_handle& h) { rep->reparent (h); }
3040 
3041  void defaults (void) const { rep->defaults (); }
3042 
3043  bool isa (const std::string& go_name) const { return rep->isa (go_name); }
3044 
3045  base_properties& get_properties (void) { return rep->get_properties (); }
3046 
3047  const base_properties& get_properties (void) const
3048  {
3049  return rep->get_properties ();
3050  }
3051 
3052  void update_axis_limits (const std::string& axis_type)
3053  {
3054  rep->update_axis_limits (axis_type);
3055  }
3056 
3057  void update_axis_limits (const std::string& axis_type,
3058  const graphics_handle& h)
3059  {
3060  rep->update_axis_limits (axis_type, h);
3061  }
3062 
3063  bool valid_object (void) const { return rep->valid_object (); }
3064 
3065  std::string type (void) const { return rep->type (); }
3066 
3067  operator bool (void) const { return rep->valid_object (); }
3068 
3069  // FIXME: these functions should be generated automatically by the
3070  // genprops.awk script.
3071  //
3072  // EMIT_GRAPHICS_OBJECT_GET_FUNCTIONS
3073 
3074  octave_value get_alim (void) const
3075  { return get_properties ().get_alim (); }
3076 
3077  octave_value get_clim (void) const
3078  { return get_properties ().get_clim (); }
3079 
3080  octave_value get_xlim (void) const
3081  { return get_properties ().get_xlim (); }
3082 
3083  octave_value get_ylim (void) const
3084  { return get_properties ().get_ylim (); }
3085 
3086  octave_value get_zlim (void) const
3087  { return get_properties ().get_zlim (); }
3088 
3089  bool is_aliminclude (void) const
3090  { return get_properties ().is_aliminclude (); }
3091 
3092  bool is_climinclude (void) const
3093  { return get_properties ().is_climinclude (); }
3094 
3095  bool is_xliminclude (void) const
3096  { return get_properties ().is_xliminclude (); }
3097 
3098  bool is_yliminclude (void) const
3099  { return get_properties ().is_yliminclude (); }
3100 
3101  bool is_zliminclude (void) const
3102  { return get_properties ().is_zliminclude (); }
3103 
3104  bool is_handle_visible (void) const
3105  { return get_properties ().is_handle_visible (); }
3106 
3107  graphics_toolkit get_toolkit (void) const { return rep->get_toolkit (); }
3108 
3109  void add_property_listener (const std::string& nm, const octave_value& v,
3110  listener_mode mode = POSTSET)
3111  { rep->add_property_listener (nm, v, mode); }
3112 
3113  void delete_property_listener (const std::string& nm, const octave_value& v,
3114  listener_mode mode = POSTSET)
3115  { rep->delete_property_listener (nm, v, mode); }
3116 
3117  void initialize (void) { rep->initialize (*this); }
3118 
3119  void finalize (void) { rep->finalize (*this); }
3120 
3121  void update (int id) { rep->update (*this, id); }
3122 
3123  void reset_default_properties (void)
3124  { rep->reset_default_properties (); }
3125 
3126 private:
3127  base_graphics_object *rep;
3128 };
3129 
3130 // ---------------------------------------------------------------------
3131 
3132 class OCTINTERP_API root_figure : public base_graphics_object
3133 {
3134 public:
3135  class OCTINTERP_API properties : public base_properties
3136  {
3137  public:
3138  void remove_child (const graphics_handle& h);
3139 
3140  Matrix get_boundingbox (bool internal = false,
3141  const Matrix& parent_pix_size = Matrix ()) const;
3142 
3143  // See the genprops.awk script for an explanation of the
3144  // properties declarations.
3145 
3146  // FIXME: Properties that still don't have callbacks are:
3147  // monitorpositions, pointerlocation, pointerwindow.
3148  // Note that these properties are not yet used by Octave, so setting
3149  // them will have no effect.
3150 
3151  // FIXME: The commandwindowsize property has been deprecated in Matlab
3152  // and is now available through matlab.desktop.comandwindow.size.
3153  // Until Octave has something similar, keep this property in root.
3154 
3155  // Programming note: Keep property list sorted if new ones are added.
3156 
3157  BEGIN_PROPERTIES (root_figure, root)
3158  handle_property callbackobject Sr , graphics_handle ()
3159  array_property commandwindowsize r , Matrix (1, 2, 0)
3160  handle_property currentfigure S , graphics_handle ()
3161  string_property fixedwidthfontname , "Courier"
3162  array_property monitorpositions r , default_screensize ()
3163  array_property pointerlocation , Matrix (1, 2, 0)
3164  double_property pointerwindow r , 0.0
3165  double_property screendepth r , default_screendepth ()
3166  double_property screenpixelsperinch r , default_screenpixelsperinch ()
3167  array_property screensize r , default_screensize ()
3168  bool_property showhiddenhandles , "off"
3169  radio_property units U , "inches|centimeters|normalized|points|{pixels}"
3170  END_PROPERTIES
3171 
3172  private:
3173  std::list<graphics_handle> cbo_stack;
3174 
3175  };
3176 
3177 private:
3178  properties xproperties;
3179 
3180 public:
3181 
3182  root_figure (void)
3183  : xproperties (0, graphics_handle ()), default_properties () { }
3184 
3185  ~root_figure (void) { }
3186 
3187  void mark_modified (void) { }
3188 
3189  void override_defaults (base_graphics_object& obj)
3190  {
3191  // Now override with our defaults. If the default_properties
3192  // list includes the properties for all defaults (line,
3193  // surface, etc.) then we don't have to know the type of OBJ
3194  // here, we just call its set function and let it decide which
3195  // properties from the list to use.
3196  obj.set_from_list (default_properties);
3197  }
3198 
3199  void set (const caseless_str& name, const octave_value& value)
3200  {
3201  if (name.compare ("default", 7))
3202  // strip "default", pass rest to function that will
3203  // parse the remainder and add the element to the
3204  // default_properties map.
3205  default_properties.set (name.substr (7), value);
3206  else
3207  xproperties.set (name, value);
3208  }
3209 
3210  octave_value get (const caseless_str& name) const
3211  {
3212  octave_value retval;
3213 
3214  if (name.compare ("default", 7))
3215  return get_default (name.substr (7));
3216  else if (name.compare ("factory", 7))
3217  return get_factory_default (name.substr (7));
3218  else
3219  retval = xproperties.get (name);
3220 
3221  return retval;
3222  }
3223 
3224  octave_value get_default (const caseless_str& name) const
3225  {
3226  octave_value retval = default_properties.lookup (name);
3227 
3228  if (retval.is_undefined ())
3229  {
3230  // no default property found, use factory default
3231  retval = factory_properties.lookup (name);
3232 
3233  if (retval.is_undefined ())
3234  error ("get: invalid default property '%s'", name.c_str ());
3235  }
3236 
3237  return retval;
3238  }
3239 
3240  octave_value get_factory_default (const caseless_str& name) const
3241  {
3242  octave_value retval = factory_properties.lookup (name);
3243 
3244  if (retval.is_undefined ())
3245  error ("get: invalid factory default property '%s'", name.c_str ());
3246 
3247  return retval;
3248  }
3249 
3250  octave_value get_defaults (void) const
3251  {
3252  return default_properties.as_struct ("default");
3253  }
3254 
3255  property_list get_defaults_list (void) const
3256  {
3257  return default_properties;
3258  }
3259 
3260  octave_value get_factory_defaults (void) const
3261  {
3262  return factory_properties.as_struct ("factory");
3263  }
3264 
3265  property_list get_factory_defaults_list (void) const
3266  {
3267  return factory_properties;
3268  }
3269 
3270  base_properties& get_properties (void) { return xproperties; }
3271 
3272  const base_properties& get_properties (void) const { return xproperties; }
3273 
3274  bool valid_object (void) const { return true; }
3275 
3276  void reset_default_properties (void);
3277 
3278  bool has_readonly_property (const caseless_str& pname) const
3279  {
3280  bool retval = xproperties.has_readonly_property (pname);
3281  if (! retval)
3282  retval = base_properties::has_readonly_property (pname);
3283  return retval;
3284  }
3285 
3286 private:
3287  property_list default_properties;
3288 
3289  static property_list factory_properties;
3290 
3291  static property_list::plist_map_type init_factory_properties (void);
3292 };
3293 
3294 // ---------------------------------------------------------------------
3295 
3296 class OCTINTERP_API figure : public base_graphics_object
3297 {
3298 public:
3299  class OCTINTERP_API properties : public base_properties
3300  {
3301  public:
3302  void init_integerhandle (const octave_value& val)
3303  {
3304  integerhandle = val;
3305  }
3306 
3307  void remove_child (const graphics_handle& h);
3308 
3309  void set_visible (const octave_value& val);
3310 
3311  graphics_toolkit get_toolkit (void) const
3312  {
3313  if (! toolkit)
3314  toolkit = gtk_manager::get_toolkit ();
3315 
3316  return toolkit;
3317  }
3318 
3319  void set_toolkit (const graphics_toolkit& b);
3320 
3321  void set___graphics_toolkit__ (const octave_value& val)
3322  {
3323  if (! val.is_string ())
3324  error ("set___graphics_toolkit__ must be a string");
3325 
3326  std::string nm = val.string_value ();
3327  graphics_toolkit b = gtk_manager::find_toolkit (nm);
3328 
3329  if (b.get_name () != nm)
3330  error ("set___graphics_toolkit__: invalid graphics toolkit");
3331 
3332  if (nm != get___graphics_toolkit__ ())
3333  {
3334  set_toolkit (b);
3335  mark_modified ();
3336  }
3337  }
3338 
3339  void adopt (const graphics_handle& h);
3340 
3341  void set_position (const octave_value& val,
3342  bool do_notify_toolkit = true);
3343 
3344  void set_outerposition (const octave_value& val,
3345  bool do_notify_toolkit = true);
3346 
3347  Matrix get_boundingbox (bool internal = false,
3348  const Matrix& parent_pix_size = Matrix ()) const;
3349 
3350  void set_boundingbox (const Matrix& bb, bool internal = false,
3351  bool do_notify_toolkit = true);
3352 
3353  Matrix map_from_boundingbox (double x, double y) const;
3354 
3355  Matrix map_to_boundingbox (double x, double y) const;
3356 
3357  void update_units (const caseless_str& old_units);
3358 
3359  void update_paperunits (const caseless_str& old_paperunits);
3360 
3361  std::string get_title (void) const;
3362 
3363  // See the genprops.awk script for an explanation of the
3364  // properties declarations.
3365  // FIXME: Several properties have been deleted from Matlab.
3366  // We should either immediately remove them or figure out a way
3367  // to deprecate them for a release or two.
3368  // Obsolete properties: doublebuffer, mincolormap, wvisual, wvisualmode,
3369  // xdisplay, xvisual, xvisualmode
3370 
3371  // Programming note: Keep property list sorted if new ones are added.
3372 
3373  BEGIN_PROPERTIES (figure)
3374  array_property alphamap , Matrix (64, 1, 1)
3375  callback_property buttondownfcn , Matrix ()
3376  callback_property closerequestfcn , "closereq"
3377  color_property color , color_property (color_values (1, 1, 1), radio_values ("none"))
3378  array_property colormap , viridis_colormap ()
3379  handle_property currentaxes S , graphics_handle ()
3380  string_property currentcharacter r , ""
3381  handle_property currentobject r , graphics_handle ()
3382  array_property currentpoint r , Matrix (2, 1, 0)
3383  bool_property dockcontrols , "off"
3384  string_property filename , ""
3385  bool_property graphicssmoothing , "on"
3386  bool_property integerhandle S , "on"
3387  bool_property inverthardcopy , "on"
3388  callback_property keypressfcn , Matrix ()
3389  callback_property keyreleasefcn , Matrix ()
3390  radio_property menubar , "{figure}|none"
3391  string_property name , ""
3392  // FIXME: Need RO property which returns current figure number.
3393  // double_property number r ,
3394  radio_property nextplot , "{add}|new|replace|replacechildren"
3395  bool_property numbertitle , "on"
3396  array_property outerposition s , Matrix (1, 4, -1.0)
3397  radio_property paperorientation U , "{portrait}|landscape"
3398  array_property paperposition m , default_figure_paperposition ()
3399  // FIXME: Matlab default is "auto", but this messes up hgsave BIST test.
3400  radio_property paperpositionmode au , "auto|{manual}"
3401  array_property papersize U , default_figure_papersize ()
3402  radio_property papertype SU , "{usletter}|uslegal|a0|a1|a2|a3|a4|a5|b0|b1|b2|b3|b4|b5|arch-a|arch-b|arch-c|arch-d|arch-e|a|b|c|d|e|tabloid|<custom>"
3403  radio_property paperunits Su , "{inches}|centimeters|normalized|points"
3404  radio_property pointer , "crosshair|fullcrosshair|{arrow}|ibeam|watch|topl|topr|botl|botr|left|top|right|bottom|circle|cross|fleur|custom|hand"
3405  array_property pointershapecdata , Matrix (16, 16, 0)
3406  array_property pointershapehotspot , Matrix (1, 2, 0)
3407  array_property position s , default_figure_position ()
3408  radio_property renderer m , "{opengl}|painters"
3409  radio_property renderermode , "{auto}|manual"
3410  bool_property resize , "on"
3411  // FIXME: resizefcn has been deprecated by Matlab, and
3412  // replaced with sizechangedfcn
3413  // Eventually this will need to be hidden, and then removed.
3414  callback_property resizefcn , Matrix ()
3415  radio_property selectiontype , "{normal}|extend|alt|open"
3416  callback_property sizechangedfcn , Matrix ()
3417  radio_property toolbar , "{auto}|figure|none"
3418  radio_property units Su , "{pixels}|normalized|inches|centimeters|points|characters"
3419  callback_property windowbuttondownfcn , Matrix ()
3420  callback_property windowbuttonmotionfcn , Matrix ()
3421  callback_property windowbuttonupfcn , Matrix ()
3422  callback_property windowkeypressfcn , Matrix ()
3423  callback_property windowkeyreleasefcn , Matrix ()
3424  callback_property windowscrollwheelfcn , Matrix ()
3425  radio_property windowstyle , "{normal}|modal|docked"
3426  // Octave-specific properties
3427  mutable string_property __gl_extensions__ hr , ""
3428  mutable string_property __gl_renderer__ hr , ""
3429  mutable string_property __gl_vendor__ hr , ""
3430  mutable string_property __gl_version__ hr , ""
3431  string_property __graphics_toolkit__ hs , gtk_manager::default_toolkit ()
3432  any_property __guidata__ h , Matrix ()
3433  radio_property __mouse_mode__ hS , "{none}|pan|rotate|select|text|zoom"
3434  any_property __pan_mode__ h , Matrix ()
3435  any_property __plot_stream__ h , Matrix ()
3436  any_property __rotate_mode__ h , Matrix ()
3437  any_property __zoom_mode__ h , Matrix ()
3438 
3439  // Obsolete properties: doublebuffer, mincolormap, wvisual, wvisualmode,
3440  // xdisplay, xvisual, xvisualmode
3441  // FIXME: Remove in version 4.6
3442  bool_property doublebuffer h , "on"
3443  double_property mincolormap h , 64
3444  string_property wvisual hm , ""
3445  radio_property wvisualmode h , "{auto}|manual"
3446  string_property xdisplay h , ""
3447  string_property xvisual hm , ""
3448  radio_property xvisualmode h , "{auto}|manual"
3449  END_PROPERTIES
3450 
3451  protected:
3452  void init (void)
3453  {
3454  alphamap.add_constraint (dim_vector (-1, 1));
3455  colormap.add_constraint (dim_vector (-1, 3));
3456  outerposition.add_constraint (dim_vector (1, 4));
3457  paperposition.add_constraint (dim_vector (1, 4));
3458  papersize.add_constraint (dim_vector (1, 2));
3459  pointershapecdata.add_constraint (dim_vector (16, 16));
3460  pointershapehotspot.add_constraint (dim_vector (1, 2));
3461  position.add_constraint (dim_vector (1, 4));
3462  }
3463 
3464  private:
3465  Matrix get_auto_paperposition (void);
3466 
3467  void update_paperpositionmode (void)
3468  {
3469  if (paperpositionmode.is ("auto"))
3470  paperposition.set (get_auto_paperposition ());
3471  }
3472 
3473  mutable graphics_toolkit toolkit;
3474  };
3475 
3476 private:
3477  properties xproperties;
3478 
3479 public:
3480  figure (const graphics_handle& mh, const graphics_handle& p)
3481  : base_graphics_object (), xproperties (mh, p), default_properties ()
3482  { }
3483 
3484  ~figure (void) { }
3485 
3486  void override_defaults (base_graphics_object& obj)
3487  {
3488  // Allow parent (root figure) to override first (properties knows how
3489  // to find the parent object).
3490  xproperties.override_defaults (obj);
3491 
3492  // Now override with our defaults. If the default_properties
3493  // list includes the properties for all defaults (line,
3494  // surface, etc.) then we don't have to know the type of OBJ
3495  // here, we just call its set function and let it decide which
3496  // properties from the list to use.
3497  obj.set_from_list (default_properties);
3498  }
3499 
3500  void set (const caseless_str& name, const octave_value& value)
3501  {
3502  if (name.compare ("default", 7))
3503  // strip "default", pass rest to function that will
3504  // parse the remainder and add the element to the
3505  // default_properties map.
3506  default_properties.set (name.substr (7), value);
3507  else
3508  xproperties.set (name, value);
3509  }
3510 
3511  octave_value get (const caseless_str& name) const
3512  {
3513  octave_value retval;
3514 
3515  if (name.compare ("default", 7))
3516  retval = get_default (name.substr (7));
3517  else
3518  retval = xproperties.get (name);
3519 
3520  return retval;
3521  }
3522 
3523  octave_value get_default (const caseless_str& name) const;
3524 
3525  octave_value get_defaults (void) const
3526  {
3527  return default_properties.as_struct ("default");
3528  }
3529 
3530  property_list get_defaults_list (void) const
3531  {
3532  return default_properties;
3533  }
3534 
3535  base_properties& get_properties (void) { return xproperties; }
3536 
3537  const base_properties& get_properties (void) const { return xproperties; }
3538 
3539  bool valid_object (void) const { return true; }
3540 
3541  void reset_default_properties (void);
3542 
3543  bool has_readonly_property (const caseless_str& pname) const
3544  {
3545  bool retval = xproperties.has_readonly_property (pname);
3546  if (! retval)
3547  retval = base_properties::has_readonly_property (pname);
3548  return retval;
3549  }
3550 
3551 private:
3552  property_list default_properties;
3553 };
3554 
3555 // ---------------------------------------------------------------------
3556 
3557 class OCTINTERP_API graphics_xform
3558 {
3559 public:
3560  graphics_xform (void)
3561  : xform (xform_eye ()), xform_inv (xform_eye ()),
3562  sx ("linear"), sy ("linear"), sz ("linear"), zlim (1, 2, 0.0)
3563  {
3564  zlim(1) = 1.0;
3565  }
3566 
3567  graphics_xform (const Matrix& xm, const Matrix& xim,
3568  const scaler& x, const scaler& y, const scaler& z,
3569  const Matrix& zl)
3570  : xform (xm), xform_inv (xim), sx (x), sy (y), sz (z), zlim (zl) { }
3571 
3572  graphics_xform (const graphics_xform& g)
3573  : xform (g.xform), xform_inv (g.xform_inv), sx (g.sx),
3574  sy (g.sy), sz (g.sz), zlim (g.zlim) { }
3575 
3576  ~graphics_xform (void) { }
3577 
3578  graphics_xform& operator = (const graphics_xform& g)
3579  {
3580  xform = g.xform;
3581  xform_inv = g.xform_inv;
3582  sx = g.sx;
3583  sy = g.sy;
3584  sz = g.sz;
3585  zlim = g.zlim;
3586 
3587  return *this;
3588  }
3589 
3590  static ColumnVector xform_vector (double x, double y, double z);
3591 
3592  static Matrix xform_eye (void);
3593 
3594  ColumnVector transform (double x, double y, double z,
3595  bool use_scale = true) const;
3596 
3597  ColumnVector untransform (double x, double y, double z,
3598  bool use_scale = true) const;
3599 
3600  ColumnVector untransform (double x, double y, bool use_scale = true) const
3601  { return untransform (x, y, (zlim(0)+zlim(1))/2, use_scale); }
3602 
3603  Matrix xscale (const Matrix& m) const { return sx.scale (m); }
3604  Matrix yscale (const Matrix& m) const { return sy.scale (m); }
3605  Matrix zscale (const Matrix& m) const { return sz.scale (m); }
3606 
3607  Matrix scale (const Matrix& m) const
3608  {
3609  bool has_z = (m.columns () > 2);
3610 
3611  if (sx.is_linear () && sy.is_linear ()
3612  && (! has_z || sz.is_linear ()))
3613  return m;
3614 
3615  Matrix retval (m.dims ());
3616 
3617  int r = m.rows ();
3618 
3619  for (int i = 0; i < r; i++)
3620  {
3621  retval(i,0) = sx.scale (m(i,0));
3622  retval(i,1) = sy.scale (m(i,1));
3623  if (has_z)
3624  retval(i,2) = sz.scale (m(i,2));
3625  }
3626 
3627  return retval;
3628  }
3629 
3630 private:
3631  Matrix xform;
3632  Matrix xform_inv;
3633  scaler sx, sy, sz;
3634  Matrix zlim;
3635 };
3636 
3637 enum
3638 {
3639  AXE_ANY_DIR = 0,
3640  AXE_DEPTH_DIR = 1,
3641  AXE_HORZ_DIR = 2,
3642  AXE_VERT_DIR = 3
3643 };
3644 
3645 class OCTINTERP_API axes : public base_graphics_object
3646 {
3647 public:
3648  class OCTINTERP_API properties : public base_properties
3649  {
3650  public:
3651  void set_defaults (base_graphics_object& obj, const std::string& mode);
3652 
3653  void remove_child (const graphics_handle& h);
3654 
3655  const scaler& get_x_scaler (void) const { return sx; }
3656  const scaler& get_y_scaler (void) const { return sy; }
3657  const scaler& get_z_scaler (void) const { return sz; }
3658 
3659  Matrix get_boundingbox (bool internal = false,
3660  const Matrix& parent_pix_size = Matrix ()) const;
3661  Matrix get_extent (bool with_text = false,
3662  bool only_text_height=false) const;
3663 
3664  double get_fontsize_points (double box_pix_height = 0) const;
3665 
3666  void update_boundingbox (void)
3667  {
3668  if (units_is ("normalized"))
3669  {
3670  sync_positions ();
3671  base_properties::update_boundingbox ();
3672  }
3673  }
3674 
3675  void update_camera (void);
3676  void update_axes_layout (void);
3677  void update_aspectratios (void);
3678  void update_transform (void)
3679  {
3680  update_aspectratios ();
3681  update_camera ();
3682  update_axes_layout ();
3683  }
3684 
3685  void sync_positions (void);
3686 
3687  void update_autopos (const std::string& elem_type);
3688  void update_xlabel_position (void);
3689  void update_ylabel_position (void);
3690  void update_zlabel_position (void);
3691  void update_title_position (void);
3692 
3693  graphics_xform get_transform (void) const
3694  { return graphics_xform (x_render, x_render_inv, sx, sy, sz, x_zlim); }
3695 
3696  Matrix get_transform_matrix (void) const { return x_render; }
3697  Matrix get_inverse_transform_matrix (void) const { return x_render_inv; }
3698  Matrix get_opengl_matrix_1 (void) const { return x_gl_mat1; }
3699  Matrix get_opengl_matrix_2 (void) const { return x_gl_mat2; }
3700  Matrix get_transform_zlim (void) const { return x_zlim; }
3701 
3702  int get_xstate (void) const { return xstate; }
3703  int get_ystate (void) const { return ystate; }
3704  int get_zstate (void) const { return zstate; }
3705  double get_xPlane (void) const { return xPlane; }
3706  double get_xPlaneN (void) const { return xPlaneN; }
3707  double get_yPlane (void) const { return yPlane; }
3708  double get_yPlaneN (void) const { return yPlaneN; }
3709  double get_zPlane (void) const { return zPlane; }
3710  double get_zPlaneN (void) const { return zPlaneN; }
3711  double get_xpTick (void) const { return xpTick; }
3712  double get_xpTickN (void) const { return xpTickN; }
3713  double get_ypTick (void) const { return ypTick; }
3714  double get_ypTickN (void) const { return ypTickN; }
3715  double get_zpTick (void) const { return zpTick; }
3716  double get_zpTickN (void) const { return zpTickN; }
3717  double get_x_min (void) const { return std::min (xPlane, xPlaneN); }
3718  double get_x_max (void) const { return std::max (xPlane, xPlaneN); }
3719  double get_y_min (void) const { return std::min (yPlane, yPlaneN); }
3720  double get_y_max (void) const { return std::max (yPlane, yPlaneN); }
3721  double get_z_min (void) const { return std::min (zPlane, zPlaneN); }
3722  double get_z_max (void) const { return std::max (zPlane, zPlaneN); }
3723  double get_fx (void) const { return fx; }
3724  double get_fy (void) const { return fy; }
3725  double get_fz (void) const { return fz; }
3726  double get_xticklen (void) const { return xticklen; }
3727  double get_yticklen (void) const { return yticklen; }
3728  double get_zticklen (void) const { return zticklen; }
3729  double get_xtickoffset (void) const { return xtickoffset; }
3730  double get_ytickoffset (void) const { return ytickoffset; }
3731  double get_ztickoffset (void) const { return ztickoffset; }
3732  bool get_x2Dtop (void) const { return x2Dtop; }
3733  bool get_y2Dright (void) const { return y2Dright; }
3734  bool get_layer2Dtop (void) const { return layer2Dtop; }
3735  bool get_is2D (void) const { return is2D; }
3736  bool get_xySym (void) const { return xySym; }
3737  bool get_xyzSym (void) const { return xyzSym; }
3738  bool get_zSign (void) const { return zSign; }
3739  bool get_nearhoriz (void) const { return nearhoriz; }
3740 
3741  ColumnVector pixel2coord (double px, double py) const
3742  { return get_transform ().untransform (px, py, (x_zlim(0)+x_zlim(1))/2); }
3743 
3744  ColumnVector coord2pixel (double x, double y, double z) const
3745  { return get_transform ().transform (x, y, z); }
3746 
3747  void zoom_about_point (const std::string& mode, double x, double y,
3748  double factor, bool push_to_zoom_stack = true);
3749  void zoom (const std::string& mode, double factor,
3750  bool push_to_zoom_stack = true);
3751  void zoom (const std::string& mode, const Matrix& xl, const Matrix& yl,
3752  bool push_to_zoom_stack = true);
3753 
3754  void translate_view (const std::string& mode,
3755  double x0, double x1, double y0, double y1,
3756  bool push_to_zoom_stack = true);
3757 
3758  void pan (const std::string& mode, double factor,
3759  bool push_to_zoom_stack = true);
3760 
3761  void rotate3d (double x0, double x1, double y0, double y1,
3762  bool push_to_zoom_stack = true);
3763 
3764  void rotate_view (double delta_az, double delta_el,
3765  bool push_to_zoom_stack = true);
3766 
3767  void unzoom (void);
3768  void push_zoom_stack (void);
3769  void clear_zoom_stack (bool do_unzoom = true);
3770 
3771  void update_units (const caseless_str& old_units);
3772 
3773  void update_fontunits (const caseless_str& old_fontunits);
3774 
3775  private:
3776  scaler sx, sy, sz;
3777  Matrix x_render, x_render_inv;
3778  Matrix x_gl_mat1, x_gl_mat2;
3779  Matrix x_zlim;
3780  std::list<octave_value> zoom_stack;
3781 
3782  // Axes layout data
3783  int xstate, ystate, zstate;
3784  double xPlane, xPlaneN, yPlane, yPlaneN, zPlane, zPlaneN;
3785  double xpTick, xpTickN, ypTick, ypTickN, zpTick, zpTickN;
3786  double fx, fy, fz;
3787  double xticklen, yticklen, zticklen;
3788  double xtickoffset, ytickoffset, ztickoffset;
3789  bool x2Dtop, y2Dright, layer2Dtop, is2D;
3790  bool xySym, xyzSym, zSign, nearhoriz;
3791 
3792  // Text renderer, used for calculation of text (tick labels) size
3793  octave::text_renderer txt_renderer;
3794 
3795  void set_text_child (handle_property& h, const std::string& who,
3796  const octave_value& v);
3797 
3798  void delete_text_child (handle_property& h);
3799 
3800  // See the genprops.awk script for an explanation of the
3801  // properties declarations.
3802 
3803  // FIXME: Several properties have been deleted from Matlab.
3804  // We should either immediately remove them or figure out a way
3805  // to deprecate them for a release or two.
3806  // Obsolete properties: drawmode
3807 
3808  // Programming note: Keep property list sorted if new ones are added.
3809 
3810  BEGIN_PROPERTIES (axes)
3811  radio_property activepositionproperty , "{outerposition}|position"
3812  row_vector_property alim m , default_lim ()
3813  radio_property alimmode , "{auto}|manual"
3814  color_property ambientlightcolor , color_values (1, 1, 1)
3815  bool_property box , "off"
3816  radio_property boxstyle , "{back}|full"
3817  array_property cameraposition m , Matrix (1, 3, 0.0)
3818  radio_property camerapositionmode , "{auto}|manual"
3819  array_property cameratarget m , Matrix (1, 3, 0.0)
3820  radio_property cameratargetmode , "{auto}|manual"
3821  array_property cameraupvector m , Matrix (1, 3, 0.0)
3822  radio_property cameraupvectormode , "{auto}|manual"
3823  double_property cameraviewangle m , 6.6086
3824  radio_property cameraviewanglemode , "{auto}|manual"
3825  row_vector_property clim m , default_lim ()
3826  radio_property climmode al , "{auto}|manual"
3827  radio_property clippingstyle , "{3dbox}|rectangle"
3828  color_property color , color_property (color_values (1, 1, 1), radio_values ("none"))
3829  array_property colororder , default_colororder ()
3830  double_property colororderindex , 1.0
3831  array_property currentpoint , Matrix (2, 3, 0.0)
3832  array_property dataaspectratio mu , Matrix (1, 3, 1.0)
3833  radio_property dataaspectratiomode u , "{auto}|manual"
3834  radio_property drawmode , "{normal}|fast"
3835  radio_property fontangle u , "{normal}|italic"
3836  string_property fontname u , OCTAVE_DEFAULT_FONTNAME
3837  double_property fontsize u , 10
3838  radio_property fontunits SU , "{points}|inches|centimeters|normalized|pixels"
3839  bool_property fontsmoothing , "on"
3840  radio_property fontweight u , "{normal}|bold"
3841  double_property gridalpha m , 0.15
3842  radio_property gridalphamode , "{auto}|manual"
3843  color_property gridcolor , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
3844  radio_property gridcolormode , "{auto}|manual"
3845  radio_property gridlinestyle , "{-}|--|:|-.|none"
3846  double_property labelfontsizemultiplier , 1.1
3847  radio_property layer u , "{bottom}|top"
3848  // FIXME: should be kind of string array.
3849  any_property linestyleorder S , "-"
3850  double_property linestyleorderindex , 1.0
3851  double_property linewidth , 0.5
3852  double_property minorgridalpha m , 0.25
3853  radio_property minorgridalphamode , "{auto}|manual"
3854  color_property minorgridcolor m , color_property (color_values (0.1, 0.1, 0.1), radio_values ("none"))
3855  radio_property minorgridcolormode , "{auto}|manual"
3856  radio_property minorgridlinestyle , "{:}|-|--|-.|none"
3857  radio_property nextplot , "{replace}|add|replacechildren"
3858  array_property outerposition u , default_axes_outerposition ()
3859  array_property plotboxaspectratio mu , Matrix (1, 3, 1.0)
3860  radio_property plotboxaspectratiomode u , "{auto}|manual"
3861  radio_property pickableparts , "{visible}|all|none"
3862  array_property position u , default_axes_position ()
3863  radio_property projection , "{orthographic}|perspective"
3864  radio_property sortmethod , "{depth}|childorder"
3865  radio_property tickdir mu , "{in}|out"
3866  radio_property tickdirmode u , "{auto}|manual"
3867  // FIXME: Added recently to Matlab, should replace interpreter property.
3868  radio_property ticklabelinterpreter , "{tex}|latex|none"
3869  array_property ticklength u , default_axes_ticklength ()
3870  array_property tightinset r , Matrix (1, 4, 0.0)
3871  handle_property title SOf , gh_manager::make_graphics_handle ("text", __myhandle__, false, false, false)
3872  double_property titlefontsizemultiplier , 1.1
3873  radio_property titlefontweight , "{bold}|normal"
3874  // FIXME: uicontextmenu should be moved here.
3875  radio_property units SU , "{normalized}|inches|centimeters|points|pixels|characters"
3876  array_property view u , default_axes_view ()
3877  // FIXME: Remove "zero" in 4.6
3878  radio_property xaxislocation u , "{bottom}|top|origin|zero"
3879  color_property xcolor mu , color_values (0.15, 0.15, 0.15)
3880  radio_property xcolormode , "{auto}|manual"
3881  radio_property xdir u , "{normal}|reverse"
3882  bool_property xgrid , "off"
3883  handle_property xlabel SOf , gh_manager::make_graphics_handle ("text", __myhandle__, false, false, false)
3884  row_vector_property xlim mu , default_lim ()
3885  radio_property xlimmode al , "{auto}|manual"
3886  bool_property xminorgrid , "off"
3887  bool_property xminortick , "off"
3888  radio_property xscale alu , "{linear}|log"
3889  row_vector_property xtick mu , default_axes_tick ()
3890  // FIXME: should be kind of string array.
3891  any_property xticklabel S , ""
3892  radio_property xticklabelmode u , "{auto}|manual"
3893  double_property xticklabelrotation , 0.0
3894  radio_property xtickmode u , "{auto}|manual"
3895  // FIXME: Remove "zero" in 4.6
3896  radio_property yaxislocation u , "{left}|right|origin|zero"
3897  color_property ycolor mu , color_values (0.15, 0.15, 0.15)
3898  radio_property ycolormode , "{auto}|manual"
3899  radio_property ydir u , "{normal}|reverse"
3900  bool_property ygrid , "off"
3901  handle_property ylabel SOf , gh_manager::make_graphics_handle ("text", __myhandle__, false, false, false)
3902  row_vector_property ylim mu , default_lim ()
3903  radio_property ylimmode al , "{auto}|manual"
3904  bool_property yminorgrid , "off"
3905  bool_property yminortick , "off"
3906  radio_property yscale alu , "{linear}|log"
3907  row_vector_property ytick mu , default_axes_tick ()
3908  any_property yticklabel S , ""
3909  radio_property yticklabelmode u , "{auto}|manual"
3910  double_property yticklabelrotation , 0.0
3911  radio_property ytickmode u , "{auto}|manual"
3912  color_property zcolor mu , color_values (0.15, 0.15, 0.15)
3913  radio_property zcolormode , "{auto}|manual"
3914  radio_property zdir u , "{normal}|reverse"
3915  bool_property zgrid , "off"
3916  handle_property zlabel SOf , gh_manager::make_graphics_handle ("text", __myhandle__, false, false, false)
3917  row_vector_property zlim mu , default_lim ()
3918  radio_property zlimmode al , "{auto}|manual"
3919  bool_property zminorgrid , "off"
3920  bool_property zminortick , "off"
3921  radio_property zscale alu , "{linear}|log"
3922  row_vector_property ztick mu , default_axes_tick ()
3923  any_property zticklabel S , ""
3924  radio_property zticklabelmode u , "{auto}|manual"
3925  double_property zticklabelrotation , 0.0
3926  radio_property ztickmode u , "{auto}|manual"
3927  // Octave-specific properties
3928  double_property mousewheelzoom , 0.5
3929  // hidden properties for alignment of subplots
3930  radio_property autopos_tag h , "{none}|subplot"
3931  // hidden properties for inset
3932  array_property looseinset hu , Matrix (1, 4, 0.0)
3933  // hidden properties for transformation computation
3934  array_property x_viewtransform h , Matrix (4, 4, 0.0)
3935  array_property x_projectiontransform h , Matrix (4, 4, 0.0)
3936  array_property x_viewporttransform h , Matrix (4, 4, 0.0)
3937  array_property x_normrendertransform h , Matrix (4, 4, 0.0)
3938  array_property x_rendertransform h , Matrix (4, 4, 0.0)
3939  // hidden properties for minor ticks
3940  row_vector_property xmtick h , Matrix ()
3941  row_vector_property ymtick h , Matrix ()
3942  row_vector_property zmtick h , Matrix ()
3943  // hidden property for text rendering
3944  double_property fontsize_points hgr , 0
3945  END_PROPERTIES
3946 
3947  protected:
3948  void init (void);
3949 
3950  private:
3951 
3952  std::string
3953  get_scale (const std::string& scale, const Matrix& lims)
3954  {
3955  std::string retval = scale;
3956 
3957  if (scale == "log" && lims.numel () > 1 && lims(0) < 0 && lims(1) < 0)
3958  retval = "neglog";
3959 
3960  return retval;
3961  }
3962 
3963  void update_xscale (void)
3964  {
3965  sx = get_scale (get_xscale (), xlim.get ().matrix_value ());
3966  }
3967 
3968  void update_yscale (void)
3969  {
3970  sy = get_scale (get_yscale (), ylim.get ().matrix_value ());
3971  }
3972 
3973  void update_zscale (void)
3974  {
3975  sz = get_scale (get_zscale (), zlim.get ().matrix_value ());
3976  }
3977 
3978  void update_label_color (handle_property label, color_property col);
3979  void update_xcolor (void)
3980  { update_label_color (xlabel, xcolor); }
3981 
3982  void update_ycolor (void)
3983  { update_label_color (ylabel, ycolor); }
3984 
3985  void update_zcolor (void)
3986  { update_label_color (zlabel, zcolor); }
3987 
3988  void update_view (void) { sync_positions (); }
3989  void update_dataaspectratio (void) { sync_positions (); }
3990  void update_dataaspectratiomode (void) { sync_positions (); }
3991  void update_plotboxaspectratio (void) { sync_positions (); }
3992  void update_plotboxaspectratiomode (void) { sync_positions (); }
3993 
3994  void update_layer (void) { update_axes_layout (); }
3995  void update_yaxislocation (void)
3996  {
3997  // FIXME: Remove warning with "zero" in 4.6
3998  if (yaxislocation_is ("zero"))
3999  warning_with_id ("Octave:deprecated-property",
4000  "Setting 'yaxislocation' to 'zero' is deprecated, "
4001  "set to 'origin' instead.");
4002  sync_positions ();
4003  update_axes_layout ();
4004  update_ylabel_position ();
4005  }
4006  void update_xaxislocation (void)
4007  {
4008  // FIXME: Remove warning with "zero" in 4.6
4009  if (xaxislocation_is ("zero"))
4010  warning_with_id ("Octave:deprecated-property",
4011  "Setting 'xaxislocation' to 'zero' is deprecated, "
4012  "set to 'origin' instead.");
4013  sync_positions ();
4014  update_axes_layout ();
4015  update_xlabel_position ();
4016  }
4017 
4018  void update_xdir (void) { update_camera (); update_axes_layout (); }
4019  void update_ydir (void) { update_camera (); update_axes_layout (); }
4020  void update_zdir (void) { update_camera (); update_axes_layout (); }
4021 
4022  void update_ticklength (void);
4023  void update_tickdir (void) { update_ticklength (); }
4024  void update_tickdirmode (void) { update_ticklength (); }
4025 
4026  void update_xtick (void)
4027  {
4028  if (xticklabelmode.is ("auto"))
4029  calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
4030  sync_positions ();
4031  }
4032  void update_ytick (void)
4033  {
4034  if (yticklabelmode.is ("auto"))
4035  calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
4036  sync_positions ();
4037  }
4038  void update_ztick (void)
4039  {
4040  if (zticklabelmode.is ("auto"))
4041  calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
4042  sync_positions ();
4043  }
4044 
4045  void update_xtickmode (void)
4046  {
4047  if (xtickmode.is ("auto"))
4048  {
4049  calc_ticks_and_lims (xlim, xtick, xmtick, xlimmode.is ("auto"),
4050  xscale.is ("log"));
4051  update_xtick ();
4052  }
4053  }
4054  void update_ytickmode (void)
4055  {
4056  if (ytickmode.is ("auto"))
4057  {
4058  calc_ticks_and_lims (ylim, ytick, ymtick, ylimmode.is ("auto"),
4059  yscale.is ("log"));
4060  update_ytick ();
4061  }
4062  }
4063  void update_ztickmode (void)
4064  {
4065  if (ztickmode.is ("auto"))
4066  {
4067  calc_ticks_and_lims (zlim, ztick, zmtick, zlimmode.is ("auto"),
4068  zscale.is ("log"));
4069  update_ztick ();
4070  }
4071  }
4072 
4073  void update_xticklabelmode (void)
4074  {
4075  if (xticklabelmode.is ("auto"))
4076  calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
4077  }
4078  void update_yticklabelmode (void)
4079  {
4080  if (yticklabelmode.is ("auto"))
4081  calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
4082  }
4083  void update_zticklabelmode (void)
4084  {
4085  if (zticklabelmode.is ("auto"))
4086  calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
4087  }
4088 
4089  void update_font (void);
4090  void update_fontname (void)
4091  {
4092  update_font ();
4093  sync_positions ();
4094  }
4095  void update_fontsize (void)
4096  {
4097  update_font ();
4098  sync_positions ();
4099  }
4100  void update_fontangle (void)
4101  {
4102  update_font ();
4103  sync_positions ();
4104  }
4105  void update_fontweight (void)
4106  {
4107  update_font ();
4108  sync_positions ();
4109  }
4110 
4111  void update_outerposition (void)
4112  {
4113  set_activepositionproperty ("outerposition");
4114  caseless_str old_units = get_units ();
4115  set_units ("normalized");
4116  Matrix outerbox = outerposition.get ().matrix_value ();
4117  Matrix innerbox = position.get ().matrix_value ();
4118  Matrix linset = looseinset.get ().matrix_value ();
4119  Matrix tinset = tightinset.get ().matrix_value ();
4120  outerbox(2) = outerbox(2) + outerbox(0);
4121  outerbox(3) = outerbox(3) + outerbox(1);
4122  innerbox(0) = outerbox(0) + std::max (linset(0), tinset(0));
4123  innerbox(1) = outerbox(1) + std::max (linset(1), tinset(1));
4124  innerbox(2) = outerbox(2) - std::max (linset(2), tinset(2));
4125  innerbox(3) = outerbox(3) - std::max (linset(3), tinset(3));
4126  innerbox(2) = innerbox(2) - innerbox(0);
4127  innerbox(3) = innerbox(3) - innerbox(1);
4128  position = innerbox;
4129  set_units (old_units);
4130  update_transform ();
4131  }
4132 
4133  void update_position (void)
4134  {
4135  set_activepositionproperty ("position");
4136  caseless_str old_units = get_units ();
4137  set_units ("normalized");
4138  Matrix outerbox = outerposition.get ().matrix_value ();
4139  Matrix innerbox = position.get ().matrix_value ();
4140  Matrix linset = looseinset.get ().matrix_value ();
4141  Matrix tinset = tightinset.get ().matrix_value ();
4142  innerbox(2) = innerbox(2) + innerbox(0);
4143  innerbox(3) = innerbox(3) + innerbox(1);
4144  outerbox(0) = innerbox(0) - std::max (linset(0), tinset(0));
4145  outerbox(1) = innerbox(1) - std::max (linset(1), tinset(1));
4146  outerbox(2) = innerbox(2) + std::max (linset(2), tinset(2));
4147  outerbox(3) = innerbox(3) + std::max (linset(3), tinset(3));
4148  outerbox(2) = outerbox(2) - outerbox(0);
4149  outerbox(3) = outerbox(3) - outerbox(1);
4150  outerposition = outerbox;
4151  set_units (old_units);
4152  update_transform ();
4153  }
4154 
4155  void update_looseinset (void)
4156  {
4157  caseless_str old_units = get_units ();
4158  set_units ("normalized");
4159  Matrix innerbox = position.get ().matrix_value ();
4160  innerbox(2) = innerbox(2) + innerbox(0);
4161  innerbox(3) = innerbox(3) + innerbox(1);
4162  Matrix outerbox = outerposition.get ().matrix_value ();
4163  outerbox(2) = outerbox(2) + outerbox(0);
4164  outerbox(3) = outerbox(3) + outerbox(1);
4165  Matrix linset = looseinset.get ().matrix_value ();
4166  Matrix tinset = tightinset.get ().matrix_value ();
4167  if (activepositionproperty.is ("position"))
4168  {
4169  outerbox(0) = innerbox(0) - std::max (linset(0), tinset(0));
4170  outerbox(1) = innerbox(1) - std::max (linset(1), tinset(1));
4171  outerbox(2) = innerbox(2) + std::max (linset(2), tinset(2));
4172  outerbox(3) = innerbox(3) + std::max (linset(3), tinset(3));
4173  outerbox(2) = outerbox(2) - outerbox(0);
4174  outerbox(3) = outerbox(3) - outerbox(1);
4175  outerposition = outerbox;
4176  }
4177  else
4178  {
4179  innerbox(0) = outerbox(0) + std::max (linset(0), tinset(0));
4180  innerbox(1) = outerbox(1) + std::max (linset(1), tinset(1));
4181  innerbox(2) = outerbox(2) - std::max (linset(2), tinset(2));
4182  innerbox(3) = outerbox(3) - std::max (linset(3), tinset(3));
4183  innerbox(2) = innerbox(2) - innerbox(0);
4184  innerbox(3) = innerbox(3) - innerbox(1);
4185  position = innerbox;
4186  }
4187  set_units (old_units);
4188  update_transform ();
4189  }
4190 
4191  double calc_tick_sep (double minval, double maxval);
4192  void calc_ticks_and_lims (array_property& lims, array_property& ticks,
4193  array_property& mticks,
4194  bool limmode_is_auto, bool is_logscale);
4195  void calc_ticklabels (const array_property& ticks, any_property& labels,
4196  bool is_logscale);
4197  Matrix get_ticklabel_extents (const Matrix& ticks,
4198  const string_vector& ticklabels,
4199  const Matrix& limits);
4200 
4201  void fix_limits (array_property& lims)
4202  {
4203  if (lims.get ().is_empty ())
4204  return;
4205 
4206  Matrix l = lims.get ().matrix_value ();
4207  if (l(0) > l(1))
4208  {
4209  l(0) = 0;
4210  l(1) = 1;
4211  lims = l;
4212  }
4213  else if (l(0) == l(1))
4214  {
4215  l(0) -= 0.5;
4216  l(1) += 0.5;
4217  lims = l;
4218  }
4219  }
4220 
4221  Matrix calc_tightbox (const Matrix& init_pos);
4222 
4223  public:
4224  Matrix get_axis_limits (double xmin, double xmax,
4225  double min_pos, double max_neg,
4226  bool logscale);
4227 
4228  void update_xlim ()
4229  {
4230  if (xtickmode.is ("auto"))
4231  calc_ticks_and_lims (xlim, xtick, xmtick, xlimmode.is ("auto"),
4232  xscale.is ("log"));
4233  if (xticklabelmode.is ("auto"))
4234  calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
4235 
4236  fix_limits (xlim);
4237 
4238  update_xscale ();
4239 
4240  update_axes_layout ();
4241  }
4242 
4243  void update_ylim (void)
4244  {
4245  if (ytickmode.is ("auto"))
4246  calc_ticks_and_lims (ylim, ytick, ymtick, ylimmode.is ("auto"),
4247  yscale.is ("log"));
4248  if (yticklabelmode.is ("auto"))
4249  calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
4250 
4251  fix_limits (ylim);
4252 
4253  update_yscale ();
4254 
4255  update_axes_layout ();
4256  }
4257 
4258  void update_zlim (void)
4259  {
4260  if (ztickmode.is ("auto"))
4261  calc_ticks_and_lims (zlim, ztick, zmtick, zlimmode.is ("auto"),
4262  zscale.is ("log"));
4263  if (zticklabelmode.is ("auto"))
4264  calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
4265 
4266  fix_limits (zlim);
4267 
4268  update_zscale ();
4269 
4270  update_axes_layout ();
4271  }
4272 
4273  };
4274 
4275 private:
4276  properties xproperties;
4277 
4278 public:
4279  axes (const graphics_handle& mh, const graphics_handle& p)
4280  : base_graphics_object (), xproperties (mh, p), default_properties ()
4281  {
4282  xproperties.update_transform ();
4283  }
4284 
4285  ~axes (void) { }
4286 
4287  void override_defaults (base_graphics_object& obj)
4288  {
4289  // Allow parent (figure) to override first (properties knows how
4290  // to find the parent object).
4291  xproperties.override_defaults (obj);
4292 
4293  // Now override with our defaults. If the default_properties
4294  // list includes the properties for all defaults (line,
4295  // surface, etc.) then we don't have to know the type of OBJ
4296  // here, we just call its set function and let it decide which
4297  // properties from the list to use.
4298  obj.set_from_list (default_properties);
4299  }
4300 
4301  void set (const caseless_str& name, const octave_value& value)
4302  {
4303  if (name.compare ("default", 7))
4304  // strip "default", pass rest to function that will
4305  // parse the remainder and add the element to the
4306  // default_properties map.
4307  default_properties.set (name.substr (7), value);
4308  else
4309  xproperties.set (name, value);
4310  }
4311 
4312  void set_defaults (const std::string& mode)
4313  {
4314  xproperties.set_defaults (*this, mode);
4315  }
4316 
4317  octave_value get (const caseless_str& name) const
4318  {
4319  octave_value retval;
4320 
4321  // FIXME: finish this.
4322  if (name.compare ("default", 7))
4323  retval = get_default (name.substr (7));
4324  else
4325  retval = xproperties.get (name);
4326 
4327  return retval;
4328  }
4329 
4330  octave_value get_default (const caseless_str& name) const;
4331 
4332  octave_value get_defaults (void) const
4333  {
4334  return default_properties.as_struct ("default");
4335  }
4336 
4337  property_list get_defaults_list (void) const
4338  {
4339  return default_properties;
4340  }
4341 
4342  base_properties& get_properties (void) { return xproperties; }
4343 
4344  const base_properties& get_properties (void) const { return xproperties; }
4345 
4346  void update_axis_limits (const std::string& axis_type);
4347 
4348  void update_axis_limits (const std::string& axis_type,
4349  const graphics_handle& h);
4350 
4351  bool valid_object (void) const { return true; }
4352 
4353  void reset_default_properties (void);
4354 
4355  bool has_readonly_property (const caseless_str& pname) const
4356  {
4357  bool retval = xproperties.has_readonly_property (pname);
4358  if (! retval)
4359  retval = base_properties::has_readonly_property (pname);
4360  return retval;
4361  }
4362 
4363 protected:
4364  void initialize (const graphics_object& go);
4365 
4366 private:
4367  property_list default_properties;
4368 };
4369 
4370 // ---------------------------------------------------------------------
4371 
4372 class OCTINTERP_API line : public base_graphics_object
4373 {
4374 public:
4375  class OCTINTERP_API properties : public base_properties
4376  {
4377  public:
4378  // See the genprops.awk script for an explanation of the
4379  // properties declarations.
4380  // Programming note: Keep property list sorted if new ones are added.
4381 
4382  BEGIN_PROPERTIES (line)
4383  color_property color , color_property (color_values (0, 0, 0), radio_values ("none"))
4384  string_property displayname , ""
4385  // FIXME: Remove erasemode property in version 4.6.
4386  radio_property erasemode h , "{normal}|none|xor|background"
4387  // FIXME: interpreter is not a property of Matlab line objects.
4388  // Octave uses this for legend() with the string displayname.
4389  radio_property interpreter , "{tex}|none|latex"
4390  radio_property linestyle , "{-}|--|:|-.|none"
4391  double_property linewidth , 0.5
4392  radio_property marker , "{none}|+|o|*|.|x|s|square|d|diamond|^|v|>|<|p|pentagram|h|hexagram"
4393  color_property markeredgecolor , color_property (radio_values ("{auto}|none"), color_values (0, 0, 0))
4394  color_property markerfacecolor , color_property (radio_values ("auto|{none}"), color_values (0, 0, 0))
4395  double_property markersize , 6
4396  row_vector_property xdata u , default_data ()
4397  string_property xdatasource , ""
4398  row_vector_property ydata u , default_data ()
4399  string_property ydatasource , ""
4400  row_vector_property zdata u , Matrix ()
4401  string_property zdatasource , ""
4402 
4403  // hidden properties for limit computation
4404  row_vector_property xlim hlr , Matrix ()
4405  row_vector_property ylim hlr , Matrix ()
4406  row_vector_property zlim hlr , Matrix ()
4407  bool_property xliminclude hl , "on"
4408  bool_property yliminclude hl , "on"
4409  bool_property zliminclude hl , "off"
4410  END_PROPERTIES
4411 
4412  private:
4413  Matrix compute_xlim (void) const;
4414  Matrix compute_ylim (void) const;
4415 
4416  void update_xdata (void) { set_xlim (compute_xlim ()); }
4417 
4418  void update_ydata (void) { set_ylim (compute_ylim ()); }
4419 
4420  void update_zdata (void)
4421  {
4422  set_zlim (zdata.get_limits ());
4423  set_zliminclude (get_zdata ().numel () > 0);
4424  }
4425  };
4426 
4427 private:
4428  properties xproperties;
4429 
4430 public:
4431  line (const graphics_handle& mh, const graphics_handle& p)
4432  : base_graphics_object (), xproperties (mh, p)
4433  { }
4434 
4435  ~line (void) { }
4436 
4437  base_properties& get_properties (void) { return xproperties; }
4438 
4439  const base_properties& get_properties (void) const { return xproperties; }
4440 
4441  bool valid_object (void) const { return true; }
4442 
4443  bool has_readonly_property (const caseless_str& pname) const
4444  {
4445  bool retval = xproperties.has_readonly_property (pname);
4446  if (! retval)
4447  retval = base_properties::has_readonly_property (pname);
4448  return retval;
4449  }
4450 };
4451 
4452 // ---------------------------------------------------------------------
4453 
4454 class OCTINTERP_API text : public base_graphics_object
4455 {
4456 public:
4457  class OCTINTERP_API properties : public base_properties
4458  {
4459  public:
4460  double get_fontsize_points (double box_pix_height = 0) const;
4461 
4462  void set_position (const octave_value& val)
4463  {
4464  octave_value new_val (val);
4465 
4466  if (new_val.numel () == 2)
4467  {
4468  dim_vector dv (1, 3);
4469 
4470  new_val = new_val.resize (dv, true);
4471  }
4472 
4473  if (position.set (new_val, false))
4474  {
4475  set_positionmode ("manual");
4476  update_position ();
4477  position.run_listeners (POSTSET);
4478  mark_modified ();
4479  }
4480  else
4481  set_positionmode ("manual");
4482  }
4483 
4484  // See the genprops.awk script for an explanation of the
4485  // properties declarations.
4486 
4487  BEGIN_PROPERTIES (text)
4488  color_property backgroundcolor , color_property (radio_values ("{none}"), color_values (1, 1, 1))
4489  color_property color u , color_values (0, 0, 0)
4490  string_property displayname , ""
4491  color_property edgecolor , color_property (radio_values ("{none}"), color_values (0, 0, 0))
4492  bool_property editing , "off"
4493  radio_property erasemode h , "{normal}|none|xor|background"
4494  array_property extent rG , Matrix (1, 4, 0.0)
4495  radio_property fontangle u , "{normal}|italic|oblique"
4496  string_property fontname u , OCTAVE_DEFAULT_FONTNAME
4497  double_property fontsize u , 10
4498  radio_property fontunits SU , "inches|centimeters|normalized|{points}|pixels"
4499  radio_property fontweight u , "light|{normal}|demi|bold"
4500  radio_property horizontalalignment mu , "{left}|center|right"
4501  radio_property interpreter u , "{tex}|none|latex"
4502  radio_property linestyle , "{-}|--|:|-.|none"
4503  double_property linewidth , 0.5
4504  double_property margin , 2
4505  array_property position smu , Matrix (1, 3, 0.0)
4506  double_property rotation mu , 0
4507  text_label_property string u , ""
4508  radio_property units u , "{data}|pixels|normalized|inches|centimeters|points"
4509  radio_property verticalalignment mu , "top|cap|{middle}|baseline|bottom"
4510 
4511  // hidden properties for limit computation
4512  row_vector_property xlim hlr , Matrix ()
4513  row_vector_property ylim hlr , Matrix ()
4514  row_vector_property zlim hlr , Matrix ()
4515  bool_property xliminclude hl , "off"
4516  bool_property yliminclude hl , "off"
4517  bool_property zliminclude hl , "off"
4518  // hidden properties for auto-positioning
4519  radio_property positionmode hu , "{auto}|manual"
4520  radio_property rotationmode hu , "{auto}|manual"
4521  radio_property horizontalalignmentmode hu , "{auto}|manual"
4522  radio_property verticalalignmentmode hu , "{auto}|manual"
4523  radio_property autopos_tag h , "{none}|xlabel|ylabel|zlabel|title"
4524  // hidden property for text rendering
4525  double_property fontsize_points hgr , 0
4526  END_PROPERTIES
4527 
4528  Matrix get_data_position (void) const;
4529  Matrix get_extent_matrix (void) const;
4530  const uint8NDArray& get_pixels (void) const { return pixels; }
4531 
4532  // Text renderer, used for calculation of text size
4533  octave::text_renderer txt_renderer;
4534 
4535  protected:
4536  void init (void)
4537  {
4538  position.add_constraint (dim_vector (1, 3));
4539  cached_units = get_units ();
4540  update_font ();
4541  }
4542 
4543  private:
4544  void update_position (void)
4545  {
4546  Matrix pos = get_data_position ();
4547  Matrix lim;
4548 
4549  lim = Matrix (1, 3, pos(0));
4550  lim(2) = (lim(2) <= 0 ? octave::numeric_limits<double>::Inf () : lim(2));
4551  set_xlim (lim);
4552 
4553  lim = Matrix (1, 3, pos(1));
4554  lim(2) = (lim(2) <= 0 ? octave::numeric_limits<double>::Inf () : lim(2));
4555  set_ylim (lim);
4556 
4557  if (pos.numel () == 3)
4558  {
4559  lim = Matrix (1, 3, pos(2));
4560  lim(2) = (lim(2) <= 0 ? octave::numeric_limits<double>::Inf () : lim(2));
4561  set_zliminclude ("on");
4562  set_zlim (lim);
4563  }
4564  else
4565  set_zliminclude ("off");
4566  }
4567 
4568  void update_text_extent (void);
4569 
4570  void request_autopos (void);
4571  void update_positionmode (void) { request_autopos (); }
4572  void update_rotationmode (void) { request_autopos (); }
4573  void update_horizontalalignmentmode (void) { request_autopos (); }
4574  void update_verticalalignmentmode (void) { request_autopos (); }
4575 
4576  void update_font (void);
4577  void update_string (void) { request_autopos (); update_text_extent (); }
4578  void update_rotation (void) { update_text_extent (); }
4579  void update_color (void) { update_font (); update_text_extent (); }
4580  void update_fontname (void) { update_font (); update_text_extent (); }
4581  void update_fontsize (void) { update_font (); update_text_extent (); }
4582  void update_fontangle (void) { update_font (); update_text_extent (); }
4583  void update_fontweight (void) { update_font (); update_text_extent (); }
4584  void update_interpreter (void) { update_text_extent (); }
4585  void update_horizontalalignment (void) { update_text_extent (); }
4586  void update_verticalalignment (void) { update_text_extent (); }
4587 
4588  void update_units (void);
4589  void update_fontunits (const caseless_str& old_fontunits);
4590 
4591  private:
4592  std::string cached_units;
4593  uint8NDArray pixels;
4594  };
4595 
4596 private:
4597  properties xproperties;
4598 
4599 public:
4600  text (const graphics_handle& mh, const graphics_handle& p)
4601  : base_graphics_object (), xproperties (mh, p)
4602  {
4603  xproperties.set_clipping ("off");
4604  }
4605 
4606  ~text (void) { }
4607 
4608  base_properties& get_properties (void) { return xproperties; }
4609 
4610  const base_properties& get_properties (void) const { return xproperties; }
4611 
4612  bool valid_object (void) const { return true; }
4613 
4614  bool has_readonly_property (const caseless_str& pname) const
4615  {
4616  bool retval = xproperties.has_readonly_property (pname);
4617  if (! retval)
4618  retval = base_properties::has_readonly_property (pname);
4619  return retval;
4620  }
4621 };
4622 
4623 // ---------------------------------------------------------------------
4624 
4625 class OCTINTERP_API image : public base_graphics_object
4626 {
4627 public:
4628  class OCTINTERP_API properties : public base_properties
4629  {
4630  public:
4631  bool is_aliminclude (void) const
4632  { return (aliminclude.is_on () && alphadatamapping.is ("scaled")); }
4633  std::string get_aliminclude (void) const
4634  { return aliminclude.current_value (); }
4635 
4636  bool is_climinclude (void) const
4637  { return (climinclude.is_on () && cdatamapping.is ("scaled")); }
4638  std::string get_climinclude (void) const
4639  { return climinclude.current_value (); }
4640 
4641  octave_value get_color_data (void) const;
4642 
4643  void initialize_data (void) { update_cdata (); }
4644 
4645  // See the genprops.awk script for an explanation of the
4646  // properties declarations.
4647  // Programming note: Keep property list sorted if new ones are added.
4648 
4649  BEGIN_PROPERTIES (image)
4650  array_property alphadata u , Matrix (1, 1, 1.0)
4651  radio_property alphadatamapping al , "{none}|direct|scaled"
4652  array_property cdata u , default_image_cdata ()
4653  radio_property cdatamapping al , "scaled|{direct}"
4654  string_property displayname , ""
4655  radio_property erasemode h , "{normal}|none|xor|background"
4656  row_vector_property xdata mu , Matrix ()
4657  row_vector_property ydata mu , Matrix ()
4658  // hidden properties for limit computation
4659  row_vector_property alim hlr , Matrix ()
4660  row_vector_property clim hlr , Matrix ()
4661  row_vector_property xlim hlr , Matrix ()
4662  row_vector_property ylim hlr , Matrix ()
4663  bool_property aliminclude hlg , "on"
4664  bool_property climinclude hlg , "on"
4665  bool_property xliminclude hl , "on"
4666  bool_property yliminclude hl , "on"
4667  radio_property xdatamode ha , "{auto}|manual"
4668  radio_property ydatamode ha , "{auto}|manual"
4669  END_PROPERTIES
4670 
4671  protected:
4672  void init (void)
4673  {
4674  xdata.add_constraint (2);
4675  xdata.add_constraint (dim_vector (0, 0));
4676  ydata.add_constraint (2);
4677  ydata.add_constraint (dim_vector (0, 0));
4678  cdata.add_constraint ("double");
4679  cdata.add_constraint ("single");
4680  cdata.add_constraint ("logical");
4681  cdata.add_constraint ("uint8");
4682  cdata.add_constraint ("uint16");
4683  cdata.add_constraint ("int16");
4684  cdata.add_constraint ("real");
4685  cdata.add_constraint (dim_vector (-1, -1));
4686  cdata.add_constraint (dim_vector (-1, -1, 3));
4687  alphadata.add_constraint (dim_vector (-1, -1));
4688  alphadata.add_constraint ("double");
4689  alphadata.add_constraint ("uint8");
4690  }
4691 
4692  private:
4693  void update_alphadata (void)
4694  {
4695  if (alphadatamapping_is ("scaled"))
4696  set_alim (alphadata.get_limits ());
4697  else
4698  alim = alphadata.get_limits ();
4699  }
4700 
4701  void update_cdata (void)
4702  {
4703  if (cdatamapping_is ("scaled"))
4704  set_clim (cdata.get_limits ());
4705  else
4706  clim = cdata.get_limits ();
4707 
4708  if (xdatamode.is ("auto"))
4709  update_xdata ();
4710 
4711  if (ydatamode.is ("auto"))
4712  update_ydata ();
4713  }
4714 
4715  void update_xdata (void)
4716  {
4717  if (xdata.get ().is_empty ())
4718  set_xdatamode ("auto");
4719 
4720  if (xdatamode.is ("auto"))
4721  {
4722  set_xdata (get_auto_xdata ());
4723  set_xdatamode ("auto");
4724  }
4725 
4726  Matrix limits = xdata.get_limits ();
4727  float dp = pixel_xsize ();
4728 
4729  limits(0) = limits(0) - dp;
4730  limits(1) = limits(1) + dp;
4731  set_xlim (limits);
4732  }
4733 
4734  void update_ydata (void)
4735  {
4736  if (ydata.get ().is_empty ())
4737  set_ydatamode ("auto");
4738 
4739  if (ydatamode.is ("auto"))
4740  {
4741  set_ydata (get_auto_ydata ());
4742  set_ydatamode ("auto");
4743  }
4744 
4745  Matrix limits = ydata.get_limits ();
4746  float dp = pixel_ysize ();
4747 
4748  limits(0) = limits(0) - dp;
4749  limits(1) = limits(1) + dp;
4750  set_ylim (limits);
4751  }
4752 
4753  Matrix get_auto_xdata (void)
4754  {
4755  dim_vector dv = get_cdata ().dims ();
4756  Matrix data;
4757  if (dv(1) > 0.)
4758  {
4759  data = Matrix (1, 2, 1);
4760  data(1) = dv(1);
4761  }
4762  return data;
4763  }
4764 
4765  Matrix get_auto_ydata (void)
4766  {
4767  dim_vector dv = get_cdata ().dims ();
4768  Matrix data;
4769  if (dv(0) > 0.)
4770  {
4771  data = Matrix (1, 2, 1);
4772  data(1) = dv(0);
4773  }
4774  return data;
4775  }
4776 
4777  float pixel_size (octave_idx_type dim, const Matrix limits)
4778  {
4779  octave_idx_type l = dim - 1;
4780  float dp;
4781 
4782  if (l > 0 && limits(0) != limits(1))
4783  dp = (limits(1) - limits(0))/(2*l);
4784  else
4785  {
4786  if (limits(1) == limits(2))
4787  dp = 0.5;
4788  else
4789  dp = (limits(1) - limits(0))/2;
4790  }
4791  return dp;
4792  }
4793 
4794  public:
4795  float pixel_xsize (void)
4796  {
4797  return pixel_size ((get_cdata ().dims ())(1), xdata.get_limits ());
4798  }
4799 
4800  float pixel_ysize (void)
4801  {
4802  return pixel_size ((get_cdata ().dims ())(0), ydata.get_limits ());
4803  }
4804  };
4805 
4806 private:
4807  properties xproperties;
4808 
4809 public:
4810  image (const graphics_handle& mh, const graphics_handle& p)
4811  : base_graphics_object (), xproperties (mh, p)
4812  {
4813  xproperties.initialize_data ();
4814  }
4815 
4816  ~image (void) { }
4817 
4818  base_properties& get_properties (void) { return xproperties; }
4819 
4820  const base_properties& get_properties (void) const { return xproperties; }
4821 
4822  bool valid_object (void) const { return true; }
4823 
4824  bool has_readonly_property (const caseless_str& pname) const
4825  {
4826  bool retval = xproperties.has_readonly_property (pname);
4827  if (! retval)
4828  retval = base_properties::has_readonly_property (pname);
4829  return retval;
4830  }
4831 };
4832 
4833 // ---------------------------------------------------------------------
4834 
4835 class OCTINTERP_API light : public base_graphics_object
4836 {
4837 public:
4838  class OCTINTERP_API properties : public base_properties
4839  {
4840  // See the genprops.awk script for an explanation of the
4841  // properties declarations.
4842  // Programming note: Keep property list sorted if new ones are added.
4843 
4844  BEGIN_PROPERTIES (light)
4845  color_property color , color_values (1, 1, 1)
4846  array_property position , default_light_position ()
4847  radio_property style , "{infinite}|local"
4848  END_PROPERTIES
4849 
4850  protected:
4851  void init (void)
4852  {
4853  position.add_constraint (dim_vector (1, 3));
4854  }
4855  };
4856 
4857 private:
4858  properties xproperties;
4859 
4860 public:
4861  light (const graphics_handle& mh, const graphics_handle& p)
4862  : base_graphics_object (), xproperties (mh, p)
4863  { }
4864 
4865  ~light (void) { }
4866 
4867  base_properties& get_properties (void) { return xproperties; }
4868 
4869  const base_properties& get_properties (void) const { return xproperties; }
4870 
4871  bool valid_object (void) const { return true; }
4872 
4873  bool has_readonly_property (const caseless_str& pname) const
4874  {
4875  bool retval = xproperties.has_readonly_property (pname);
4876  if (! retval)
4877  retval = base_properties::has_readonly_property (pname);
4878  return retval;
4879  }
4880 };
4881 
4882 // ---------------------------------------------------------------------
4883 
4884 class OCTINTERP_API patch : public base_graphics_object
4885 {
4886 public:
4887  class OCTINTERP_API properties : public base_properties
4888  {
4889  public:
4890  octave_value get_color_data (void) const;
4891 
4892  // Matlab allows incoherent data to be stored into patch properties.
4893  // The patch should then be ignored by the renderer.
4894  bool has_bad_data (std::string &msg) const
4895  {
4896  msg = bad_data_msg;
4897  return ! msg.empty ();
4898  }
4899 
4900  bool is_aliminclude (void) const
4901  { return (aliminclude.is_on () && alphadatamapping.is ("scaled")); }
4902  std::string get_aliminclude (void) const
4903  { return aliminclude.current_value (); }
4904 
4905  bool is_climinclude (void) const
4906  { return (climinclude.is_on () && cdatamapping.is ("scaled")); }
4907  std::string get_climinclude (void) const
4908  { return climinclude.current_value (); }
4909 
4910  // See the genprops.awk script for an explanation of the
4911  // properties declarations.
4912  // Programming note: Keep property list sorted if new ones are added.
4913 
4914  BEGIN_PROPERTIES (patch)
4915  radio_property alphadatamapping l , "none|{scaled}|direct"
4916  double_property ambientstrength , 0.3
4917  radio_property backfacelighting , "unlit|lit|{reverselit}"
4918  array_property cdata u , Matrix ()
4919  radio_property cdatamapping l , "{scaled}|direct"
4920  double_property diffusestrength , 0.6
4921  string_property displayname , ""
4922  double_radio_property edgealpha , double_radio_property (1.0, radio_values ("flat|interp"))
4923  color_property edgecolor , color_property (color_values (0, 0, 0), radio_values ("none|flat|interp"))
4924  radio_property edgelighting , "{none}|flat|gouraud|phong"
4925  radio_property erasemode h , "{normal}|none|xor|background"
4926  double_radio_property facealpha , double_radio_property (1.0, radio_values ("flat|interp"))
4927  color_property facecolor , color_property (color_values (0, 0, 0), radio_values ("none|flat|interp"))
4928  radio_property facelighting , "none|{flat}|gouraud|phong"
4929  array_property facenormals m , Matrix ()
4930  radio_property facenormalsmode , "{auto}|manual"
4931  array_property faces u , default_patch_faces ()
4932  array_property facevertexalphadata , Matrix ()
4933  array_property facevertexcdata u , Matrix ()
4934  // FIXME: interpreter is not a property of a Matlab patch.
4935  // Octave uses this for legend() with the string displayname.
4936  radio_property interpreter , "{tex}|none|latex"
4937  radio_property linestyle , "{-}|--|:|-.|none"
4938  double_property linewidth , 0.5
4939  radio_property marker , "{none}|+|o|*|.|x|s|square|d|diamond|^|v|>|<|p|pentagram|h|hexagram"
4940  color_property markeredgecolor , color_property (radio_values ("none|{auto}|flat"), color_values (0, 0, 0))
4941  color_property markerfacecolor , color_property (radio_values ("{none}|auto|flat"), color_values (0, 0, 0))
4942  double_property markersize , 6
4943  radio_property normalmode hsg , "{auto}|manual"
4944  double_property specularcolorreflectance , 1.0
4945  double_property specularexponent , 10.0
4946  double_property specularstrength , 0.9
4947  array_property vertexnormals m , Matrix ()
4948  radio_property vertexnormalsmode , "{auto}|manual"
4949  array_property vertices u , default_patch_vertices ()
4950  array_property xdata u , default_patch_xdata ()
4951  array_property ydata u , default_patch_ydata ()
4952  array_property zdata u , Matrix ()
4953 
4954  // hidden properties for limit computation
4955  row_vector_property alim hlr , Matrix ()
4956  row_vector_property clim hlr , Matrix ()
4957  row_vector_property xlim hlr , Matrix ()
4958  row_vector_property ylim hlr , Matrix ()
4959  row_vector_property zlim hlr , Matrix ()
4960  bool_property aliminclude hlg , "on"
4961  bool_property climinclude hlg , "on"
4962  bool_property xliminclude hl , "on"
4963  bool_property yliminclude hl , "on"
4964  bool_property zliminclude hl , "on"
4965  END_PROPERTIES
4966 
4967  protected:
4968  void init (void)
4969  {
4970  xdata.add_constraint (dim_vector (-1, -1));
4971  ydata.add_constraint (dim_vector (-1, -1));
4972  zdata.add_constraint (dim_vector (-1, -1));
4973  faces.add_constraint (dim_vector (-1, -1));
4974  vertices.add_constraint (dim_vector (-1, 2));
4975  vertices.add_constraint (dim_vector (-1, 3));
4976  cdata.add_constraint (dim_vector (-1, -1));
4977  cdata.add_constraint (dim_vector (-1, -1, 3));
4978  facevertexcdata.add_constraint (dim_vector (-1, 1));
4979  facevertexcdata.add_constraint (dim_vector (-1, 3));
4980  facevertexalphadata.add_constraint (dim_vector (-1, 1));
4981  facenormals.add_constraint (dim_vector (-1, 3));
4982  facenormals.add_constraint (dim_vector (0, 0));
4983  vertexnormals.add_constraint (dim_vector (-1, 3));
4984  vertexnormals.add_constraint (dim_vector (0, 0));
4985  }
4986 
4987  private:
4988  std::string bad_data_msg;
4989 
4990  void update_faces (void) { update_data ();}
4991 
4992  void update_vertices (void) { update_data ();}
4993 
4994  void update_facevertexcdata (void) { update_data ();}
4995 
4996  void update_fvc (void);
4997 
4998  void update_xdata (void)
4999  {
5000  if (get_xdata ().is_empty ())
5001  {
5002  // For compatibility with matlab behavior,
5003  // if x/ydata are set empty, silently empty other *data and
5004  // faces properties while vertices remain unchanged.
5005  set_ydata (Matrix ());
5006  set_zdata (Matrix ());
5007  set_cdata (Matrix ());
5008  set_faces (Matrix ());
5009  }
5010  else
5011  update_fvc ();
5012 
5013  set_xlim (xdata.get_limits ());
5014  }
5015 
5016  void update_ydata (void)
5017  {
5018  if (get_ydata ().is_empty ())
5019  {
5020  set_xdata (Matrix ());
5021  set_zdata (Matrix ());
5022  set_cdata (Matrix ());
5023  set_faces (Matrix ());
5024  }
5025  else
5026  update_fvc ();
5027 
5028  set_ylim (ydata.get_limits ());
5029  }
5030 
5031  void update_zdata (void)
5032  {
5033  update_fvc ();
5034  set_zlim (zdata.get_limits ());
5035  }
5036 
5037  void update_cdata (void)
5038  {
5039  update_fvc ();
5040 
5041  if (cdatamapping_is ("scaled"))
5042  set_clim (cdata.get_limits ());
5043  else
5044  clim = cdata.get_limits ();
5045  }
5046 
5047  void update_data (void);
5048 
5049  void set_normalmode (const octave_value& val)
5050  {
5051  warning_with_id ("Octave:deprecated-property",
5052  "patch: Property 'normalmode' is deprecated and will be removed "
5053  "from a future version of Octave. Use 'vertexnormalsmode' instead.");
5054  set_vertexnormalsmode (val);
5055  }
5056 
5057  std::string get_normalmode (void) const
5058  {
5059  warning_with_id ("Octave:deprecated-property",
5060  "patch: Property 'normalmode' is deprecated and will be removed "
5061  "from a future version of Octave. Use 'vertexnormalsmode' instead.");
5062  return vertexnormalsmode.current_value ();
5063  }
5064  };
5065 
5066 private:
5067  properties xproperties;
5068 
5069 public:
5070  patch (const graphics_handle& mh, const graphics_handle& p)
5071  : base_graphics_object (), xproperties (mh, p)
5072  { }
5073 
5074  ~patch (void) { }
5075 
5076  base_properties& get_properties (void) { return xproperties; }
5077 
5078  const base_properties& get_properties (void) const { return xproperties; }
5079 
5080  bool valid_object (void) const { return true; }
5081 
5082  bool has_readonly_property (const caseless_str& pname) const
5083  {
5084  bool retval = xproperties.has_readonly_property (pname);
5085  if (! retval)
5086  retval = base_properties::has_readonly_property (pname);
5087  return retval;
5088  }
5089 };
5090 
5091 // ---------------------------------------------------------------------
5092 
5093 class OCTINTERP_API surface : public base_graphics_object
5094 {
5095 public:
5096  class OCTINTERP_API properties : public base_properties
5097  {
5098  public:
5099  octave_value get_color_data (void) const;
5100 
5101  bool is_aliminclude (void) const
5102  { return (aliminclude.is_on () && alphadatamapping.is ("scaled")); }
5103  std::string get_aliminclude (void) const
5104  { return aliminclude.current_value (); }
5105 
5106  bool is_climinclude (void) const
5107  { return (climinclude.is_on () && cdatamapping.is ("scaled")); }
5108  std::string get_climinclude (void) const
5109  { return climinclude.current_value (); }
5110 
5111  // See the genprops.awk script for an explanation of the
5112  // properties declarations.
5113  // Programming note: Keep property list sorted if new ones are added.
5114 
5115  BEGIN_PROPERTIES (surface)
5116  array_property alphadata u , Matrix (1, 1, 1.0)
5117  radio_property alphadatamapping l , "none|direct|{scaled}"
5118  double_property ambientstrength , 0.3
5119  radio_property backfacelighting , "unlit|lit|{reverselit}"
5120  array_property cdata u , default_surface_cdata ()
5121  radio_property cdatamapping al , "{scaled}|direct"
5122  string_property cdatasource , ""
5123  double_property diffusestrength , 0.6
5124  string_property displayname , ""
5125  double_radio_property edgealpha , double_radio_property (1.0, radio_values ("flat|interp"))
5126  color_property edgecolor , color_property (color_values (0, 0, 0), radio_values ("none|flat|interp"))
5127  radio_property edgelighting , "{none}|flat|gouraud|phong"
5128  radio_property erasemode h , "{normal}|none|xor|background"
5129  double_radio_property facealpha , double_radio_property (1.0, radio_values ("flat|interp|texturemap"))
5130  color_property facecolor , color_property (radio_values ("none|{flat}|interp|texturemap"), color_values (0, 0, 0))
5131  radio_property facelighting , "none|{flat}|gouraud|phong"
5132  array_property facenormals m , Matrix ()
5133  radio_property facenormalsmode , "{auto}|manual"
5134  // FIXME: interpreter is not a Matlab surface property
5135  // Octave uses this for legend() with the string displayname.
5136  radio_property interpreter , "{tex}|none|latex"
5137  radio_property linestyle , "{-}|--|:|-.|none"
5138  double_property linewidth , 0.5
5139  radio_property marker , "{none}|+|o|*|.|x|s|square|d|diamond|^|v|>|<|p|pentagram|h|hexagram"
5140  color_property markeredgecolor , color_property (radio_values ("none|{auto}|flat"), color_values (0, 0, 0))
5141  color_property markerfacecolor , color_property (radio_values ("{none}|auto|flat"), color_values (0, 0, 0))
5142  double_property markersize , 6
5143  radio_property meshstyle , "{both}|row|column"
5144  radio_property normalmode hsg , "{auto}|manual"
5145  double_property specularcolorreflectance , 1
5146  double_property specularexponent , 10
5147  double_property specularstrength , 0.9
5148  array_property vertexnormals m , Matrix ()
5149  radio_property vertexnormalsmode u , "{auto}|manual"
5150  array_property xdata u , default_surface_xdata ()
5151  string_property xdatasource , ""
5152  array_property ydata u , default_surface_ydata ()
5153  string_property ydatasource , ""
5154  array_property zdata u , default_surface_zdata ()
5155  string_property zdatasource , ""