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