3 Copyright (C) 2007, 2008, 2009 John W. Eaton
5 This file is part of Octave.
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
39 #include "file-stat.h"
50 #include "ov-fcn-handle.h"
53 #include "unwind-prot.h"
55 // forward declaration
56 static octave_value xget (const graphics_handle& h, const caseless_str& name);
59 gripe_set_invalid (const std::string& pname)
61 error ("set: invalid value for %s property", pname.c_str ());
67 Matrix cmap (64, 3, 0.0);
69 for (octave_idx_type i = 0; i < 64; i++)
71 // This is the jet colormap. It would be nice to be able
72 // to feval the jet function but since there is a static
73 // property object that includes a colormap_property
74 // object, we need to initialize this before main is even
75 // called, so calling an interpreted function is not
80 if (x >= 3.0/8.0 && x < 5.0/8.0)
81 cmap(i,0) = 4.0 * x - 3.0/2.0;
82 else if (x >= 5.0/8.0 && x < 7.0/8.0)
84 else if (x >= 7.0/8.0)
85 cmap(i,0) = -4.0 * x + 9.0/2.0;
87 if (x >= 1.0/8.0 && x < 3.0/8.0)
88 cmap(i,1) = 4.0 * x - 1.0/2.0;
89 else if (x >= 3.0/8.0 && x < 5.0/8.0)
91 else if (x >= 5.0/8.0 && x < 7.0/8.0)
92 cmap(i,1) = -4.0 * x + 7.0/2.0;
95 cmap(i,2) = 4.0 * x + 1.0/2.0;
96 else if (x >= 1.0/8.0 && x < 3.0/8.0)
98 else if (x >= 3.0/8.0 && x < 5.0/8.0)
99 cmap(i,2) = -4.0 * x + 5.0/2.0;
106 default_screendepth (void)
108 return display_info::depth ();
112 default_screensize (void)
114 Matrix retval (1, 4, 1.0);
116 retval(2) = display_info::width ();
117 retval(3) = display_info::height ();
123 default_screenpixelsperinch (void)
125 return (display_info::x_dpi () + display_info::y_dpi ()) / 2;
129 default_colororder (void)
131 Matrix retval (7, 3, 0.0);
166 Matrix retval (1, 2);
175 default_axes_position (void)
177 Matrix m (1, 4, 0.0);
186 default_axes_outerposition (void)
188 Matrix m (1, 4, 0.0);
194 default_axes_tick (void)
196 Matrix m (1, 6, 0.0);
207 default_axes_ticklength (void)
209 Matrix m (1, 2, 0.01);
215 default_figure_position (void)
217 Matrix m (1, 4, 0.0);
226 default_figure_papersize (void)
228 Matrix m (1, 2, 0.0);
235 default_figure_paperposition (void)
237 Matrix m (1, 4, 0.0);
246 convert_position (const Matrix& pos, const caseless_str& from_units,
247 const caseless_str& to_units,
248 const Matrix& parent_dim = Matrix (1, 2, 0.0))
250 Matrix retval (1, 4);
253 if (from_units.compare ("pixels"))
255 else if (from_units.compare ("normalized"))
257 retval(0) = pos(0) * parent_dim(0) + 1;
258 retval(1) = pos(1) * parent_dim(1) + 1;
259 retval(2) = pos(2) * parent_dim(0);
260 retval(3) = pos(3) * parent_dim(1);
262 else if (from_units.compare ("characters"))
265 res = xget (0, "screenpixelsperinch").double_value ();
269 // FIXME -- this assumes the system font is Helvetica 10pt
270 // (for which "x" requires 6x12 pixels at 74.951 pixels/inch)
271 f = 12.0 * res / 74.951;
275 retval(0) = 0.5 * pos(0) * f;
276 retval(1) = pos(1) * f;
277 retval(2) = 0.5 * pos(2) * f;
278 retval(3) = pos(3) * f;
284 res = xget (0, "screenpixelsperinch").double_value ();
288 if (from_units.compare ("points"))
290 else if (from_units.compare ("inches"))
292 else if (from_units.compare ("centimeters"))
297 retval(0) = pos(0) * f + 1;
298 retval(1) = pos(1) * f + 1;
299 retval(2) = pos(2) * f;
300 retval(3) = pos(3) * f;
304 if (! to_units.compare ("pixels"))
306 if (to_units.compare ("normalized"))
308 retval(0) = (retval(0) - 1) / parent_dim(0);
309 retval(1) = (retval(1) - 1) / parent_dim(1);
310 retval(2) /= parent_dim(0);
311 retval(3) /= parent_dim(1);
313 else if (to_units.compare ("characters"))
316 res = xget (0, "screenpixelsperinch").double_value ();
320 f = 12.0 * res / 74.951;
324 retval(0) = 2 * retval(0) / f;
325 retval(1) = retval(1) / f;
326 retval(2) = 2 * retval(2) / f;
327 retval(3) = retval(3) / f;
333 res = xget (0, "screenpixelsperinch").double_value ();
337 if (to_units.compare ("points"))
339 else if (to_units.compare ("inches"))
341 else if (to_units.compare ("centimeters"))
346 retval(0) = (retval(0) - 1) / f;
347 retval(1) = (retval(1) - 1) / f;
357 static graphics_object
358 xget_ancestor (const graphics_object& go_arg, const std::string& type)
360 graphics_object go = go_arg;
364 if (go.valid_object ())
369 go = gh_manager::get_object (go.get_parent ());
372 return graphics_object ();
378 convert_cdata (const base_properties& props, const octave_value& cdata,
379 bool is_scaled, int cdim)
381 dim_vector dv (cdata.dims ());
383 if (dv.length () == cdim && dv(cdim-1) == 3)
386 Matrix cmap (1, 3, 0.0);
387 Matrix clim (1, 2, 0.0);
389 graphics_object go = gh_manager::get_object (props.get___myhandle__ ());
390 graphics_object fig = xget_ancestor (go, "figure");
392 if (fig.valid_object ())
394 Matrix _cmap = fig.get (caseless_str ("colormap")).matrix_value ();
402 graphics_object ax = xget_ancestor (go, "axes");
404 if (ax.valid_object ())
406 Matrix _clim = ax.get (caseless_str ("clim")).matrix_value ();
418 octave_idx_type lda = a.numel () / static_cast<octave_idx_type> (3);
419 octave_idx_type nc = cmap.rows ();
421 double *av = a.fortran_vec ();
422 const double *cmapv = cmap.data ();
423 const double *cv = 0;
424 const octave_uint8 *icv = 0;
426 if (cdata.is_integer_type ())
427 icv = cdata.uint8_array_value ().data ();
429 cv = cdata.array_value ().data ();
431 for (octave_idx_type i = 0; i < lda; i++)
433 double x = (cv ? cv[i] : double (icv[i]));
436 x = xround ((nc - 1) * (x - clim(0)) / (clim(1) - clim(0)));
445 octave_idx_type idx = static_cast<octave_idx_type> (x);
448 av[i+lda] = cmapv[idx+nc];
449 av[i+2*lda] = cmapv[idx+2*nc];
452 return octave_value (a);
457 get_array_limits (const Array<T>& m, double& emin, double& emax,
460 const T *data = m.data ();
461 octave_idx_type n = m.numel ();
463 for (octave_idx_type i = 0; i < n; i++)
465 double e = double (data[i]);
467 if (! (xisinf (e) || xisnan (e)))
475 if (e > 0 && e < eminp)
482 lookup_object_name (const caseless_str& name, caseless_str& go_name,
485 int len = name.length ();
491 caseless_str pfx = name.substr (0, 4);
493 if (pfx.compare ("axes") || pfx.compare ("line")
494 || pfx.compare ("text"))
498 pfx = name.substr (0, 5);
500 if (pfx.compare ("image") || pfx.compare ("patch"))
504 pfx = name.substr (0, 6);
506 if (pfx.compare ("figure"))
510 pfx = name.substr (0, 7);
512 if (pfx.compare ("surface") || pfx.compare ("hggroup"))
521 rest = name.substr (offset);
529 static base_graphics_object*
530 make_graphics_object_from_type (const caseless_str& type,
531 const graphics_handle& h = graphics_handle (),
532 const graphics_handle& p = graphics_handle ())
534 base_graphics_object *go = 0;
536 if (type.compare ("figure"))
537 go = new figure (h, p);
538 else if (type.compare ("axes"))
539 go = new axes (h, p);
540 else if (type.compare ("line"))
541 go = new line (h, p);
542 else if (type.compare ("text"))
543 go = new text (h, p);
544 else if (type.compare ("image"))
545 go = new image (h, p);
546 else if (type.compare ("patch"))
547 go = new patch (h, p);
548 else if (type.compare ("surface"))
549 go = new surface (h, p);
550 else if (type.compare ("hggroup"))
551 go = new hggroup (h, p);
556 // ---------------------------------------------------------------------
559 base_property::set (const octave_value& v, bool do_run )
567 graphics_object go = gh_manager::get_object (parent);
570 graphics_backend backend = go.get_backend();
572 backend.property_changed (go, id);
577 if (do_run && ! error_state)
578 run_listeners (POSTSET);
588 base_property::run_listeners (listener_mode mode)
590 const octave_value_list& l = listeners[mode];
592 for (int i = 0; i < l.length (); i++)
594 gh_manager::execute_callback (parent, l(i), octave_value ());
601 radio_values::radio_values (const std::string& opt_string)
604 size_t len = opt_string.length ();
605 bool done = len == 0;
609 size_t end = opt_string.find ('|', beg);
611 if (end == std::string::npos)
617 std::string t = opt_string.substr (beg, end-beg);
619 // Might want more error checking here...
622 t = t.substr (1, t.length () - 2);
625 else if (beg == 0) // ensure default value
628 possible_vals.insert (t);
635 color_values::str2rgb (std::string str)
637 double tmp_rgb[3] = {0, 0, 0};
639 unsigned int len = str.length();
641 std::transform (str.begin (), str.end (), str.begin (), tolower);
643 if (str.compare(0, len, "blue", 0, len) == 0)
645 else if (str.compare(0, len, "black", 0, len) == 0
646 || str.compare(0, len, "k", 0, len) == 0)
647 tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 0;
648 else if (str.compare(0, len, "red", 0, len) == 0)
650 else if (str.compare(0, len, "green", 0, len) == 0)
652 else if (str.compare(0, len, "yellow", 0, len) == 0)
653 tmp_rgb[0] = tmp_rgb[1] = 1;
654 else if (str.compare(0, len, "magenta", 0, len) == 0)
655 tmp_rgb[0] = tmp_rgb[2] = 1;
656 else if (str.compare(0, len, "cyan", 0, len) == 0)
657 tmp_rgb[1] = tmp_rgb[2] = 1;
658 else if (str.compare(0, len, "white", 0, len) == 0
659 || str.compare(0, len, "w", 0, len) == 0)
660 tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 1;
666 for (int i = 0; i < 3; i++)
667 xrgb(i) = tmp_rgb[i];
674 color_property::do_set (const octave_value& val)
676 if (val.is_string ())
678 std::string s = val.string_value ();
682 if (radio_val.contains (s))
684 if (current_type != radio_t || current_val != s)
687 current_type = radio_t;
693 color_values col (s);
696 if (current_type != color_t || col != color_val)
699 current_type = color_t;
704 error ("invalid value for color property \"%s\" (value = %s)",
705 get_name ().c_str (), s.c_str ());
709 error ("invalid value for color property \"%s\"",
710 get_name ().c_str ());
712 else if (val.is_numeric_type ())
714 Matrix m = val.matrix_value ();
718 color_values col (m (0), m (1), m(2));
721 if (current_type != color_t || col != color_val)
724 current_type = color_t;
730 error ("invalid value for color property \"%s\"",
731 get_name ().c_str ());
734 error ("invalid value for color property \"%s\"",
735 get_name ().c_str ());
741 double_radio_property::do_set (const octave_value& val)
743 if (val.is_string ())
745 std::string s = val.string_value ();
747 if (! s.empty () && radio_val.contains (s))
749 if (current_type != radio_t || s != current_val)
752 current_type = radio_t;
757 error ("invalid value for double_radio property \"%s\"",
758 get_name ().c_str ());
760 else if (val.is_scalar_type () && val.is_real_type ())
762 double new_dval = val.double_value ();
764 if (current_type != double_t || new_dval != dval)
767 current_type = double_t;
772 error ("invalid value for double_radio property \"%s\"",
773 get_name ().c_str ());
779 array_property::validate (const octave_value& v)
783 // FIXME -- should we always support []?
784 if (v.is_empty () && v.is_numeric_type ())
788 if (type_constraints.size () > 0)
790 for (std::list<std::string>::const_iterator it = type_constraints.begin ();
791 ! xok && it != type_constraints.end (); ++it)
792 if ((*it) == v.class_name ())
796 xok = v.is_numeric_type ();
800 dim_vector vdims = v.dims ();
801 int vlen = vdims.length ();
806 if (size_constraints.size () > 0)
807 for (std::list<dim_vector>::const_iterator it = size_constraints.begin ();
808 ! xok && it != size_constraints.end (); ++it)
810 dim_vector itdims = (*it);
812 if (itdims.length () == vlen)
816 for (int i = 0; xok && i < vlen; i++)
817 if (itdims(i) >= 0 && itdims(i) != vdims(i))
829 array_property::is_equal (const octave_value& v) const
831 if (data.type_name () == v.type_name ())
833 if (data.dims () == v.dims ())
836 #define CHECK_ARRAY_EQUAL(T,F,A) \
838 if (data.numel () == 1) \
839 return data.F ## scalar_value () == \
840 v.F ## scalar_value (); \
843 /* Keep copy of array_value to allow sparse/bool arrays */ \
844 /* that are converted, to not be deallocated early */ \
845 const A m1 = data.F ## array_value (); \
846 const T* d1 = m1.data (); \
847 const A m2 = v.F ## array_value (); \
848 const T* d2 = m2.data ();\
852 for (int i = 0; flag && i < data.numel (); i++) \
853 if (d1[i] != d2[i]) \
860 if (data.is_double_type() || data.is_bool_type ())
861 CHECK_ARRAY_EQUAL (double, , NDArray)
862 else if (data.is_single_type ())
863 CHECK_ARRAY_EQUAL (float, float_, FloatNDArray)
864 else if (data.is_int8_type ())
865 CHECK_ARRAY_EQUAL (octave_int8, int8_, int8NDArray)
866 else if (data.is_int16_type ())
867 CHECK_ARRAY_EQUAL (octave_int16, int16_, int16NDArray)
868 else if (data.is_int32_type ())
869 CHECK_ARRAY_EQUAL (octave_int32, int32_, int32NDArray)
870 else if (data.is_int64_type ())
871 CHECK_ARRAY_EQUAL (octave_int64, int64_, int64NDArray)
872 else if (data.is_uint8_type ())
873 CHECK_ARRAY_EQUAL (octave_uint8, uint8_, uint8NDArray)
874 else if (data.is_uint16_type ())
875 CHECK_ARRAY_EQUAL (octave_uint16, uint16_, uint16NDArray)
876 else if (data.is_uint32_type ())
877 CHECK_ARRAY_EQUAL (octave_uint32, uint32_, uint32NDArray)
878 else if (data.is_uint64_type ())
879 CHECK_ARRAY_EQUAL (octave_uint64, uint64_, uint64NDArray)
887 array_property::get_data_limits (void)
889 xmin = xminp = octave_Inf;
892 if (! data.is_empty ())
894 if (data.is_integer_type ())
896 if (data.is_int8_type ())
897 get_array_limits (data.int8_array_value (), xmin, xmax, xminp);
898 else if (data.is_uint8_type ())
899 get_array_limits (data.uint8_array_value (), xmin, xmax, xminp);
900 else if (data.is_int16_type ())
901 get_array_limits (data.int16_array_value (), xmin, xmax, xminp);
902 else if (data.is_uint16_type ())
903 get_array_limits (data.uint16_array_value (), xmin, xmax, xminp);
904 else if (data.is_int32_type ())
905 get_array_limits (data.int32_array_value (), xmin, xmax, xminp);
906 else if (data.is_uint32_type ())
907 get_array_limits (data.uint32_array_value (), xmin, xmax, xminp);
908 else if (data.is_int64_type ())
909 get_array_limits (data.int64_array_value (), xmin, xmax, xminp);
910 else if (data.is_uint64_type ())
911 get_array_limits (data.uint64_array_value (), xmin, xmax, xminp);
914 get_array_limits (data.array_value (), xmin, xmax, xminp);
919 handle_property::do_set (const octave_value& v)
921 double dv = v.double_value ();
925 graphics_handle gh = gh_manager::lookup (dv);
927 if (xisnan (gh.value ()) || gh.ok ())
929 if (current_val != gh)
936 error ("set: invalid graphics handle (= %g) for property \"%s\"",
937 dv, get_name ().c_str ());
940 error ("set: invalid graphics handle for property \"%s\"",
941 get_name ().c_str ());
947 callback_property::validate (const octave_value& v) const
949 // case 1: function handle
950 // case 2: cell array with first element being a function handle
951 // case 3: string corresponding to known function name
952 // case 4: evaluatable string
953 // case 5: empty matrix
955 if (v.is_function_handle ())
957 else if (v.is_string ())
958 // complete validation will be done at execution-time
960 else if (v.is_cell () && v.length () > 0
961 && (v.rows() == 1 || v.columns () == 1)
962 && v.cell_value ()(0).is_function_handle ())
964 else if (v.is_empty ())
971 callback_property::execute (const octave_value& data) const
973 if (callback.is_defined () && ! callback.is_empty ())
974 gh_manager::execute_callback (get_parent (), callback, data);
977 // Used to cache dummy graphics objects from which dynamic
978 // properties can be cloned.
979 static std::map<caseless_str, graphics_object> dprop_obj_map;
982 property::create (const std::string& name, const graphics_handle& h,
983 const caseless_str& type, const octave_value_list& args)
987 if (type.compare ("string"))
989 std::string val = (args.length () > 0 ? args(0).string_value () : "");
992 retval = property (new string_property (name, h, val));
994 else if (type.compare ("any"))
997 (args.length () > 0 ? args(0) : octave_value (Matrix ()));
999 retval = property (new any_property (name, h, val));
1001 else if (type.compare ("radio"))
1003 if (args.length () > 0)
1005 std::string vals = args(0).string_value ();
1009 retval = property (new radio_property (name, h, vals));
1011 if (args.length () > 1)
1012 retval.set (args(1));
1015 error ("addproperty: invalid argument for radio property, expected a string value");
1018 error ("addproperty: missing possible values for radio property");
1020 else if (type.compare ("double"))
1022 double d = (args.length () > 0 ? args(0).double_value () : 0);
1025 retval = property (new double_property (name, h, d));
1027 else if (type.compare ("handle"))
1029 double hh = (args.length () > 0 ? args(0).double_value () : octave_NaN);
1033 graphics_handle gh (hh);
1035 retval = property (new handle_property (name, h, gh));
1038 else if (type.compare ("boolean"))
1040 retval = property (new bool_property (name, h, false));
1042 if (args.length () > 0)
1043 retval.set (args(0));
1045 else if (type.compare ("data"))
1047 retval = property (new array_property (name, h, Matrix ()));
1049 if (args.length () > 0)
1051 retval.set (args(0));
1053 // FIXME -- additional argument could define constraints,
1054 // but is this really useful?
1057 else if (type.compare ("color"))
1059 color_values cv (0, 0, 0);
1062 if (args.length () > 1)
1063 rv = radio_values (args(1).string_value ());
1067 retval = property (new color_property (name, h, cv, rv));
1071 if (args.length () > 0 && ! args(0).is_empty ())
1072 retval.set (args(0));
1074 retval.set (rv.default_value ());
1080 caseless_str go_name, go_rest;
1082 if (lookup_object_name (type, go_name, go_rest))
1086 std::map<caseless_str, graphics_object>::const_iterator it =
1087 dprop_obj_map.find (go_name);
1089 if (it == dprop_obj_map.end ())
1091 base_graphics_object *bgo =
1092 make_graphics_object_from_type (go_name);
1096 go = graphics_object (bgo);
1098 dprop_obj_map[go_name] = go;
1104 if (go.valid_object ())
1106 property prop = go.get_properties ().get_property (go_rest);
1110 retval = prop.clone ();
1112 retval.set_parent (h);
1113 retval.set_name (name);
1115 if (args.length () > 0)
1116 retval.set (args(0));
1120 error ("addproperty: invalid object type (= %s)",
1124 error ("addproperty: unsupported type for dynamic property (= %s)",
1131 // ---------------------------------------------------------------------
1134 property_list::set (const caseless_str& name, const octave_value& val)
1138 size_t len = name.length ();
1142 caseless_str pfx = name.substr (0, 4);
1144 if (pfx.compare ("axes") || pfx.compare ("line")
1145 || pfx.compare ("text"))
1149 pfx = name.substr (0, 5);
1151 if (pfx.compare ("image") || pfx.compare ("patch"))
1155 pfx = name.substr (0, 6);
1157 if (pfx.compare ("figure"))
1161 pfx = name.substr (0, 7);
1163 if (pfx.compare ("surface") || pfx.compare ("hggroup"))
1171 // FIXME -- should we validate property names and values here?
1173 std::string pname = name.substr (offset);
1175 std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
1176 std::transform (pname.begin (), pname.end (), pname.begin (), tolower);
1178 bool has_property = false;
1180 has_property = axes::properties::has_property (pname);
1181 else if (pfx == "line")
1182 has_property = line::properties::has_property (pname);
1183 else if (pfx == "text")
1184 has_property = text::properties::has_property (pname);
1185 else if (pfx == "image")
1186 has_property = image::properties::has_property (pname);
1187 else if (pfx == "patch")
1188 has_property = patch::properties::has_property (pname);
1189 else if (pfx == "figure")
1190 has_property = figure::properties::has_property (pname);
1191 else if (pfx == "surface")
1192 has_property = surface::properties::has_property (pname);
1193 else if (pfx == "hggroup")
1194 has_property = hggroup::properties::has_property (pname);
1198 bool remove = false;
1199 if (val.is_string ())
1201 caseless_str tval = val.string_value ();
1203 remove = tval.compare ("remove");
1206 pval_map_type& pval_map = plist_map[pfx];
1210 pval_map_iterator p = pval_map.find (pname);
1212 if (p != pval_map.end ())
1216 pval_map[pname] = val;
1219 error ("invalid %s property `%s'", pfx.c_str (), pname.c_str ());
1223 if (! error_state && offset == 0)
1224 error ("invalid default property specification");
1228 property_list::lookup (const caseless_str& name) const
1230 octave_value retval;
1234 size_t len = name.length ();
1238 caseless_str pfx = name.substr (0, 4);
1240 if (pfx.compare ("axes") || pfx.compare ("line")
1241 || pfx.compare ("text"))
1245 pfx = name.substr (0, 5);
1247 if (pfx.compare ("image") || pfx.compare ("patch"))
1251 pfx = name.substr (0, 6);
1253 if (pfx.compare ("figure"))
1257 pfx = name.substr (0, 7);
1259 if (pfx.compare ("surface") || pfx.compare ("hggroup"))
1267 std::string pname = name.substr (offset);
1269 std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
1270 std::transform (pname.begin (), pname.end (), pname.begin (), tolower);
1272 plist_map_const_iterator p = find (pfx);
1276 const pval_map_type& pval_map = p->second;
1278 pval_map_const_iterator q = pval_map.find (pname);
1280 if (q != pval_map.end ())
1290 property_list::as_struct (const std::string& prefix_arg) const
1294 for (plist_map_const_iterator p = begin (); p != end (); p++)
1296 std::string prefix = prefix_arg + p->first;
1298 const pval_map_type pval_map = p->second;
1300 for (pval_map_const_iterator q = pval_map.begin ();
1301 q != pval_map.end ();
1303 m.assign (prefix + q->first, q->second);
1309 graphics_handle::graphics_handle (const octave_value& a)
1316 double tval = a.double_value ();
1321 error ("invalid graphics handle");
1326 graphics_object::set (const octave_value_list& args)
1328 int nargin = args.length ();
1332 else if (nargin % 2 == 0)
1334 for (int i = 0; i < nargin; i += 2)
1336 caseless_str name = args(i).string_value ();
1340 octave_value val = args(i+1);
1342 if (val.is_string ())
1344 caseless_str tval = val.string_value ();
1346 if (tval.compare ("default"))
1347 val = get_default (name);
1348 else if (tval.compare ("factory"))
1349 val = get_factory_default (name);
1355 rep->set (name, val);
1358 error ("set: expecting argument %d to be a property name", i);
1362 error ("set: invalid number of arguments");
1366 make_handle_fraction (void)
1368 static double maxrand = RAND_MAX + 2.0;
1370 return (rand () + 1.0) / maxrand;
1374 gh_manager::get_handle (const std::string& go_name)
1376 graphics_handle retval;
1378 if (go_name == "figure")
1380 // Figure handles are positive integers corresponding to the
1383 // We always want the lowest unused figure number.
1387 while (handle_map.find (retval) != handle_map.end ())
1392 // Other graphics handles are negative integers plus some random
1393 // fractional part. To avoid running out of integers, we
1394 // recycle the integer part but tack on a new random part each
1397 free_list_iterator p = handle_free_list.begin ();
1399 if (p != handle_free_list.end ())
1402 handle_free_list.erase (p);
1406 retval = graphics_handle (next_handle);
1408 next_handle = ceil (next_handle) - 1.0 - make_handle_fraction ();
1416 gh_manager::do_free (const graphics_handle& h)
1420 if (h.value () != 0)
1422 iterator p = handle_map.find (h);
1424 if (p != handle_map.end ())
1426 base_properties& bp = p->second.get_properties ();
1428 bp.set_beingdeleted (true);
1430 bp.delete_children ();
1432 octave_value val = bp.get_deletefcn ();
1434 bp.execute_deletefcn ();
1437 graphics_backend backend = p->second.get_backend ();
1439 backend.object_destroyed (p->second);
1441 // Note: this will be valid only for first explicitly
1442 // deleted object. All its children will then have an
1445 // Graphics handles for non-figure objects are negative
1446 // integers plus some random fractional part. To avoid
1447 // running out of integers, we recycle the integer part
1448 // but tack on a new random part each time.
1450 handle_map.erase (p);
1453 handle_free_list.insert (ceil (h.value ()) - make_handle_fraction ());
1456 error ("graphics_handle::free: invalid object %g", h.value ());
1459 error ("graphics_handle::free: can't delete root figure");
1463 gh_manager *gh_manager::instance = 0;
1466 xset (const graphics_handle& h, const caseless_str& name,
1467 const octave_value& val)
1469 graphics_object obj = gh_manager::get_object (h);
1470 obj.set (name, val);
1474 xset (const graphics_handle& h, const octave_value_list& args)
1476 if (args.length () > 0)
1478 graphics_object obj = gh_manager::get_object (h);
1485 xget (const graphics_handle& h, const caseless_str& name)
1487 graphics_object obj = gh_manager::get_object (h);
1488 return obj.get (name);
1491 static graphics_handle
1492 reparent (const octave_value& ov, const std::string& who,
1493 const std::string& property, const graphics_handle& new_parent,
1496 graphics_handle h = octave_NaN;
1498 double val = ov.double_value ();
1502 h = gh_manager::lookup (val);
1506 graphics_object obj = gh_manager::get_object (h);
1508 graphics_handle parent_h = obj.get_parent ();
1510 graphics_object parent_obj = gh_manager::get_object (parent_h);
1512 parent_obj.remove_child (h);
1515 obj.set ("parent", new_parent.value ());
1517 obj.reparent (new_parent);
1520 error ("%s: invalid graphics handle (= %g) for %s",
1521 who.c_str (), val, property.c_str ());
1524 error ("%s: expecting %s to be a graphics handle",
1525 who.c_str (), property.c_str ());
1530 // This function is NOT equivalent to the scripting language function gcf.
1534 octave_value val = xget (0, "currentfigure");
1536 return val.is_empty () ? octave_NaN : val.double_value ();
1539 // This function is NOT equivalent to the scripting language function gca.
1543 octave_value val = xget (gcf (), "currentaxes");
1545 return val.is_empty () ? octave_NaN : val.double_value ();
1549 adopt (const graphics_handle& p, const graphics_handle& h)
1551 graphics_object parent_obj = gh_manager::get_object (p);
1553 parent_obj.adopt (h);
1557 is_handle (const graphics_handle& h)
1563 is_handle (double val)
1565 graphics_handle h = gh_manager::lookup (val);
1571 is_handle (const octave_value& val)
1573 octave_value retval = false;
1575 if (val.is_real_scalar () && is_handle (val.double_value ()))
1577 else if (val.is_real_matrix ())
1579 if (val.is_string ())
1580 retval = boolNDArray (val.dims (), false);
1583 const NDArray handles = val.array_value ();
1587 boolNDArray result (handles.dims ());
1589 for (octave_idx_type i = 0; i < handles.numel (); i++)
1590 result.xelem (i) = is_handle (handles (i));
1601 is_figure (double val)
1603 graphics_object obj = gh_manager::get_object (val);
1605 return obj && obj.isa ("figure");
1609 xcreatefcn (const graphics_handle& h)
1611 graphics_object obj = gh_manager::get_object (h);
1612 obj.get_properties ().execute_createfcn ();
1615 // ---------------------------------------------------------------------
1618 base_graphics_backend::property_changed (const graphics_handle& h, int id)
1620 graphics_object go = gh_manager::get_object (h);
1622 property_changed (go, id);
1626 base_graphics_backend::object_created (const graphics_handle& h)
1628 graphics_object go = gh_manager::get_object (h);
1630 object_created (go);
1634 base_graphics_backend::object_destroyed (const graphics_handle& h)
1636 graphics_object go = gh_manager::get_object (h);
1638 object_destroyed (go);
1640 // ---------------------------------------------------------------------
1643 maybe_set_children (const Matrix& kids, const octave_value& val)
1645 const Matrix new_kids = val.matrix_value ();
1651 if (kids.numel () == new_kids.numel ())
1654 Matrix t2 = new_kids;
1666 error ("set: new children must be a permutation of existing children");
1671 error ("set: expecting children to be array of graphics handles");
1674 return ok ? new_kids : kids;
1678 base_properties::set_from_list (base_graphics_object& obj,
1679 property_list& defaults)
1681 std::string go_name = graphics_object_name ();
1683 property_list::plist_map_const_iterator p = defaults.find (go_name);
1685 if (p != defaults.end ())
1687 const property_list::pval_map_type pval_map = p->second;
1689 for (property_list::pval_map_const_iterator q = pval_map.begin ();
1690 q != pval_map.end ();
1693 std::string pname = q->first;
1695 obj.set (pname, q->second);
1699 error ("error setting default property %s", pname.c_str ());
1707 base_properties::get_dynamic (const caseless_str& name) const
1709 octave_value retval;
1711 std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.find (name);
1713 if (it != all_props.end ())
1714 retval = it->second.get ();
1716 error ("get: unknown property \"%s\"", name.c_str ());
1722 base_properties::get_dynamic (bool all) const
1726 for (std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.begin ();
1727 it != all_props.end (); ++it)
1728 if (all || ! it->second.is_hidden ())
1729 m.assign (it->second.get_name (), it->second.get ());
1734 std::map<std::string, std::set<std::string> > base_properties::all_dynamic_properties;
1737 base_properties::has_dynamic_property (const std::string& pname,
1738 const std::string& cname)
1740 // FIXME -- we need to maintain a static map of class names to sets
1741 // of dynamic property names, then look up the set for the given
1742 // cname, then see if the set contains the given pname. Doing that
1743 // implies changes to set_dynamic, I think. Where is set_dynamic
1746 std::set<std::string>& dynprops = all_dynamic_properties[cname];
1748 return dynprops.find (pname) != dynprops.end ();
1752 base_properties::set_dynamic (const caseless_str& pname,
1753 const std::string& cname,
1754 const octave_value& val)
1756 std::map<caseless_str, property, cmp_caseless_str>::iterator it = all_props.find (pname);
1758 if (it != all_props.end ())
1759 it->second.set (val);
1761 error ("set: unknown property \"%s\"", pname.c_str ());
1765 all_dynamic_properties[cname].insert (pname);
1772 base_properties::get_property_dynamic (const caseless_str& name)
1774 std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.find (name);
1776 if (it == all_props.end ())
1778 error ("get_property: unknown property \"%s\"", name.c_str ());
1786 base_properties::has_property (const caseless_str& name)
1790 unwind_protect::begin_frame("base_properties::has_property");
1792 unwind_protect_bool (discard_error_messages);
1793 unwind_protect_int (error_state);
1795 discard_error_messages = true;
1797 p = get_property (name);
1799 unwind_protect::run_frame ("base_properties::has_property");
1805 base_properties::remove_child (const graphics_handle& h)
1807 octave_idx_type k = -1;
1808 octave_idx_type n = children.numel ();
1809 for (octave_idx_type i = 0; i < n; i++)
1811 if (h.value () == children(i))
1820 Matrix new_kids (n-1, 1);
1821 octave_idx_type j = 0;
1822 for (octave_idx_type i = 0; i < n; i++)
1825 new_kids(j++) = children(i);
1827 children = new_kids;
1833 base_properties::set_parent (const octave_value& val)
1835 double tmp = val.double_value ();
1837 graphics_handle new_parent = octave_NaN;
1841 new_parent = gh_manager::lookup (tmp);
1843 if (new_parent.ok ())
1845 graphics_object parent_obj = gh_manager::get_object (get_parent ());
1847 parent_obj.remove_child (__myhandle__);
1849 parent = new_parent.as_octave_value ();
1851 ::adopt (parent.handle_value (), __myhandle__);
1854 error ("set: invalid graphics handle (= %g) for parent", tmp);
1857 error ("set: expecting parent to be a graphics handle");
1861 base_properties::set_children (const octave_value& val)
1863 children = maybe_set_children (children, val);
1867 base_properties::mark_modified (void)
1869 __modified__ = "on";
1870 graphics_object parent_obj = gh_manager::get_object (get_parent ());
1872 parent_obj.mark_modified ();
1876 base_properties::override_defaults (base_graphics_object& obj)
1878 graphics_object parent_obj = gh_manager::get_object (get_parent ());
1881 parent_obj.override_defaults (obj);
1885 base_properties::update_axis_limits (const std::string& axis_type) const
1887 graphics_object obj = gh_manager::get_object (__myhandle__);
1890 obj.update_axis_limits (axis_type);
1894 base_properties::delete_children (void)
1896 octave_idx_type n = children.numel ();
1898 // A callback function might have already deleted the child,
1899 // so check before deleting
1900 for (octave_idx_type i = 0; i < n; i++)
1902 graphics_object go = gh_manager::get_object (children(i));
1904 if (go.valid_object ())
1905 gh_manager::free (children(i));
1910 base_properties::get_backend (void) const
1912 graphics_object go = gh_manager::get_object (get_parent ());
1915 return go.get_backend ();
1917 return graphics_backend ();
1921 base_properties::update_boundingbox (void)
1923 Matrix kids = get_children ();
1925 for (int i = 0; i < kids.numel (); i++)
1927 graphics_object go = gh_manager::get_object (kids(i));
1929 if (go.valid_object ())
1930 go.get_properties ().update_boundingbox ();
1935 base_properties::add_listener (const caseless_str& nm, const octave_value& v,
1938 property p = get_property (nm);
1940 if (! error_state && p.ok ())
1941 p.add_listener (v, mode);
1945 base_properties::delete_listener (const caseless_str& nm,
1946 const octave_value& v, listener_mode mode)
1948 property p = get_property (nm);
1950 if (! error_state && p.ok ())
1951 p.delete_listener (v, mode);
1954 // ---------------------------------------------------------------------
1956 class gnuplot_backend : public base_graphics_backend
1959 gnuplot_backend (void)
1960 : base_graphics_backend ("gnuplot") { }
1962 ~gnuplot_backend (void) { }
1964 bool is_valid (void) const { return true; }
1966 void object_destroyed (const graphics_object& go)
1968 if (go.isa ("figure"))
1970 const figure::properties& props =
1971 dynamic_cast<const figure::properties&> (go.get_properties ());
1973 send_quit (props.get___plot_stream__ ());
1977 void property_changed (const graphics_object& go, int id)
1979 if (go.isa ("figure"))
1981 graphics_object obj (go);
1983 figure::properties& props =
1984 dynamic_cast<figure::properties&> (obj.get_properties ());
1988 case base_properties::VISIBLE:
1989 if (! props.is_visible ())
1991 send_quit (props.get___plot_stream__ ());
1992 props.set___plot_stream__ (Matrix ());
1993 props.set___enhanced__ (false);
2000 void redraw_figure (const graphics_object& go) const
2002 octave_value_list args;
2003 args(0) = go.get_handle ().as_octave_value ();
2004 feval ("gnuplot_drawnow", args);
2007 void print_figure (const graphics_object& go, const std::string& term,
2008 const std::string& file, bool mono,
2009 const std::string& debug_file) const
2011 octave_value_list args;
2012 if (! debug_file.empty ())
2013 args(4) = debug_file;
2017 args(0) = go.get_handle ().as_octave_value ();
2018 feval ("gnuplot_drawnow", args);
2021 Matrix get_canvas_size (const graphics_handle&) const
2023 Matrix sz (1, 2, 0.0);
2027 double get_screen_resolution (void) const
2030 Matrix get_screen_size (void) const
2031 { return Matrix (1, 2, 0.0); }
2034 void send_quit (const octave_value& pstream) const
2036 if (! pstream.is_empty())
2038 octave_value_list args;
2039 Matrix fids = pstream.matrix_value ();
2043 args(1) = "\nquit;\n";
2044 args(0) = octave_value (fids (0));
2045 feval ("fputs", args);
2047 feval ("fflush", args);
2048 feval ("pclose", args);
2049 if (fids.numel () > 1)
2051 args(0) = octave_value (fids (1));
2052 feval ("pclose", args);
2060 graphics_backend::default_backend (void)
2062 if (available_backends.size () == 0)
2063 register_backend (new gnuplot_backend ());
2065 return available_backends["gnuplot"];
2068 std::map<std::string, graphics_backend> graphics_backend::available_backends;
2070 // ---------------------------------------------------------------------
2073 base_graphics_object::update_axis_limits (const std::string& axis_type)
2075 if (valid_object ())
2077 graphics_object parent_obj = gh_manager::get_object (get_parent ());
2080 parent_obj.update_axis_limits (axis_type);
2083 error ("base_graphics_object::update_axis_limits: invalid graphics object");
2087 base_graphics_object::remove_all_listeners (void)
2089 Octave_map m = get (true).map_value ();
2091 for (Octave_map::const_iterator pa = m.begin (); pa != m.end (); pa++)
2093 if (get_properties().has_property (pa->first))
2095 property p = get_properties ().get_property (pa->first);
2097 if (! error_state && p.ok ())
2098 p.delete_listener ();
2103 // ---------------------------------------------------------------------
2105 #include "graphics-props.cc"
2107 // ---------------------------------------------------------------------
2110 root_figure::properties::set_currentfigure (const octave_value& v)
2112 graphics_handle val (v);
2117 if (xisnan (val.value ()) || is_handle (val))
2119 currentfigure = val;
2121 gh_manager::push_figure (val);
2124 gripe_set_invalid ("currentfigure");
2128 root_figure::properties::set_callbackobject (const octave_value& v)
2130 graphics_handle val (v);
2135 if (xisnan (val.value ()))
2137 if (! cbo_stack.empty ())
2139 val = cbo_stack.front ();
2141 cbo_stack.pop_front ();
2144 callbackobject = val;
2146 else if (is_handle (val))
2148 if (get_callbackobject ().ok ())
2149 cbo_stack.push_front (get_callbackobject ());
2151 callbackobject = val;
2154 gripe_set_invalid ("callbackobject");
2158 root_figure::properties::update_units (void)
2160 caseless_str xunits = get_units ();
2162 Matrix ss = default_screensize ();
2164 double dpi = get_screenpixelsperinch ();
2166 if (xunits.compare ("inches"))
2173 else if (xunits.compare ("centimeters"))
2177 ss(2) *= 2.54 / dpi;
2178 ss(3) *= 2.54 / dpi;
2180 else if (xunits.compare ("normalized"))
2182 ss = Matrix (1, 4, 1.0);
2184 else if (xunits.compare ("points"))
2192 set_screensize (ss);
2196 root_figure::properties::remove_child (const graphics_handle& gh)
2198 gh_manager::pop_figure (gh);
2200 graphics_handle cf = gh_manager::current_figure ();
2202 xset (0, "currentfigure", cf.value ());
2204 base_properties::remove_child (gh);
2208 root_figure::factory_properties = root_figure::init_factory_properties ();
2210 // ---------------------------------------------------------------------
2213 figure::properties::set_currentaxes (const octave_value& v)
2215 graphics_handle val (v);
2220 if (xisnan (val.value ()) || is_handle (val))
2223 gripe_set_invalid ("currentaxes");
2227 figure::properties::remove_child (const graphics_handle& gh)
2229 base_properties::remove_child (gh);
2231 if (gh == currentaxes.handle_value ())
2233 graphics_handle new_currentaxes;
2235 for (octave_idx_type i = 0; i < children.numel (); i++)
2237 graphics_handle kid = children(i);
2239 graphics_object go = gh_manager::get_object (kid);
2241 if (go.isa ("axes"))
2243 new_currentaxes = kid;
2248 currentaxes = new_currentaxes;
2253 figure::properties::set_visible (const octave_value& val)
2255 std::string s = val.string_value ();
2260 xset (0, "currentfigure", __myhandle__.value ());
2267 figure::properties::get_boundingbox (bool) const
2269 Matrix screen_size = xget (0, "screensize").matrix_value ().extract_n (0, 2, 1, 2);
2272 pos = convert_position (get_position ().matrix_value (), get_units (),
2273 "pixels", screen_size);
2277 pos(1) = screen_size(1) - pos(1) - pos(3);
2283 figure::properties::set_boundingbox (const Matrix& bb)
2285 Matrix screen_size = xget (0, "screensize").matrix_value ().extract_n (0, 2, 1, 2);
2288 pos(1) = screen_size(1) - pos(1) - pos(3);
2291 pos = convert_position (pos, "pixels", get_units (), screen_size);
2297 figure::properties::set_position (const octave_value& v)
2301 Matrix old_bb, new_bb;
2303 old_bb = get_boundingbox ();
2305 new_bb = get_boundingbox ();
2307 if (old_bb != new_bb)
2309 if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
2311 execute_resizefcn ();
2312 update_boundingbox ();
2321 figure::properties::get_title (void) const
2323 if (is_numbertitle ())
2325 std::ostringstream os;
2326 std::string nm = get_name ();
2328 os << "Figure " << __myhandle__.value ();
2330 os << ": " << get_name ();
2339 figure::get_default (const caseless_str& name) const
2341 octave_value retval = default_properties.lookup (name);
2343 if (retval.is_undefined ())
2345 graphics_handle parent = get_parent ();
2346 graphics_object parent_obj = gh_manager::get_object (parent);
2348 retval = parent_obj.get_default (name);
2354 // ---------------------------------------------------------------------
2357 axes::properties::init (void)
2359 position.add_constraint (dim_vector (1, 4));
2360 position.add_constraint (dim_vector (0, 0));
2361 outerposition.add_constraint (dim_vector (1, 4));
2362 colororder.add_constraint (dim_vector (-1, 3));
2363 dataaspectratio.add_constraint (dim_vector (1, 3));
2364 plotboxaspectratio.add_constraint (dim_vector (1, 3));
2365 xlim.add_constraint (2);
2366 ylim.add_constraint (2);
2367 zlim.add_constraint (2);
2368 clim.add_constraint (2);
2369 alim.add_constraint (2);
2370 xtick.add_constraint (dim_vector (1, -1));
2371 ytick.add_constraint (dim_vector (1, -1));
2372 ztick.add_constraint (dim_vector (1, -1));
2373 Matrix vw (1, 2, 0);
2376 view.add_constraint (dim_vector (1, 2));
2377 cameraposition.add_constraint (dim_vector (1, 3));
2378 Matrix upv (1, 3, 0.0);
2380 cameraupvector = upv;
2381 cameraupvector.add_constraint (dim_vector (1, 3));
2382 currentpoint.add_constraint (dim_vector (2, 3));
2383 ticklength.add_constraint (dim_vector (1, 2));
2384 tightinset.add_constraint (dim_vector (1, 4));
2386 x_zlim.resize (1, 2);
2392 xset (xlabel.handle_value (), "handlevisibility", "off");
2393 xset (ylabel.handle_value (), "handlevisibility", "off");
2394 xset (zlabel.handle_value (), "handlevisibility", "off");
2395 xset (title.handle_value (), "handlevisibility", "off");
2397 xset (xlabel.handle_value (), "horizontalalignment", "center");
2398 xset (ylabel.handle_value (), "horizontalalignment", "center");
2399 xset (zlabel.handle_value (), "horizontalalignment", "right");
2400 xset (title.handle_value (), "horizontalalignment", "center");
2402 xset (xlabel.handle_value (), "verticalalignment", "cap");
2403 xset (ylabel.handle_value (), "verticalalignment", "bottom");
2404 xset (title.handle_value (), "verticalalignment", "bottom");
2406 xset (ylabel.handle_value (), "rotation", 90.0);
2408 adopt (xlabel.handle_value ());
2409 adopt (ylabel.handle_value ());
2410 adopt (zlabel.handle_value ());
2411 adopt (title.handle_value ());
2415 axes::properties::sync_positions (void)
2418 // FIXME -- this should take font metrics into consideration,
2419 // and also the fact that the colorbox leaves the outerposition
2420 // alone but alters the position. For now just don't adjust the
2421 // positions relative to each other.
2423 if (activepositionproperty.is ("outerposition"))
2425 Matrix outpos = outerposition.get ().matrix_value ();
2426 Matrix defpos = default_axes_position ();
2428 pos(0) = outpos(0) + defpos(0) * outpos(2);
2429 pos(1) = outpos(1) + defpos(1) * outpos(3);
2430 pos(2) = outpos(2) * defpos(2);
2431 pos(3) = outpos(3) * defpos(3);
2436 Matrix pos = position.get ().matrix_value ();
2437 pos(0) -= pos(2)*0.05;
2438 pos(1) -= pos(3)*0.05;
2441 outerposition = pos;
2445 update_transform ();
2449 axes::properties::set_text_child (handle_property& hp,
2450 const std::string& who,
2451 const octave_value& v)
2453 graphics_handle val = ::reparent (v, "set", who, __myhandle__, false);
2457 xset (val, "handlevisibility", "off");
2459 gh_manager::free (hp.handle_value ());
2461 base_properties::remove_child (hp.handle_value ());
2465 adopt (hp.handle_value ());
2470 axes::properties::set_xlabel (const octave_value& v)
2472 set_text_child (xlabel, "xlabel", v);
2476 axes::properties::set_ylabel (const octave_value& v)
2478 set_text_child (ylabel, "ylabel", v);
2482 axes::properties::set_zlabel (const octave_value& v)
2484 set_text_child (zlabel, "zlabel", v);
2488 axes::properties::set_title (const octave_value& v)
2490 set_text_child (title, "title", v);
2494 axes::properties::set_defaults (base_graphics_object& obj,
2495 const std::string& mode)
2502 colororder = default_colororder ();
2503 dataaspectratio = Matrix (1, 3, 1.0);
2504 dataaspectratiomode = "auto";
2507 Matrix tlim (1, 2, 0.0);
2513 Matrix cl (1, 2, 0);
2537 xticklabelmode = "auto";
2538 yticklabelmode = "auto";
2539 zticklabelmode = "auto";
2540 color = color_values (1, 1, 1);
2541 xcolor = color_values ("black");
2542 ycolor = color_values ("black");
2543 zcolor = color_values ("black");
2550 yaxislocation = "left";
2551 xaxislocation = "bottom";
2553 // Note: camera properties will be set through update_transform
2554 camerapositionmode = "auto";
2555 cameratargetmode = "auto";
2556 cameraupvectormode = "auto";
2557 cameraviewanglemode = "auto";
2558 plotboxaspectratio = Matrix (1, 3, 1.0);
2559 drawmode = "normal";
2560 gridlinestyle = ":";
2561 linestyleorder = "-";
2563 minorgridlinestyle = ":";
2564 // Note: plotboxaspectratio will be set through update_aspectratiors
2565 plotboxaspectratiomode = "auto";
2566 projection = "orthographic";
2568 tickdirmode = "auto";
2569 ticklength = default_axes_ticklength ();
2570 tightinset = Matrix (1, 4, 0.0);
2576 Matrix tview (1, 2, 0.0);
2581 nextplot = "replace";
2583 if (mode != "replace")
2585 fontangle = "normal";
2586 fontname = OCTAVE_DEFAULT_FONTNAME;
2588 fontunits = "points";
2589 fontweight = "normal";
2591 Matrix touterposition (1, 4, 0.0);
2592 touterposition(2) = 1;
2593 touterposition(3) = 1;
2594 outerposition = touterposition;
2596 position = default_axes_position ();
2598 activepositionproperty = "outerposition";
2603 children = Matrix ();
2605 xlabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
2606 ylabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
2607 zlabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
2608 title = gh_manager::make_graphics_handle ("text", __myhandle__, false);
2610 xset (xlabel.handle_value (), "handlevisibility", "off");
2611 xset (ylabel.handle_value (), "handlevisibility", "off");
2612 xset (zlabel.handle_value (), "handlevisibility", "off");
2613 xset (title.handle_value (), "handlevisibility", "off");
2615 xset (xlabel.handle_value (), "horizontalalignment", "center");
2616 xset (ylabel.handle_value (), "horizontalalignment", "center");
2617 xset (zlabel.handle_value (), "horizontalalignment", "right");
2618 xset (title.handle_value (), "horizontalalignment", "center");
2620 xset (xlabel.handle_value (), "verticalalignment", "cap");
2621 xset (ylabel.handle_value (), "verticalalignment", "bottom");
2622 xset (title.handle_value (), "verticalalignment", "bottom");
2624 xset (ylabel.handle_value (), "rotation", 90.0);
2626 adopt (xlabel.handle_value ());
2627 adopt (ylabel.handle_value ());
2628 adopt (zlabel.handle_value ());
2629 adopt (title.handle_value ());
2631 update_transform ();
2633 override_defaults (obj);
2637 axes::properties::delete_text_child (handle_property& hp)
2639 graphics_handle h = hp.handle_value ();
2643 graphics_object go = gh_manager::get_object (h);
2645 if (go.valid_object ())
2646 gh_manager::free (h);
2648 base_properties::remove_child (h);
2651 // FIXME -- is it necessary to check whether the axes object is
2652 // being deleted now? I think this function is only called when an
2653 // individual child object is delete and not when the parent axes
2654 // object is deleted.
2656 if (! is_beingdeleted ())
2658 hp = gh_manager::make_graphics_handle ("text", __myhandle__, false);
2660 xset (hp.handle_value (), "handlevisibility", "off");
2662 adopt (hp.handle_value ());
2667 axes::properties::remove_child (const graphics_handle& h)
2669 if (xlabel.handle_value ().ok () && h == xlabel.handle_value ())
2670 delete_text_child (xlabel);
2671 else if (ylabel.handle_value ().ok () && h == ylabel.handle_value ())
2672 delete_text_child (ylabel);
2673 else if (zlabel.handle_value ().ok () && h == zlabel.handle_value ())
2674 delete_text_child (zlabel);
2675 else if (title.handle_value ().ok () && h == title.handle_value ())
2676 delete_text_child (title);
2678 base_properties::remove_child (h);
2682 base_properties::get_children (void) const
2684 Matrix retval = children;
2686 graphics_object go = gh_manager::get_object (0);
2688 root_figure::properties& props =
2689 dynamic_cast<root_figure::properties&> (go.get_properties ());
2691 if (! props.is_showhiddenhandles ())
2693 octave_idx_type k = 0;
2695 for (octave_idx_type i = 0; i < children.numel (); i++)
2697 graphics_handle kid = children (i);
2699 if (gh_manager::is_handle_visible (kid))
2700 retval(k++) = children(i);
2703 retval.resize (k, 1);
2712 Matrix m (4, 4, 0.0);
2713 for (int i = 0; i < 4; i++)
2721 ColumnVector v (4, 0.0);
2727 xform_vector (double x, double y, double z)
2729 ColumnVector v (4, 1.0);
2730 v(0) = x; v(1) = y; v(2) = z;
2735 transform (const Matrix& m, double x, double y, double z)
2737 return (m * xform_vector (x, y, z));
2741 xform_scale (double x, double y, double z)
2743 Matrix m (4, 4, 0.0);
2744 m(0,0) = x; m(1,1) = y; m(2,2) = z; m(3,3) = 1;
2749 xform_translate (double x, double y, double z)
2751 Matrix m = xform_matrix ();
2752 m(0,3) = x; m(1,3) = y; m(2,3) = z; m(3,3) = 1;
2757 scale (Matrix& m, double x, double y, double z)
2759 m = m * xform_scale (x, y, z);
2763 translate (Matrix& m, double x, double y, double z)
2765 m = m * xform_translate (x, y, z);
2769 xform (ColumnVector& v, const Matrix& m)
2775 scale (ColumnVector& v, double x, double y, double z)
2783 translate (ColumnVector& v, double x, double y, double z)
2791 normalize (ColumnVector& v)
2793 double fact = 1.0/sqrt(v(0)*v(0)+v(1)*v(1)+v(2)*v(2));
2794 scale (v, fact, fact, fact);
2798 dot (const ColumnVector& v1, const ColumnVector& v2)
2800 return (v1(0)*v2(0)+v1(1)*v2(1)+v1(2)*v2(2));
2804 norm (const ColumnVector& v)
2806 return sqrt (dot (v, v));
2810 cross (const ColumnVector& v1, const ColumnVector& v2)
2812 ColumnVector r = xform_vector ();
2813 r(0) = v1(1)*v2(2)-v1(2)*v2(1);
2814 r(1) = v1(2)*v2(0)-v1(0)*v2(2);
2815 r(2) = v1(0)*v2(1)-v1(1)*v2(0);
2822 static double data[32] = {
2832 memcpy (m.fortran_vec (), data, sizeof(double)*32);
2837 cam2xform (const Array<double>& m)
2839 ColumnVector retval (4, 1.0);
2840 memcpy (retval.fortran_vec (), m.fortran_vec (), sizeof(double)*3);
2845 xform2cam (const ColumnVector& v)
2847 return v.extract_n (0, 3).transpose ();
2851 axes::properties::update_camera (void)
2853 double xd = (xdir_is ("normal") ? 1 : -1);
2854 double yd = (ydir_is ("normal") ? 1 : -1);
2855 double zd = (zdir_is ("normal") ? 1 : -1);
2857 Matrix xlimits = sx.scale (get_xlim ().matrix_value ());
2858 Matrix ylimits = sy.scale (get_ylim ().matrix_value ());
2859 Matrix zlimits = sz.scale (get_zlim ().matrix_value ());
2861 double xo = xlimits(xd > 0 ? 0 : 1);
2862 double yo = ylimits(yd > 0 ? 0 : 1);
2863 double zo = zlimits(zd > 0 ? 0 : 1);
2865 Matrix pb = get_plotboxaspectratio ().matrix_value ();
2867 bool autocam = (camerapositionmode_is ("auto")
2868 && cameratargetmode_is ("auto")
2869 && cameraupvectormode_is ("auto")
2870 && cameraviewanglemode_is ("auto"));
2871 bool dowarp = (autocam && dataaspectratiomode_is("auto")
2872 && plotboxaspectratiomode_is ("auto"));
2874 ColumnVector c_eye (xform_vector ());
2875 ColumnVector c_center (xform_vector ());
2876 ColumnVector c_upv (xform_vector ());
2878 if (cameratargetmode_is ("auto"))
2880 c_center(0) = (xlimits(0)+xlimits(1))/2;
2881 c_center(1) = (ylimits(0)+ylimits(1))/2;
2882 c_center(2) = (zlimits(0)+zlimits(1))/2;
2884 cameratarget = xform2cam (c_center);
2887 c_center = cam2xform (get_cameratarget ().matrix_value ());
2889 if (camerapositionmode_is ("auto"))
2891 Matrix tview = get_view ().matrix_value ();
2892 double az = tview(0), el = tview(1);
2893 double d = 5*sqrt(pb(0)*pb(0)+pb(1)*pb(1)+pb(2)*pb(2));
2895 if (el == 90 || el == -90)
2896 c_eye(2) = d*signum(el);
2901 c_eye(0) = d*cos(el)*sin(az);
2902 c_eye(1) = -d*cos(el)*cos(az);
2903 c_eye(2) = d*sin(el);
2905 c_eye(0) = c_eye(0)*(xlimits(1)-xlimits(0))/(xd*pb(0))+c_center(0);
2906 c_eye(1) = c_eye(1)*(ylimits(1)-ylimits(0))/(yd*pb(1))+c_center(1);
2907 c_eye(2) = c_eye(2)*(zlimits(1)-zlimits(0))/(zd*pb(2))+c_center(2);
2909 cameraposition = xform2cam (c_eye);
2912 c_eye = cam2xform (get_cameraposition ().matrix_value ());
2914 if (cameraupvectormode_is ("auto"))
2916 Matrix tview = get_view ().matrix_value ();
2917 double az = tview(0), el = tview(1);
2919 if (el == 90 || el == -90)
2921 c_upv(0) = -sin(az*M_PI/180.0)*(xlimits(1)-xlimits(0))/pb(0);
2922 c_upv(1) = cos(az*M_PI/180.0)*(ylimits(1)-ylimits(0))/pb(1);
2927 cameraupvector = xform2cam (c_upv);
2930 c_upv = cam2xform (get_cameraupvector ().matrix_value ());
2932 Matrix x_view = xform_matrix ();
2933 Matrix x_projection = xform_matrix ();
2934 Matrix x_viewport = xform_matrix ();
2935 Matrix x_normrender = xform_matrix ();
2936 Matrix x_pre = xform_matrix ();
2938 x_render = xform_matrix ();
2939 x_render_inv = xform_matrix ();
2941 scale (x_pre, pb(0), pb(1), pb(2));
2942 translate (x_pre, -0.5, -0.5, -0.5);
2943 scale (x_pre, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
2944 zd/(zlimits(1)-zlimits(0)));
2945 translate (x_pre, -xo, -yo, -zo);
2947 xform (c_eye, x_pre);
2948 xform (c_center, x_pre);
2949 scale (c_upv, pb(0)/(xlimits(1)-xlimits(0)), pb(1)/(ylimits(1)-ylimits(0)),
2950 pb(2)/(zlimits(1)-zlimits(0)));
2951 translate (c_center, -c_eye(0), -c_eye(1), -c_eye(2));
2953 ColumnVector F (c_center), f (F), UP (c_upv);
2957 if (std::abs (dot (f, UP)) > 1e-15)
2959 double fa = 1/sqrt(1-f(2)*f(2));
2960 scale (UP, fa, fa, fa);
2963 ColumnVector s = cross (f, UP);
2964 ColumnVector u = cross (s, f);
2966 scale (x_view, 1, 1, -1);
2967 Matrix l = xform_matrix ();
2968 l(0,0) = s(0); l(0,1) = s(1); l(0,2) = s(2);
2969 l(1,0) = u(0); l(1,1) = u(1); l(1,2) = u(2);
2970 l(2,0) = -f(0); l(2,1) = -f(1); l(2,2) = -f(2);
2971 x_view = x_view * l;
2972 translate (x_view, -c_eye(0), -c_eye(1), -c_eye(2));
2973 scale (x_view, pb(0), pb(1), pb(2));
2974 translate (x_view, -0.5, -0.5, -0.5);
2976 Matrix x_cube = x_view * unit_cube ();
2977 ColumnVector cmin = x_cube.row_min (), cmax = x_cube.row_max ();
2978 double xM = cmax(0)-cmin(0);
2979 double yM = cmax(1)-cmin(1);
2981 Matrix bb = get_boundingbox (true);
2985 if (cameraviewanglemode_is ("auto"))
2989 // FIXME -- was this really needed? When compared to Matlab, it
2990 // does not seem to be required. Need investigation with concrete
2991 // backend to see results visually.
2992 if (false && dowarp)
2993 af = 1.0 / (xM > yM ? xM : yM);
2996 if ((bb(2)/bb(3)) > (xM/yM))
3001 v_angle = 2 * (180.0 / M_PI) * atan (1 / (2 * af * norm (F)));
3003 cameraviewangle = v_angle;
3006 v_angle = get_cameraviewangle ();
3008 double pf = 1 / (2 * tan ((v_angle / 2) * M_PI / 180.0) * norm (F));
3009 scale (x_projection, pf, pf, 1);
3015 translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
3016 scale (x_viewport, bb(2)/xM, -bb(3)/yM, 1);
3023 if ((bb(2)/bb(3)) > (xM/yM))
3029 pix = (bb(2) < bb(3) ? bb(2) : bb(3));
3030 translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
3031 scale (x_viewport, pix, -pix, 1);
3034 x_normrender = x_viewport * x_projection * x_view;
3036 x_cube = x_normrender * unit_cube ();
3037 cmin = x_cube.row_min ();
3038 cmax = x_cube.row_max ();
3039 x_zlim.resize (1, 2);
3040 x_zlim(0) = cmin(2);
3041 x_zlim(1) = cmax(2);
3043 x_render = x_normrender;
3044 scale (x_render, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
3045 zd/(zlimits(1)-zlimits(0)));
3046 translate (x_render, -xo, -yo, -zo);
3048 x_viewtransform = x_view;
3049 x_projectiontransform = x_projection;
3050 x_viewporttransform = x_viewport;
3051 x_normrendertransform = x_normrender;
3052 x_rendertransform = x_render;
3054 x_render_inv = x_render.inverse ();
3056 // Note: these matrices are a slight modified version of the regular
3057 // matrices, more suited for OpenGL rendering (x_gl_mat1 => light
3060 scale (x_gl_mat1, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
3061 zd/(zlimits(1)-zlimits(0)));
3062 translate (x_gl_mat1, -xo, -yo, -zo);
3063 x_gl_mat2 = x_viewport * x_projection;
3067 axes::properties::update_aspectratios (void)
3069 Matrix xlimits = get_xlim ().matrix_value ();
3070 Matrix ylimits = get_ylim ().matrix_value ();
3071 Matrix zlimits = get_zlim ().matrix_value ();
3073 double dx = (xlimits(1)-xlimits(0));
3074 double dy = (ylimits(1)-ylimits(0));
3075 double dz = (zlimits(1)-zlimits(0));
3077 if (dataaspectratiomode_is ("auto"))
3079 double dmin = xmin (xmin (dx, dy), dz);
3080 Matrix da (1, 3, 0.0);
3086 dataaspectratio = da;
3089 if (plotboxaspectratiomode_is ("auto"))
3091 if (dataaspectratiomode_is ("auto"))
3092 plotboxaspectratio = Matrix (1, 3, 1.0);
3095 Matrix da = get_dataaspectratio ().matrix_value ();
3096 Matrix pba (1, 3, 0.0);
3104 // FIXME -- if plotboxaspectratiomode is "manual", limits
3105 // and/or dataaspectratio might be adapted.
3108 // The INTERNAL flag defines whether position or outerposition is used.
3111 axes::properties::get_boundingbox (bool internal) const
3113 graphics_object obj = gh_manager::get_object (get_parent ());
3114 Matrix parent_bb = obj.get_properties ().get_boundingbox (true);
3115 Matrix pos = (internal ?
3116 get_position ().matrix_value ()
3117 : get_outerposition ().matrix_value ());
3120 pos = convert_position (pos, get_units (), "pixels",
3121 parent_bb.extract_n (0, 2, 1, 2));
3124 pos(1) = parent_bb(3) - pos(1) - pos(3);
3130 graphics_xform::xform_vector (double x, double y, double z)
3132 return ::xform_vector (x, y, z);
3136 graphics_xform::xform_eye (void)
3138 return ::xform_matrix ();
3142 graphics_xform::transform (double x, double y, double z,
3143 bool use_scale) const
3152 return ::transform (xform, x, y, z);
3156 graphics_xform::untransform (double x, double y, double z,
3157 bool use_scale) const
3159 ColumnVector v = ::transform (xform_inv, x, y, z);
3163 v(0) = sx.unscale (v(0));
3164 v(1) = sy.unscale (v(1));
3165 v(2) = sz.unscale (v(2));
3172 axes::get_default (const caseless_str& name) const
3174 octave_value retval = default_properties.lookup (name);
3176 if (retval.is_undefined ())
3178 graphics_handle parent = get_parent ();
3179 graphics_object parent_obj = gh_manager::get_object (parent);
3181 retval = parent_obj.get_default (name);
3188 // FIXME -- maybe this should go into array_property class?
3191 check_limit_vals (double& min_val, double& max_val, double& min_pos,
3192 const array_property& data)
3194 double val = data.min_val ();
3195 if (! (xisinf (val) || xisnan (val)) && val < min_val)
3197 val = data.max_val ();
3198 if (! (xisinf (val) || xisnan (val)) && val > max_val)
3200 val = data.min_pos ();
3201 if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos)
3207 check_limit_vals (double& min_val, double& max_val, double& min_pos,
3208 const octave_value& data)
3210 if (data.is_matrix_type ())
3212 Matrix m = data.matrix_value ();
3214 if (! error_state && m.numel () == 3)
3219 if (! (xisinf (val) || xisnan (val)) && val < min_val)
3223 if (! (xisinf (val) || xisnan (val)) && val > max_val)
3227 if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos)
3233 // magform(x) Returns (a, b), where x = a * 10^b, a >= 1., and b is
3237 magform (double x, double& a, int& b)
3246 double l = std::log10 (std::abs (x));
3247 double r = std::fmod (l, 1.);
3248 a = std::pow (10.0, r);
3249 b = static_cast<int> (l-r);
3261 // A translation from Tom Holoryd's python code at
3262 // http://kurage.nimh.nih.gov/tomh/tics.py
3263 // FIXME -- add log ticks
3266 axes::properties::calc_tick_sep (double lo, double hi)
3270 // Reference: Lewart, C. R., "Algorithms SCALE1, SCALE2, and
3271 // SCALE3 for Determination of Scales on Computer Generated
3272 // Plots", Communications of the ACM, 10 (1973), 639-640.
3273 // Also cited as ACM Algorithm 463.
3278 magform ((hi-lo)/ticint, a, b);
3280 static const double sqrt_2 = sqrt (2.0);
3281 static const double sqrt_10 = sqrt (10.0);
3282 static const double sqrt_50 = sqrt (50.0);
3286 else if (a < sqrt_10)
3288 else if (a < sqrt_50)
3293 return x * std::pow (10., b);
3297 // Attempt to make "nice" limits from the actual max and min of the
3298 // data. For log plots, we will also use the smallest strictly positive
3302 axes::properties::get_axis_limits (double xmin, double xmax,
3303 double min_pos, bool logscale)
3307 double min_val = xmin;
3308 double max_val = xmax;
3310 if (! (xisinf (min_val) || xisinf (max_val)))
3314 if (xisinf (min_pos))
3316 // warning ("axis: logscale with no positive values to plot");
3322 warning ("axis: omitting nonpositive data in log plot");
3325 // FIXME -- maybe this test should also be relative?
3326 if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
3331 min_val = pow (10, floor (log10 (min_val)));
3332 max_val = pow (10, ceil (log10 (max_val)));
3336 if (min_val == 0 && max_val == 0)
3341 // FIXME -- maybe this test should also be relative?
3342 else if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
3344 min_val -= 0.1 * std::abs (min_val);
3345 max_val += 0.1 * std::abs (max_val);
3348 double tick_sep = calc_tick_sep (min_val , max_val);
3349 min_val = tick_sep * std::floor (min_val / tick_sep);
3350 max_val = tick_sep * ceil (max_val / tick_sep);
3354 retval.resize (1, 2);
3356 retval(0) = min_val;
3357 retval(1) = max_val;
3363 axes::properties::calc_ticks_and_lims (array_property& lims,
3364 array_property& ticks,
3365 bool limmode_is_auto, bool is_logscale)
3367 // FIXME -- add log ticks and lims
3369 if (lims.get ().is_empty ())
3372 double lo = (lims.get ().matrix_value ()) (0);
3373 double hi = (lims.get ().matrix_value ()) (1);
3374 // FIXME should this be checked for somewhere else? (i.e. set{x,y,z}lim)
3384 // FIXME we should check for negtives here
3385 hi = std::log10 (hi);
3386 lo = std::log10 (lo);
3389 double tick_sep = calc_tick_sep (lo , hi);
3391 int i1 = static_cast<int> (std::floor (lo / tick_sep));
3392 int i2 = static_cast<int> (std::ceil (hi / tick_sep));
3394 if (limmode_is_auto)
3396 // adjust limits to include min and max tics
3397 Matrix tmp_lims (1,2);
3398 tmp_lims(0) = tick_sep * i1;
3399 tmp_lims(1) = tick_sep * i2;
3403 tmp_lims(0) = std::pow (10.,tmp_lims(0));
3404 tmp_lims(1) = std::pow (10.,tmp_lims(1));
3410 // adjust min and max tics if they are out of limits
3411 i1 = static_cast<int> (std::ceil (lo / tick_sep));
3412 i2 = static_cast<int> (std::floor (hi / tick_sep));
3415 Matrix tmp_ticks (1, i2-i1+1);
3416 for (int i = 0; i <= i2-i1; i++)
3418 tmp_ticks (i) = tick_sep * (i+i1);
3420 tmp_ticks (i) = std::pow (10., tmp_ticks (i));
3427 get_children_limits (double& min_val, double& max_val, double& min_pos,
3428 const Matrix& kids, char limit_type)
3430 octave_idx_type n = kids.numel ();
3435 for (octave_idx_type i = 0; i < n; i++)
3437 graphics_object obj = gh_manager::get_object (kids(i));
3439 if (obj.is_xliminclude ())
3441 octave_value lim = obj.get_xlim ();
3443 check_limit_vals (min_val, max_val, min_pos, lim);
3449 for (octave_idx_type i = 0; i < n; i++)
3451 graphics_object obj = gh_manager::get_object (kids(i));
3453 if (obj.is_yliminclude ())
3455 octave_value lim = obj.get_ylim ();
3457 check_limit_vals (min_val, max_val, min_pos, lim);
3463 for (octave_idx_type i = 0; i < n; i++)
3465 graphics_object obj = gh_manager::get_object (kids(i));
3467 if (obj.is_zliminclude ())
3469 octave_value lim = obj.get_zlim ();
3471 check_limit_vals (min_val, max_val, min_pos, lim);
3477 for (octave_idx_type i = 0; i < n; i++)
3479 graphics_object obj = gh_manager::get_object (kids(i));
3481 if (obj.is_climinclude ())
3483 octave_value lim = obj.get_clim ();
3485 check_limit_vals (min_val, max_val, min_pos, lim);
3491 for (octave_idx_type i = 0; i < n; i++)
3493 graphics_object obj = gh_manager::get_object (kids(i));
3495 if (obj.is_aliminclude ())
3497 octave_value lim = obj.get_alim ();
3499 check_limit_vals (min_val, max_val, min_pos, lim);
3509 static bool updating_axis_limits = false;
3512 axes::update_axis_limits (const std::string& axis_type)
3514 if (updating_axis_limits)
3517 Matrix kids = xproperties.get_children ();
3519 double min_val = octave_Inf;
3520 double max_val = -octave_Inf;
3521 double min_pos = octave_Inf;
3523 char update_type = 0;
3527 if (axis_type == "xdata" || axis_type == "xscale"
3528 || axis_type == "xldata" || axis_type == "xudata"
3529 || axis_type == "xlimmode" || axis_type == "xliminclude"
3530 || axis_type == "xlim")
3532 if (xproperties.xlimmode_is ("auto"))
3534 get_children_limits (min_val, max_val, min_pos, kids, 'x');
3536 limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
3537 xproperties.xscale_is ("log"));
3542 else if (axis_type == "ydata" || axis_type == "yscale"
3543 || axis_type == "ldata" || axis_type == "udata"
3544 || axis_type == "ylimmode" || axis_type == "yliminclude"
3545 || axis_type == "ylim")
3547 if (xproperties.ylimmode_is ("auto"))
3549 get_children_limits (min_val, max_val, min_pos, kids, 'y');
3551 limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
3552 xproperties.yscale_is ("log"));
3557 else if (axis_type == "zdata" || axis_type == "zscale"
3558 || axis_type == "zlimmode" || axis_type == "zliminclude"
3559 || axis_type == "zlim")
3561 if (xproperties.zlimmode_is ("auto"))
3563 get_children_limits (min_val, max_val, min_pos, kids, 'z');
3565 limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
3566 xproperties.zscale_is ("log"));
3571 else if (axis_type == "cdata" || axis_type == "climmode"
3572 || axis_type == "cdatamapping" || axis_type == "climinclude"
3573 || axis_type == "clim")
3575 if (xproperties.climmode_is ("auto"))
3577 get_children_limits (min_val, max_val, min_pos, kids, 'c');
3579 if (min_val > max_val)
3581 min_val = min_pos = 0;
3584 else if (min_val == max_val)
3585 max_val = min_val + 1;
3587 limits.resize (1, 2);
3589 limits(0) = min_val;
3590 limits(1) = max_val;
3596 else if (axis_type == "alphadata" || axis_type == "alimmode"
3597 || axis_type == "alphadatamapping" || axis_type == "aliminclude"
3598 || axis_type == "alim")
3600 if (xproperties.alimmode_is ("auto"))
3602 get_children_limits (min_val, max_val, min_pos, kids, 'a');
3604 if (min_val > max_val)
3606 min_val = min_pos = 0;
3609 else if (min_val == max_val)
3610 max_val = min_val + 1;
3612 limits.resize (1, 2);
3614 limits(0) = min_val;
3615 limits(1) = max_val;
3622 unwind_protect_bool (updating_axis_limits);
3623 updating_axis_limits = true;
3625 switch (update_type)
3628 xproperties.set_xlim (limits);
3629 xproperties.set_xlimmode ("auto");
3630 xproperties.update_xlim ();
3634 xproperties.set_ylim (limits);
3635 xproperties.set_ylimmode ("auto");
3636 xproperties.update_ylim ();
3640 xproperties.set_zlim (limits);
3641 xproperties.set_zlimmode ("auto");
3642 xproperties.update_zlim ();
3646 xproperties.set_clim (limits);
3647 xproperties.set_climmode ("auto");
3651 xproperties.set_alim (limits);
3652 xproperties.set_alimmode ("auto");
3659 xproperties.update_transform ();
3661 unwind_protect::run ();
3665 axes::properties::zoom (const Matrix& xl, const Matrix& yl)
3667 zoom_stack.push_front (xlimmode.get ());
3668 zoom_stack.push_front (xlim.get ());
3669 zoom_stack.push_front (ylimmode.get ());
3670 zoom_stack.push_front (ylim.get ());
3673 xlimmode = "manual";
3675 ylimmode = "manual";
3677 update_transform ();
3678 update_xlim (false);
3679 update_ylim (false);
3683 axes::properties::unzoom (void)
3685 if (zoom_stack.size () >= 4)
3687 ylim = zoom_stack.front ();
3688 zoom_stack.pop_front ();
3689 ylimmode = zoom_stack.front ();
3690 zoom_stack.pop_front ();
3691 xlim = zoom_stack.front ();
3692 zoom_stack.pop_front ();
3693 xlimmode = zoom_stack.front ();
3694 zoom_stack.pop_front ();
3696 update_transform ();
3697 update_xlim (false);
3698 update_ylim (false);
3703 axes::properties::clear_zoom_stack (void)
3705 while (zoom_stack.size () > 4)
3706 zoom_stack.pop_front ();
3711 // ---------------------------------------------------------------------
3714 line::properties::compute_xlim (void) const
3718 m(0) = xmin (xdata.min_val (), xmin (xldata.min_val (), xudata.min_val ()));
3719 m(1) = xmax (xdata.max_val (), xmax (xldata.max_val (), xudata.max_val ()));
3720 m(2) = xmin (xdata.min_pos (), xmin (xldata.min_pos (), xudata.min_pos ()));
3726 line::properties::compute_ylim (void) const
3730 m(0) = xmin (ydata.min_val (), xmin (ldata.min_val (), udata.min_val ()));
3731 m(1) = xmax (ydata.max_val (), xmax (ldata.max_val (), udata.max_val ()));
3732 m(2) = xmin (ydata.min_pos (), xmin (ldata.min_pos (), udata.min_pos ()));
3737 // ---------------------------------------------------------------------
3739 // Note: "text" code is entirely auto-generated
3741 // ---------------------------------------------------------------------
3743 // Note: "image" code is entirely auto-generated
3745 // ---------------------------------------------------------------------
3748 patch::properties::get_color_data (void) const
3750 return convert_cdata (*this, get_facevertexcdata (),
3751 cdatamapping_is ("scaled"), 2);
3754 // ---------------------------------------------------------------------
3757 surface::properties::get_color_data (void) const
3759 return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
3763 cross_product (double x1, double y1, double z1,
3764 double x2, double y2, double z2,
3765 double& x, double& y, double& z)
3767 x += (y1 * z2 - z1 * y2);
3768 y += (z1 * x2 - x1 * z2);
3769 z += (x1 * y2 - y1 * x2);
3773 surface::properties::update_normals (void)
3775 if (normalmode_is ("auto"))
3777 Matrix x = get_xdata ().matrix_value ();
3778 Matrix y = get_ydata ().matrix_value ();
3779 Matrix z = get_zdata ().matrix_value ();
3782 int p = z.columns (), q = z.rows ();
3783 int i1 = 0, i2 = 0, i3 = 0;
3784 int j1 = 0, j2 = 0, j3 = 0;
3786 bool x_mat = (x.rows () == q);
3787 bool y_mat = (y.columns () == p);
3789 NDArray n (dim_vector (q, p, 3), 0.0);
3791 for (int i = 0; i < p; i++)
3800 for (int j = 0; j < q; j++)
3809 double& nx = n(j, i, 0);
3810 double& ny = n(j, i, 1);
3811 double& nz = n(j, i, 2);
3813 if ((j > 0) && (i > 0))
3814 // upper left quadrangle
3815 cross_product (x(j1,i-1)-x(j2,i), y(j-1,i1)-y(j,i2), z(j-1,i-1)-z(j,i),
3816 x(j2,i-1)-x(j1,i), y(j,i1)-y(j-1,i2), z(j,i-1)-z(j-1,i),
3819 if ((j > 0) && (i < (p -1)))
3820 // upper right quadrangle
3821 cross_product (x(j1,i+1)-x(j2,i), y(j-1,i3)-y(j,i2), z(j-1,i+1)-z(j,i),
3822 x(j1,i)-x(j2,i+1), y(j-1,i2)-y(j,i3), z(j-1,i)-z(j,i+1),
3825 if ((j < (q - 1)) && (i > 0))
3826 // lower left quadrangle
3827 cross_product (x(j2,i-1)-x(j3,i), y(j,i1)-y(j+1,i2), z(j,i-1)-z(j+1,i),
3828 x(j3,i-1)-x(j2,i), y(j+1,i1)-y(j,i2), z(j+1,i-1)-z(j,i),
3831 if ((j < (q - 1)) && (i < (p -1)))
3832 // lower right quadrangle
3833 cross_product (x(j3,i)-x(j2,i+1), y(j+1,i2)-y(j,i3), z(j+1,i)-z(j,i+1),
3834 x(j3,i+1)-x(j2,i), y(j+1,i3)-y(j,i2), z(j+1,i+1)-z(j,i),
3837 double d = - std::max(std::max(fabs(nx), fabs(ny)), fabs(nz));
3848 // ---------------------------------------------------------------------
3851 hggroup::update_axis_limits (const std::string& axis_type)
3853 Matrix kids = xproperties.get_children ();
3855 double min_val = octave_Inf;
3856 double max_val = -octave_Inf;
3857 double min_pos = octave_Inf;
3859 char update_type = 0;
3861 if (axis_type == "xlim" || axis_type == "xliminclude")
3863 get_children_limits (min_val, max_val, min_pos, kids, 'x');
3867 else if (axis_type == "ylim" || axis_type == "yliminclude")
3869 get_children_limits (min_val, max_val, min_pos, kids, 'y');
3873 else if (axis_type == "zlim" || axis_type == "zliminclude")
3875 get_children_limits (min_val, max_val, min_pos, kids, 'z');
3879 else if (axis_type == "clim" || axis_type == "climinclude")
3881 get_children_limits (min_val, max_val, min_pos, kids, 'c');
3886 else if (axis_type == "alim" || axis_type == "aliminclude")
3888 get_children_limits (min_val, max_val, min_pos, kids, 'a');
3893 Matrix limits (1, 3, 0.0);
3895 limits(0) = min_val;
3896 limits(1) = max_val;
3897 limits(2) = min_pos;
3899 switch (update_type)
3902 xproperties.set_xlim (limits);
3906 xproperties.set_ylim (limits);
3910 xproperties.set_zlim (limits);
3914 xproperties.set_clim (limits);
3918 xproperties.set_alim (limits);
3925 base_graphics_object::update_axis_limits (axis_type);
3928 // ---------------------------------------------------------------------
3931 base_graphics_object::get_default (const caseless_str& name) const
3933 graphics_handle parent = get_parent ();
3934 graphics_object parent_obj = gh_manager::get_object (parent);
3936 return parent_obj.get_default (type () + name);
3940 base_graphics_object::get_factory_default (const caseless_str& name) const
3942 graphics_object parent_obj = gh_manager::get_object (0);
3944 return parent_obj.get_factory_default (type () + name);
3947 // We use a random value for the handle to avoid issues with plots and
3948 // scalar values for the first argument.
3949 gh_manager::gh_manager (void)
3950 : handle_map (), handle_free_list (),
3951 next_handle (-1.0 - (rand () + 1.0) / (RAND_MAX + 2.0))
3953 handle_map[0] = graphics_object (new root_figure ());
3955 // Make sure the default backend is registered.
3956 graphics_backend::default_backend ();
3960 gh_manager::do_make_graphics_handle (const std::string& go_name,
3961 const graphics_handle& p, bool do_createfcn)
3963 graphics_handle h = get_handle (go_name);
3965 base_graphics_object *go = 0;
3967 go = make_graphics_object_from_type (go_name, h, p);
3971 graphics_object obj (go);
3973 handle_map[h] = obj;
3975 go->get_properties ().execute_createfcn ();
3978 graphics_backend backend = go->get_backend ();
3980 backend.object_created (obj);
3983 error ("gh_manager::do_make_graphics_handle: invalid object type `%s'",
3990 gh_manager::do_make_figure_handle (double val)
3992 graphics_handle h = val;
3994 base_graphics_object* go = new figure (h, 0);
3995 graphics_object obj (go);
3997 handle_map[h] = obj;
4000 graphics_backend backend = go->get_backend ();
4002 backend.object_created (obj);
4008 gh_manager::do_push_figure (const graphics_handle& h)
4012 figure_list.push_front (h);
4016 gh_manager::do_pop_figure (const graphics_handle& h)
4018 for (figure_list_iterator p = figure_list.begin ();
4019 p != figure_list.end ();
4024 figure_list.erase (p);
4031 callback_event : public base_graphics_event
4034 callback_event (const graphics_handle& h, const std::string& name,
4035 const octave_value& data = Matrix ())
4036 : base_graphics_event (), handle (h), callback_name (name),
4037 callback_data (data) { }
4041 gh_manager::execute_callback (handle, callback_name, callback_data);
4045 callback_event (void)
4046 : base_graphics_event () { }
4049 graphics_handle handle;
4050 std::string callback_name;
4051 octave_value callback_data;
4055 function_event : public base_graphics_event
4058 function_event (graphics_event::event_fcn fcn, void* data = 0)
4059 : base_graphics_event (), function (fcn),
4060 function_data (data) { }
4064 function (function_data);
4068 function_event (void)
4069 : base_graphics_event () { }
4072 graphics_event::event_fcn function;
4073 void* function_data;
4077 set_event : public base_graphics_event
4080 set_event (const graphics_handle& h, const std::string& name,
4081 const octave_value& value)
4082 : base_graphics_event (), handle (h), property_name (name),
4083 property_value (value) { }
4087 gh_manager::autolock guard;
4089 xset (handle, property_name, property_value);
4094 : base_graphics_event () { }
4097 graphics_handle handle;
4098 std::string property_name;
4099 octave_value property_value;
4103 graphics_event::create_callback_event (const graphics_handle& h,
4104 const std::string& name,
4105 const octave_value& data)
4109 e.rep = new callback_event (h, name, data);
4115 graphics_event::create_function_event (graphics_event::event_fcn fcn,
4120 e.rep = new function_event (fcn, data);
4126 graphics_event::create_set_event (const graphics_handle& h,
4127 const std::string& name,
4128 const octave_value& data)
4132 e.rep = new set_event (h, name, data);
4138 xset_gcbo (const graphics_handle& h)
4140 graphics_object go = gh_manager::get_object (0);
4141 root_figure::properties& props =
4142 dynamic_cast<root_figure::properties&> (go.get_properties ());
4144 props.set_callbackobject (h.as_octave_value ());
4148 gh_manager::do_restore_gcbo (void)
4150 gh_manager::autolock guard;
4152 callback_objects.pop_front ();
4154 xset_gcbo (callback_objects.empty ()
4155 ? graphics_handle ()
4156 : callback_objects.front ().get_handle ());
4160 gh_manager::do_execute_callback (const graphics_handle& h,
4161 const octave_value& cb_arg,
4162 const octave_value& data)
4164 octave_value_list args;
4165 octave_function *fcn = 0;
4167 args(0) = h.as_octave_value ();
4168 if (data.is_defined ())
4171 args(1) = Matrix ();
4173 unwind_protect::begin_frame ("execute_callback");
4174 unwind_protect::add (gh_manager::restore_gcbo);
4178 gh_manager::autolock guard;
4180 callback_objects.push_front (get_object (h));
4184 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
4186 // Copy CB because "function_value" method is non-const.
4188 octave_value cb = cb_arg;
4190 if (cb.is_function_handle ())
4191 fcn = cb.function_value ();
4192 else if (cb.is_string ())
4195 std::string s = cb.string_value ();
4197 eval_string (s, false, status);
4199 else if (cb.is_cell () && cb.length () > 0
4200 && (cb.rows () == 1 || cb.columns () == 1)
4201 && cb.cell_value ()(0).is_function_handle ())
4203 Cell c = cb.cell_value ();
4205 fcn = c(0).function_value ();
4208 for (int i = 1; i < c.length () ; i++)
4214 std::string nm = cb.class_name ();
4215 error ("trying to execute non-executable object (class = %s)",
4219 if (fcn && ! error_state)
4222 END_INTERRUPT_WITH_EXCEPTIONS;
4224 unwind_protect::run_frame ("execute_callback");
4228 gh_manager::do_post_event (const graphics_event& e)
4230 event_queue.push_back (e);
4232 command_editor::add_event_hook (gh_manager::process_events);
4236 gh_manager::do_post_callback (const graphics_handle& h, const std::string name,
4237 const octave_value& data)
4239 gh_manager::autolock guard;
4241 graphics_object go = get_object (h);
4243 if (go.valid_object ())
4245 if (callback_objects.empty ())
4246 do_post_event (graphics_event::create_callback_event (h, name, data));
4249 const graphics_object& current = callback_objects.front ();
4251 if (current.get_properties ().is_interruptible ())
4252 do_post_event (graphics_event::create_callback_event (h, name, data));
4255 caseless_str busy_action (go.get_properties ().get_busyaction ());
4257 if (busy_action.compare ("queue"))
4258 do_post_event (graphics_event::create_callback_event (h, name, data));
4261 caseless_str cname (name);
4263 if (cname.compare ("deletefcn")
4264 || cname.compare ("createfcn")
4265 || (go.isa ("figure")
4266 && (cname.compare ("closerequestfcn")
4267 || cname.compare ("resizefcn"))))
4268 do_post_event (graphics_event::create_callback_event (h, name, data));
4276 gh_manager::do_post_function (graphics_event::event_fcn fcn, void* fcn_data)
4278 gh_manager::autolock guard;
4280 do_post_event (graphics_event::create_function_event (fcn, fcn_data));
4284 gh_manager::do_post_set (const graphics_handle& h, const std::string name,
4285 const octave_value& value)
4287 gh_manager::autolock guard;
4289 do_post_event (graphics_event::create_set_event (h, name, value));
4293 gh_manager::do_process_events (bool force)
4299 e = graphics_event ();
4301 gh_manager::lock ();
4303 if (! event_queue.empty ())
4305 if (callback_objects.empty () || force)
4307 e = event_queue.front ();
4309 event_queue.pop_front ();
4313 const graphics_object& go = callback_objects.front ();
4315 if (go.get_properties ().is_interruptible ())
4317 e = event_queue.front ();
4319 event_queue.pop_front ();
4324 gh_manager::unlock ();
4331 gh_manager::lock ();
4333 if (event_queue.empty ())
4334 command_editor::remove_event_hook (gh_manager::process_events);
4336 gh_manager::unlock ();
4341 property_list::plist_map_type
4342 root_figure::init_factory_properties (void)
4344 property_list::plist_map_type plist_map;
4346 plist_map["figure"] = figure::properties::factory_defaults ();
4347 plist_map["axes"] = axes::properties::factory_defaults ();
4348 plist_map["line"] = line::properties::factory_defaults ();
4349 plist_map["text"] = text::properties::factory_defaults ();
4350 plist_map["image"] = image::properties::factory_defaults ();
4351 plist_map["patch"] = patch::properties::factory_defaults ();
4352 plist_map["surface"] = surface::properties::factory_defaults ();
4353 plist_map["hggroup"] = hggroup::properties::factory_defaults ();
4358 // ---------------------------------------------------------------------
4360 DEFUN (ishandle, args, ,
4362 @deftypefn {Built-in Function} {} ishandle (@var{h})\n\
4363 Return true if @var{h} is a graphics handle and false otherwise.\n\
4366 gh_manager::autolock guard;
4368 octave_value retval;
4370 if (args.length () == 1)
4371 retval = is_handle (args(0));
4380 @deftypefn {Built-in Function} {} set (@var{h}, @var{p}, @var{v}, @dots{})\n\
4381 Set the named property value or vector @var{p} to the value @var{v}\n\
4382 for the graphics handle @var{h}.\n\
4385 gh_manager::autolock guard;
4387 octave_value retval;
4389 int nargin = args.length ();
4393 ColumnVector hcv (args(0).vector_value ());
4397 bool request_drawnow = false;
4399 for (octave_idx_type n = 0; n < hcv.length (); n++)
4401 graphics_object obj = gh_manager::get_object (hcv(n));
4405 obj.set (args.splice (0, 1));
4407 request_drawnow = true;
4411 error ("set: invalid handle (= %g)", hcv(n));
4416 if (! error_state && request_drawnow)
4417 Vdrawnow_requested = true;
4420 error ("set: expecting graphics handle as first argument");
4430 @deftypefn {Built-in Function} {} get (@var{h}, @var{p})\n\
4431 Return the named property @var{p} from the graphics handle @var{h}.\n\
4432 If @var{p} is omitted, return the complete property list for @var{h}.\n\
4433 If @var{h} is a vector, return a cell array including the property\n\
4434 values or lists respectively.\n\
4437 gh_manager::autolock guard;
4439 octave_value retval;
4443 int nargin = args.length ();
4445 if (nargin == 1 || nargin == 2)
4447 ColumnVector hcv (args(0).vector_value ());
4451 octave_idx_type len = hcv.length ();
4453 vals.resize (dim_vector (len, 1));
4455 for (octave_idx_type n = 0; n < len; n++)
4457 graphics_object obj = gh_manager::get_object (hcv(n));
4462 vals(n) = obj.get ();
4465 caseless_str property = args(1).string_value ();
4468 vals(n) = obj.get (property);
4471 error ("get: expecting property name as second argument");
4478 error ("get: invalid handle (= %g)", hcv(n));
4484 error ("get: expecting graphics handle as first argument");
4491 octave_idx_type len = vals.numel ();
4502 // Return all properties from the graphics handle @var{h}.
4503 // If @var{h} is a vector, return a cell array including the
4504 // property values or lists respectively.
4506 DEFUN (__get__, args, ,
4508 @deftypefn {Built-in Function} {} __get__ (@var{h})\n\
4509 Undocumented internal function.\n\
4512 gh_manager::autolock guard;
4514 octave_value retval;
4518 int nargin = args.length ();
4522 ColumnVector hcv (args(0).vector_value ());
4526 octave_idx_type len = hcv.length ();
4528 vals.resize (dim_vector (len, 1));
4530 for (octave_idx_type n = 0; n < len; n++)
4532 graphics_object obj = gh_manager::get_object (hcv(n));
4535 vals(n) = obj.get (true);
4538 error ("get: invalid handle (= %g)", hcv(n));
4544 error ("get: expecting graphics handle as first argument");
4551 octave_idx_type len = vals.numel ();
4563 make_graphics_object (const std::string& go_name,
4564 const octave_value_list& args)
4566 octave_value retval;
4568 double val = octave_NaN;
4570 octave_value_list xargs = args.splice (0, 1);
4572 caseless_str p ("parent");
4574 for (int i = 0; i < xargs.length (); i++)
4575 if (xargs(i).is_string ()
4576 && p.compare (xargs(i).string_value ()))
4578 if (i < (xargs.length () - 1))
4580 val = xargs(i+1).double_value ();
4584 xargs = xargs.splice (i, 2);
4589 error ("__go_%s__: missing value for parent property",
4593 if (! error_state && xisnan (val))
4594 val = args(0).double_value ();
4598 graphics_handle parent = gh_manager::lookup (val);
4603 = gh_manager::make_graphics_handle (go_name, parent, false);
4612 retval = h.value ();
4615 Vdrawnow_requested = true;
4618 error ("__go%s__: unable to create graphics handle",
4622 error ("__go_%s__: invalid parent", go_name.c_str ());
4625 error ("__go_%s__: invalid parent", go_name.c_str ());
4630 DEFUN (__go_figure__, args, ,
4632 @deftypefn {Built-in Function} {} __go_figure__ (@var{fignum})\n\
4633 Undocumented internal function.\n\
4636 gh_manager::autolock guard;
4638 octave_value retval;
4640 if (args.length () > 0)
4642 double val = args(0).double_value ();
4646 if (is_figure (val))
4648 graphics_handle h = gh_manager::lookup (val);
4650 xset (h, args.splice (0, 1));
4652 retval = h.value ();
4656 graphics_handle h = octave_NaN;
4659 h = gh_manager::make_graphics_handle ("figure", 0, false);
4660 else if (val > 0 && D_NINT (val) == val)
4661 h = gh_manager::make_figure_handle (val);
4663 error ("__go_figure__: invalid figure number");
4665 if (! error_state && h.ok ())
4669 xset (h, args.splice (0, 1));
4672 retval = h.value ();
4675 error ("__go_figure__: failed to create figure handle");
4679 error ("__go_figure__: expecting figure number to be double value");
4687 #define GO_BODY(TYPE) \
4688 gh_manager::autolock guard; \
4690 octave_value retval; \
4692 if (args.length () > 0) \
4693 retval = make_graphics_object (#TYPE, args); \
4699 DEFUN (__go_axes__, args, ,
4701 @deftypefn {Built-in Function} {} __go_axes__ (@var{parent})\n\
4702 Undocumented internal function.\n\
4708 DEFUN (__go_line__, args, ,
4710 @deftypefn {Built-in Function} {} __go_line__ (@var{parent})\n\
4711 Undocumented internal function.\n\
4717 DEFUN (__go_text__, args, ,
4719 @deftypefn {Built-in Function} {} __go_text__ (@var{parent})\n\
4720 Undocumented internal function.\n\
4726 DEFUN (__go_image__, args, ,
4728 @deftypefn {Built-in Function} {} __go_image__ (@var{parent})\n\
4729 Undocumented internal function.\n\
4735 DEFUN (__go_surface__, args, ,
4737 @deftypefn {Built-in Function} {} __go_surface__ (@var{parent})\n\
4738 Undocumented internal function.\n\
4744 DEFUN (__go_patch__, args, ,
4746 @deftypefn {Built-in Function} {} __go_patch__ (@var{parent})\n\
4747 Undocumented internal function.\n\
4753 DEFUN (__go_hggroup__, args, ,
4755 @deftypefn {Built-in Function} {} __go_hggroup__ (@var{parent})\n\
4756 Undocumented internal function.\n\
4762 DEFUN (__go_delete__, args, ,
4764 @deftypefn {Built-in Function} {} __go_delete__ (@var{h})\n\
4765 Undocumented internal function.\n\
4768 gh_manager::autolock guard;
4770 octave_value_list retval;
4772 if (args.length () == 1)
4774 graphics_handle h = octave_NaN;
4776 const NDArray vals = args (0).array_value ();
4780 // Check is all the handles to delete are valid first
4781 // as callbacks might delete one of the handles we
4782 // later want to delete
4783 for (octave_idx_type i = 0; i < vals.numel (); i++)
4785 h = gh_manager::lookup (vals.elem (i));
4789 error ("delete: invalid graphics object (= %g)",
4797 for (octave_idx_type i = 0; i < vals.numel (); i++)
4799 h = gh_manager::lookup (vals.elem (i));
4803 graphics_object obj = gh_manager::get_object (h);
4805 // Don't do recursive deleting, due to callbacks
4806 if (! obj.get_properties ().is_beingdeleted ())
4808 graphics_handle parent_h = obj.get_parent ();
4810 graphics_object parent_obj =
4811 gh_manager::get_object (parent_h);
4813 // NOTE: free the handle before removing it from its
4814 // parent's children, such that the object's
4815 // state is correct when the deletefcn callback
4818 gh_manager::free (h);
4820 // A callback function might have already deleted
4822 if (parent_obj.valid_object ())
4823 parent_obj.remove_child (h);
4825 Vdrawnow_requested = true;
4832 error ("delete: invalid graphics object");
4840 DEFUN (__go_axes_init__, args, ,
4842 @deftypefn {Built-in Function} {} __go_axes_init__ (@var{h}, @var{mode})\n\
4843 Undocumented internal function.\n\
4846 gh_manager::autolock guard;
4848 octave_value retval;
4850 int nargin = args.length ();
4852 std::string mode = "";
4856 mode = args(1).string_value ();
4862 if (nargin == 1 || nargin == 2)
4864 graphics_handle h = octave_NaN;
4866 double val = args(0).double_value ();
4870 h = gh_manager::lookup (val);
4874 graphics_object obj = gh_manager::get_object (h);
4876 obj.set_defaults (mode);
4878 h = gh_manager::lookup (val);
4880 error ("__go_axes_init__: axis deleted during initialization (= %g)", val);
4883 error ("__go_axes_init__: invalid graphics object (= %g)", val);
4886 error ("__go_axes_init__: invalid graphics object");
4894 DEFUN (__go_handles__, , ,
4896 @deftypefn {Built-in Function} {} __go_handles__ ()\n\
4897 Undocumented internal function.\n\
4900 gh_manager::autolock guard;
4902 return octave_value (gh_manager::handle_list ());
4905 DEFUN (__go_figure_handles__, , ,
4907 @deftypefn {Built-in Function} {} __go_figure_handles__ ()\n\
4908 Undocumented internal function.\n\
4911 gh_manager::autolock guard;
4913 return octave_value (gh_manager::figure_handle_list ());
4916 DEFUN (__go_execute_callback__, args, ,
4918 @deftypefn {Built-in Function} {} __go_execute_callback__ (@var{h}, @var{name})\n\
4919 @deftypefnx {Built-in Function} {} __go_execute_callback__ (@var{h}, @var{name}, @var{param})\n\
4920 Undocumented internal function.\n\
4923 octave_value retval;
4925 int nargin = args.length ();
4927 if (nargin == 2 || nargin == 3)
4929 double val = args(0).double_value ();
4933 graphics_handle h = gh_manager::lookup (val);
4937 std::string name = args(1).string_value ();
4942 gh_manager::execute_callback (h, name);
4944 gh_manager::execute_callback (h, name, args(2));
4947 error ("__go_execute_callback__: invalid callback name");
4950 error ("__go_execute_callback__: invalid graphics object (= %g)",
4954 error ("__go_execute_callback__: invalid graphics object");
4962 DEFUN (available_backends, , ,
4964 @deftypefn {Built-in Function} {} available_backends ()\n\
4965 Return a cell array of registered graphics backends.\n\
4968 gh_manager::autolock guard;
4970 return octave_value (graphics_backend::available_backends_list ());
4974 clear_drawnow_request (void *)
4976 Vdrawnow_requested = false;
4979 DEFUN (drawnow, args, ,
4981 @deftypefn {Built-in Function} {} drawnow ()\n\
4982 @deftypefnx {Built-in Function} {} drawnow (\"expose\")\n\
4983 @deftypefnx {Built-in Function} {} drawnow (@var{term}, @var{file}, @var{mono}, @var{debug_file})\n\
4984 Update figure windows and their children. The event queue is flushed and\n\
4985 any callbacks generated are executed. With the optional argument\n\
4986 @code{\"expose\"}, only graphic objects are updated and no other events or\n\
4987 callbacks are processed.\n\
4988 The third calling form of @code{drawnow} is for debugging and is\n\
4992 static int drawnow_executing = 0;
4993 static bool __go_close_all_registered__ = false;
4995 octave_value retval;
4997 gh_manager::lock ();
4999 unwind_protect::begin_frame ("Fdrawnow");
5000 unwind_protect::add (clear_drawnow_request);
5002 unwind_protect_int (drawnow_executing);
5004 if (++drawnow_executing <= 1)
5006 if (! __go_close_all_registered__)
5008 octave_add_atexit_function ("__go_close_all__");
5010 __go_close_all_registered__ = true;
5013 if (args.length () == 0 || args.length () == 1)
5015 Matrix hlist = gh_manager::figure_handle_list ();
5017 for (int i = 0; ! error_state && i < hlist.length (); i++)
5019 graphics_handle h = gh_manager::lookup (hlist(i));
5021 if (h.ok () && h != 0)
5023 graphics_object go = gh_manager::get_object (h);
5024 figure::properties& fprops = dynamic_cast <figure::properties&> (go.get_properties ());
5026 if (fprops.is_modified ())
5028 if (fprops.is_visible ())
5030 gh_manager::unlock ();
5032 fprops.get_backend ().redraw_figure (go);
5034 gh_manager::lock ();
5037 fprops.set_modified (false);
5042 bool do_events = true;
5044 if (args.length () == 1)
5046 caseless_str val (args(0).string_value ());
5048 if (! error_state && val.compare ("expose"))
5052 error ("drawnow: invalid argument, expected `expose' as argument");
5059 gh_manager::unlock ();
5061 gh_manager::process_events ();
5063 gh_manager::lock ();
5066 else if (args.length () >= 2 && args.length () <= 4)
5068 std::string term, file, debug_file;
5071 term = args(0).string_value ();
5075 file = args(1).string_value ();
5079 size_t pos = file.find_last_of (file_ops::dir_sep_chars ());
5081 if (pos != std::string::npos)
5083 std::string dirname = file.substr (0, pos+1);
5085 file_stat fs (dirname);
5087 if (! (fs && fs.is_dir ()))
5089 error ("drawnow: nonexistent directory `%s'",
5096 mono = (args.length () >= 3 ? args(2).bool_value () : false);
5100 debug_file = (args.length () > 3 ? args(3).string_value ()
5105 graphics_handle h = gcf ();
5109 graphics_object go = gh_manager::get_object (h);
5111 gh_manager::unlock ();
5114 .print_figure (go, term, file, mono, debug_file);
5116 gh_manager::lock ();
5119 error ("drawnow: nothing to draw");
5122 error ("drawnow: invalid debug_file, expected a string value");
5125 error ("drawnow: invalid colormode, expected a boolean value");
5128 error ("drawnow: invalid file, expected a string value");
5131 error ("drawnow: invalid terminal, expected a string value");
5137 unwind_protect::run_frame ("Fdrawnow");
5139 gh_manager::unlock ();
5144 DEFUN (addlistener, args, ,
5146 @deftypefn {Built-in Function} {} addlistener (@var{h}, @var{prop}, @var{fcn})\n\
5147 Register @var{fcn} as listener for the property @var{prop} of the graphics\n\
5148 object @var{h}. Property listeners are executed (in order of registration)\n\
5149 when the property is set. The new value is already available when the\n\
5150 listeners are executed.\n\
5152 @var{prop} must be a string naming a valid property in @var{h}.\n\
5154 @var{fcn} can be a function handle, a string or a cell array whose first\n\
5155 element is a function handle. If @var{fcn} is a function handle, the\n\
5156 corresponding function should accept at least 2 arguments, that will be\n\
5157 set to the object handle and the empty matrix respectively. If @var{fcn}\n\
5158 is a string, it must be any valid octave expression. If @var{fcn} is a cell\n\
5159 array, the first element must be a function handle with the same signature\n\
5160 as described above. The next elements of the cell array are passed\n\
5161 as additional arguments to the function.\n\
5167 function my_listener (h, dummy, p1)\n\
5168 fprintf (\"my_listener called with p1=%s\\n\", p1);\n\
5171 addlistener (gcf, \"position\", @{@@my_listener, \"my string\"@})\n\
5177 gh_manager::autolock guard;
5179 octave_value retval;
5181 if (args.length () == 3)
5183 double h = args(0).double_value ();
5187 std::string pname = args(1).string_value ();
5191 graphics_handle gh = gh_manager::lookup (h);
5195 graphics_object go = gh_manager::get_object (gh);
5197 go.add_property_listener (pname, args(2), POSTSET);
5200 error ("addlistener: invalid graphics object (= %g)",
5204 error ("addlistener: invalid property name, expected a string value");
5207 error ("addlistener: invalid handle");
5215 DEFUN (dellistener, args, ,
5217 @deftypefn {Built-in Function} {} dellistener (@var{h}, @var{prop}, @var{fcn})\n\
5218 Remove the registration of @var{fcn} as a listener for the property\n\
5219 @var{prop} of the graphics object @var{h}. The function @var{fcn} must\n\
5220 be the same variable (not just the same value), as was passed to the\n\
5221 original call to @code{addlistener}.\n\
5223 If @var{fcn} is not defined then all listener functions of @var{prop}\n\
5230 function my_listener (h, dummy, p1)\n\
5231 fprintf (\"my_listener called with p1=%s\\n\", p1);\n\
5234 c = @{@@my_listener, \"my string\"@};\n\
5235 addlistener (gcf, \"position\", c);\n\
5236 dellistener (gcf, \"position\", c);\n\
5242 gh_manager::autolock guard;
5244 octave_value retval;
5246 if (args.length () == 3 || args.length () == 2)
5248 double h = args(0).double_value ();
5252 std::string pname = args(1).string_value ();
5256 graphics_handle gh = gh_manager::lookup (h);
5260 graphics_object go = gh_manager::get_object (gh);
5262 if (args.length () == 2)
5263 go.delete_property_listener (pname, octave_value (), POSTSET);
5265 go.delete_property_listener (pname, args(2), POSTSET);
5268 error ("dellistener: invalid graphics object (= %g)",
5272 error ("dellistener: invalid property name, expected a string value");
5275 error ("dellistener: invalid handle");
5283 DEFUN (addproperty, args, ,
5285 @deftypefn {Built-in Function} {} addproperty (@var{name}, @var{h}, @var{type}, [@var{arg}, @dots{}])\n\
5286 Create a new property named @var{name} in graphics object @var{h}.\n\
5287 @var{type} determines the type of the property to create. @var{args}\n\
5288 usually contains the default value of the property, but additional\n\
5289 arguments might be given, depending on the type of the property.\n\
5291 The supported property types are:\n\
5295 A string property. @var{arg} contains the default string value.\n\
5297 An un-typed property. This kind of property can hold any octave\n\
5298 value. @var{args} contains the default value.\n\
5300 A string property with a limited set of accepted values. The first\n\
5301 argument must be a string with all accepted values separated by\n\
5302 a vertical bar ('|'). The default value can be marked by enclosing\n\
5303 it with a '@{' '@}' pair. The default value may also be given as\n\
5304 an optional second string argument.\n\
5306 A boolean property. This property type is equivalent to a radio\n\
5307 property with \"on|off\" as accepted values. @var{arg} contains\n\
5308 the default property value.\n\
5310 A scalar double property. @var{arg} contains the default value.\n\
5312 A handle property. This kind of property holds the handle of a\n\
5313 graphics object. @var{arg} contains the default handle value.\n\
5314 When no default value is given, the property is initialized to\n\
5315 the empty matrix.\n\
5317 A data (matrix) property. @var{arg} contains the default data\n\
5318 value. When no default value is given, the data is initialized to\n\
5319 the empty matrix.\n\
5321 A color property. @var{arg} contains the default color value.\n\
5322 When no default color is given, the property is set to black.\n\
5323 An optional second string argument may be given to specify an\n\
5324 additional set of accepted string values (like a radio property).\n\
5327 @var{type} may also be the concatenation of a core object type and\n\
5328 a valid property name for that object type. The property created\n\
5329 then has the same characteristics as the referenced property (type,\n\
5330 possible values, hidden state@dots{}). This allows to clone an existing\n\
5331 property into the graphics object @var{h}.\n\
5337 addproperty (\"my_property\", gcf, \"string\", \"a string value\");\n\
5338 addproperty (\"my_radio\", gcf, \"radio\", \"val_1|val_2|@{val_3@}\");\n\
5339 addproperty (\"my_style\", gcf, \"linelinestyle\", \"--\");\n\
5345 gh_manager::autolock guard;
5347 octave_value retval;
5349 if (args.length () >= 3)
5351 std::string name = args(0).string_value ();
5355 double h = args(1).double_value ();
5359 graphics_handle gh = gh_manager::lookup (h);
5363 graphics_object go = gh_manager::get_object (gh);
5365 std::string type = args(2).string_value ();
5369 if (! go.get_properties ().has_property (name))
5371 property p = property::create (name, gh, type,
5372 args.splice (0, 3));
5375 go.get_properties ().insert_property (name, p);
5378 error ("addproperty: a `%s' property already exists in the graphics object",
5382 error ("addproperty: invalid property type, expected a string value");
5385 error ("addproperty: invalid graphics object (= %g)", h);
5388 error ("addproperty: invalid handle value");
5391 error ("addproperty: invalid property name, expected a string value");
5400 get_property_from_handle (double handle, const std::string& property,
5401 const std::string& func)
5403 gh_manager::autolock guard;
5405 graphics_object obj = gh_manager::get_object (handle);
5406 octave_value retval;
5410 caseless_str p = std::string (property);
5411 retval = obj.get (p);
5414 error ("%s: invalid handle (= %g)", func.c_str(), handle);
5420 set_property_in_handle (double handle, const std::string& property,
5421 const octave_value& arg, const std::string& func)
5423 gh_manager::autolock guard;
5425 graphics_object obj = gh_manager::get_object (handle);
5430 caseless_str p = std::string (property);
5436 error ("%s: invalid handle (= %g)", func.c_str(), handle);
5442 ;;; Local Variables: ***