00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <cctype>
00028 #include <cfloat>
00029 #include <cstdlib>
00030 #include <ctime>
00031
00032 #include <algorithm>
00033 #include <list>
00034 #include <map>
00035 #include <set>
00036 #include <string>
00037 #include <sstream>
00038
00039 #include "cmd-edit.h"
00040 #include "file-ops.h"
00041 #include "file-stat.h"
00042 #include "oct-locbuf.h"
00043 #include "singleton-cleanup.h"
00044
00045 #include "cutils.h"
00046 #include "defun.h"
00047 #include "display.h"
00048 #include "error.h"
00049 #include "graphics.h"
00050 #include "input.h"
00051 #include "ov.h"
00052 #include "oct-obj.h"
00053 #include "oct-map.h"
00054 #include "ov-fcn-handle.h"
00055 #include "pager.h"
00056 #include "parse.h"
00057 #include "toplev.h"
00058 #include "txt-eng-ft.h"
00059 #include "unwind-prot.h"
00060
00061
00062 static octave_value xget (const graphics_handle& h, const caseless_str& name);
00063
00064 static void
00065 gripe_set_invalid (const std::string& pname)
00066 {
00067 error ("set: invalid value for %s property", pname.c_str ());
00068 }
00069
00070
00071
00072
00073
00074 static caseless_str
00075 validate_property_name (const std::string& who, const std::string& what,
00076 const std::set<std::string>& pnames,
00077 const caseless_str& pname)
00078 {
00079 size_t len = pname.length ();
00080 std::set<std::string> matches;
00081
00082 for (std::set<std::string>::const_iterator p = pnames.begin ();
00083 p != pnames.end (); p++)
00084 {
00085 if (pname.compare (*p, len))
00086 {
00087 if (len == p->length ())
00088 {
00089
00090 return pname;
00091 }
00092
00093 matches.insert (*p);
00094 }
00095 }
00096
00097 size_t num_matches = matches.size ();
00098
00099 if (num_matches == 0)
00100 {
00101 error ("%s: unknown %s property %s",
00102 who.c_str (), what.c_str (), pname.c_str ());
00103 }
00104 else if (num_matches > 1)
00105 {
00106 string_vector sv (matches);
00107
00108 std::ostringstream os;
00109
00110 sv.list_in_columns (os);
00111
00112 std::string match_list = os.str ();
00113
00114 error ("%s: ambiguous %s property name %s; possible matches:\n\n%s",
00115 who.c_str (), what.c_str (), pname.c_str (), match_list.c_str ());
00116 }
00117 else if (num_matches == 1)
00118 {
00119
00120
00121 std::string possible_match = *(matches.begin ());
00122
00123 warning_with_id ("Octave:abbreviated-property-match",
00124 "%s: allowing %s to match %s property %s",
00125 who.c_str (), pname.c_str (), what.c_str (),
00126 possible_match.c_str ());
00127
00128 return possible_match;
00129 }
00130
00131 return caseless_str ();
00132 }
00133
00134 static Matrix
00135 jet_colormap (void)
00136 {
00137 Matrix cmap (64, 3, 0.0);
00138
00139 for (octave_idx_type i = 0; i < 64; i++)
00140 {
00141
00142
00143
00144
00145
00146
00147
00148 double x = i / 63.0;
00149
00150 if (x >= 3.0/8.0 && x < 5.0/8.0)
00151 cmap(i,0) = 4.0 * x - 3.0/2.0;
00152 else if (x >= 5.0/8.0 && x < 7.0/8.0)
00153 cmap(i,0) = 1.0;
00154 else if (x >= 7.0/8.0)
00155 cmap(i,0) = -4.0 * x + 9.0/2.0;
00156
00157 if (x >= 1.0/8.0 && x < 3.0/8.0)
00158 cmap(i,1) = 4.0 * x - 1.0/2.0;
00159 else if (x >= 3.0/8.0 && x < 5.0/8.0)
00160 cmap(i,1) = 1.0;
00161 else if (x >= 5.0/8.0 && x < 7.0/8.0)
00162 cmap(i,1) = -4.0 * x + 7.0/2.0;
00163
00164 if (x < 1.0/8.0)
00165 cmap(i,2) = 4.0 * x + 1.0/2.0;
00166 else if (x >= 1.0/8.0 && x < 3.0/8.0)
00167 cmap(i,2) = 1.0;
00168 else if (x >= 3.0/8.0 && x < 5.0/8.0)
00169 cmap(i,2) = -4.0 * x + 5.0/2.0;
00170 }
00171
00172 return cmap;
00173 }
00174
00175 static double
00176 default_screendepth (void)
00177 {
00178 return display_info::depth ();
00179 }
00180
00181 static Matrix
00182 default_screensize (void)
00183 {
00184 Matrix retval (1, 4, 1.0);
00185
00186 retval(2) = display_info::width ();
00187 retval(3) = display_info::height ();
00188
00189 return retval;
00190 }
00191
00192 static double
00193 default_screenpixelsperinch (void)
00194 {
00195 return (display_info::x_dpi () + display_info::y_dpi ()) / 2;
00196 }
00197
00198 static Matrix
00199 default_colororder (void)
00200 {
00201 Matrix retval (7, 3, 0.0);
00202
00203 retval(0,2) = 1.0;
00204
00205 retval(1,1) = 0.5;
00206
00207 retval(2,0) = 1.0;
00208
00209 retval(3,1) = 0.75;
00210 retval(3,2) = 0.75;
00211
00212 retval(4,0) = 0.75;
00213 retval(4,2) = 0.75;
00214
00215 retval(5,0) = 0.75;
00216 retval(5,1) = 0.75;
00217
00218 retval(6,0) = 0.25;
00219 retval(6,1) = 0.25;
00220 retval(6,2) = 0.25;
00221
00222 return retval;
00223 }
00224
00225 static Matrix
00226 default_lim (bool logscale = false)
00227 {
00228 Matrix m (1, 2, 0);
00229
00230 if (logscale)
00231 {
00232 m(0) = 0.1;
00233 m(1) = 1.0;
00234 }
00235 else
00236 m(1) = 1;
00237
00238 return m;
00239 }
00240
00241 static Matrix
00242 default_data (void)
00243 {
00244 Matrix retval (1, 2);
00245
00246 retval(0) = 0;
00247 retval(1) = 1;
00248
00249 return retval;
00250 }
00251
00252 static Matrix
00253 default_axes_position (void)
00254 {
00255 Matrix m (1, 4, 0.0);
00256 m(0) = 0.13;
00257 m(1) = 0.11;
00258 m(2) = 0.775;
00259 m(3) = 0.815;
00260 return m;
00261 }
00262
00263 static Matrix
00264 default_axes_outerposition (void)
00265 {
00266 Matrix m (1, 4, 0.0);
00267 m(2) = m(3) = 1.0;
00268 return m;
00269 }
00270
00271 static Matrix
00272 default_axes_tick (void)
00273 {
00274 Matrix m (1, 6, 0.0);
00275 m(0) = 0.0;
00276 m(1) = 0.2;
00277 m(2) = 0.4;
00278 m(3) = 0.6;
00279 m(4) = 0.8;
00280 m(5) = 1.0;
00281 return m;
00282 }
00283
00284 static Matrix
00285 default_axes_ticklength (void)
00286 {
00287 Matrix m (1, 2, 0.0);
00288 m(0) = 0.01;
00289 m(1) = 0.025;
00290 return m;
00291 }
00292
00293 static Matrix
00294 default_figure_position (void)
00295 {
00296 Matrix m (1, 4, 0.0);
00297 m(0) = 300;
00298 m(1) = 200;
00299 m(2) = 560;
00300 m(3) = 420;
00301 return m;
00302 }
00303
00304 static Matrix
00305 default_figure_papersize (void)
00306 {
00307 Matrix m (1, 2, 0.0);
00308 m(0) = 8.5;
00309 m(1) = 11.0;
00310 return m;
00311 }
00312
00313 static Matrix
00314 default_figure_paperposition (void)
00315 {
00316 Matrix m (1, 4, 0.0);
00317 m(0) = 0.25;
00318 m(1) = 2.50;
00319 m(2) = 8.00;
00320 m(3) = 6.00;
00321 return m;
00322 }
00323
00324 static Matrix
00325 default_control_position (void)
00326 {
00327 Matrix retval (1, 4, 0.0);
00328
00329 retval(0) = 0;
00330 retval(1) = 0;
00331 retval(2) = 80;
00332 retval(3) = 30;
00333
00334 return retval;
00335 }
00336
00337 static Matrix
00338 default_control_sliderstep (void)
00339 {
00340 Matrix retval (1, 2, 0.0);
00341
00342 retval(0) = 0.01;
00343 retval(1) = 0.1;
00344
00345 return retval;
00346 }
00347
00348 static Matrix
00349 default_panel_position (void)
00350 {
00351 Matrix retval (1, 4, 0.0);
00352
00353 retval(0) = 0;
00354 retval(1) = 0;
00355 retval(2) = 0.5;
00356 retval(3) = 0.5;
00357
00358 return retval;
00359 }
00360
00361 static double
00362 convert_font_size (double font_size, const caseless_str& from_units,
00363 const caseless_str& to_units, double parent_height = 0)
00364 {
00365
00366
00367 if (from_units.compare (to_units))
00368 return font_size;
00369
00370
00371
00372
00373 double points_size = 0;
00374 double res = 0;
00375
00376 if (from_units.compare ("points"))
00377 points_size = font_size;
00378 else
00379 {
00380 res = xget (0, "screenpixelsperinch").double_value ();
00381
00382 if (from_units.compare ("pixels"))
00383 points_size = font_size * 72.0 / res;
00384 else if (from_units.compare ("inches"))
00385 points_size = font_size * 72.0;
00386 else if (from_units.compare ("centimeters"))
00387 points_size = font_size * 72.0 / 2.54;
00388 else if (from_units.compare ("normalized"))
00389 points_size = font_size * parent_height * 72.0 / res;
00390 }
00391
00392 double new_font_size = 0;
00393
00394 if (to_units.compare ("points"))
00395 new_font_size = points_size;
00396 else
00397 {
00398 if (res <= 0)
00399 res = xget (0, "screenpixelsperinch").double_value ();
00400
00401 if (to_units.compare ("pixels"))
00402 new_font_size = points_size * res / 72.0;
00403 else if (to_units.compare ("inches"))
00404 new_font_size = points_size / 72.0;
00405 else if (to_units.compare ("centimeters"))
00406 new_font_size = points_size * 2.54 / 72.0;
00407 else if (to_units.compare ("normalized"))
00408 {
00409
00410
00411 if (parent_height > 0)
00412 new_font_size = points_size * res / (parent_height * 72.0);
00413 }
00414 }
00415
00416 return new_font_size;
00417 }
00418
00419 static Matrix
00420 convert_position (const Matrix& pos, const caseless_str& from_units,
00421 const caseless_str& to_units, const Matrix& parent_dim)
00422 {
00423 Matrix retval (1, pos.numel ());
00424 double res = 0;
00425 bool is_rectangle = (pos.numel () == 4);
00426 bool is_2d = (pos.numel () == 2);
00427
00428 if (from_units.compare ("pixels"))
00429 retval = pos;
00430 else if (from_units.compare ("normalized"))
00431 {
00432 retval(0) = pos(0) * parent_dim(0) + 1;
00433 retval(1) = pos(1) * parent_dim(1) + 1;
00434 if (is_rectangle)
00435 {
00436 retval(2) = pos(2) * parent_dim(0);
00437 retval(3) = pos(3) * parent_dim(1);
00438 }
00439 else if (! is_2d)
00440 retval(2) = 0;
00441 }
00442 else if (from_units.compare ("characters"))
00443 {
00444 if (res <= 0)
00445 res = xget (0, "screenpixelsperinch").double_value ();
00446
00447 double f = 0.0;
00448
00449
00450
00451 f = 12.0 * res / 74.951;
00452
00453 if (f > 0)
00454 {
00455 retval(0) = 0.5 * pos(0) * f;
00456 retval(1) = pos(1) * f;
00457 if (is_rectangle)
00458 {
00459 retval(2) = 0.5 * pos(2) * f;
00460 retval(3) = pos(3) * f;
00461 }
00462 else if (! is_2d)
00463 retval(2) = 0;
00464 }
00465 }
00466 else
00467 {
00468 if (res <= 0)
00469 res = xget (0, "screenpixelsperinch").double_value ();
00470
00471 double f = 0.0;
00472
00473 if (from_units.compare ("points"))
00474 f = res / 72.0;
00475 else if (from_units.compare ("inches"))
00476 f = res;
00477 else if (from_units.compare ("centimeters"))
00478 f = res / 2.54;
00479
00480 if (f > 0)
00481 {
00482 retval(0) = pos(0) * f + 1;
00483 retval(1) = pos(1) * f + 1;
00484 if (is_rectangle)
00485 {
00486 retval(2) = pos(2) * f;
00487 retval(3) = pos(3) * f;
00488 }
00489 else if (! is_2d)
00490 retval(2) = 0;
00491 }
00492 }
00493
00494 if (! to_units.compare ("pixels"))
00495 {
00496 if (to_units.compare ("normalized"))
00497 {
00498 retval(0) = (retval(0) - 1) / parent_dim(0);
00499 retval(1) = (retval(1) - 1) / parent_dim(1);
00500 if (is_rectangle)
00501 {
00502 retval(2) /= parent_dim(0);
00503 retval(3) /= parent_dim(1);
00504 }
00505 else if (! is_2d)
00506 retval(2) = 0;
00507 }
00508 else if (to_units.compare ("characters"))
00509 {
00510 if (res <= 0)
00511 res = xget (0, "screenpixelsperinch").double_value ();
00512
00513 double f = 0.0;
00514
00515 f = 12.0 * res / 74.951;
00516
00517 if (f > 0)
00518 {
00519 retval(0) = 2 * retval(0) / f;
00520 retval(1) = retval(1) / f;
00521 if (is_rectangle)
00522 {
00523 retval(2) = 2 * retval(2) / f;
00524 retval(3) = retval(3) / f;
00525 }
00526 else if (! is_2d)
00527 retval(2) = 0;
00528 }
00529 }
00530 else
00531 {
00532 if (res <= 0)
00533 res = xget (0, "screenpixelsperinch").double_value ();
00534
00535 double f = 0.0;
00536
00537 if (to_units.compare ("points"))
00538 f = res / 72.0;
00539 else if (to_units.compare ("inches"))
00540 f = res;
00541 else if (to_units.compare ("centimeters"))
00542 f = res / 2.54;
00543
00544 if (f > 0)
00545 {
00546 retval(0) = (retval(0) - 1) / f;
00547 retval(1) = (retval(1) - 1) / f;
00548 if (is_rectangle)
00549 {
00550 retval(2) /= f;
00551 retval(3) /= f;
00552 }
00553 else if (! is_2d)
00554 retval(2) = 0;
00555 }
00556 }
00557 }
00558 else if (! is_rectangle && ! is_2d)
00559 retval(2) = 0;
00560
00561 return retval;
00562 }
00563
00564 static Matrix
00565 convert_text_position (const Matrix& pos, const text::properties& props,
00566 const caseless_str& from_units,
00567 const caseless_str& to_units)
00568 {
00569 graphics_object go = gh_manager::get_object (props.get___myhandle__ ());
00570 graphics_object ax = go.get_ancestor ("axes");
00571
00572 Matrix retval;
00573
00574 if (ax.valid_object ())
00575 {
00576 const axes::properties& ax_props =
00577 dynamic_cast<const axes::properties&> (ax.get_properties ());
00578 graphics_xform ax_xform = ax_props.get_transform ();
00579 bool is_rectangle = (pos.numel () == 4);
00580 Matrix ax_bbox = ax_props.get_boundingbox (true),
00581 ax_size = ax_bbox.extract_n (0, 2, 1, 2);
00582
00583 if (from_units.compare ("data"))
00584 {
00585 if (is_rectangle)
00586 {
00587 ColumnVector v1 = ax_xform.transform (pos(0), pos(1), 0),
00588 v2 = ax_xform.transform (pos(0) + pos(2),
00589 pos(1) + pos(3), 0);
00590
00591 retval.resize (1, 4);
00592
00593 retval(0) = v1(0) - ax_bbox(0) + 1;
00594 retval(1) = ax_bbox(1) + ax_bbox(3) - v1(1) + 1;
00595 retval(2) = v2(0) - v1(0);
00596 retval(3) = v1(1) - v2(1);
00597 }
00598 else
00599 {
00600 ColumnVector v = ax_xform.transform (pos(0), pos(1), pos(2));
00601
00602 retval.resize (1, 3);
00603
00604 retval(0) = v(0) - ax_bbox(0) + 1;
00605 retval(1) = ax_bbox(1) + ax_bbox(3) - v(1) + 1;
00606 retval(2) = 0;
00607 }
00608 }
00609 else
00610 retval = convert_position (pos, from_units, "pixels", ax_size);
00611
00612 if (! to_units.compare ("pixels"))
00613 {
00614 if (to_units.compare ("data"))
00615 {
00616 if (is_rectangle)
00617 {
00618 ColumnVector v1 = ax_xform.untransform (retval(0) + ax_bbox(0) - 1,
00619 ax_bbox(1) + ax_bbox(3) - retval(1) + 1),
00620 v2 = ax_xform.untransform (retval(0) + retval(2) + ax_bbox(0) - 1,
00621 ax_bbox(1) + ax_bbox(3) - (retval(1) + retval(3)) + 1);
00622
00623 retval.resize (1, 4);
00624
00625 retval(0) = v1(0);
00626 retval(1) = v1(1);
00627 retval(2) = v2(0) - v1(0);
00628 retval(3) = v2(1) - v1(1);
00629 }
00630 else
00631 {
00632 ColumnVector v = ax_xform.untransform (retval(0) + ax_bbox(0) - 1,
00633 ax_bbox(1) + ax_bbox(3) - retval(1) + 1);
00634
00635 retval.resize (1, 3);
00636
00637 retval(0) = v(0);
00638 retval(1) = v(1);
00639 retval(2) = v(2);
00640 }
00641 }
00642 else
00643 retval = convert_position (retval, "pixels", to_units, ax_size);
00644 }
00645 }
00646
00647 return retval;
00648 }
00649
00650
00651 static Matrix
00652 screen_size_pixels (void)
00653 {
00654 graphics_object obj = gh_manager::get_object (0);
00655 Matrix sz = obj.get ("screensize").matrix_value ();
00656 return convert_position (sz, obj.get ("units").string_value (), "pixels", sz.extract_n (0, 2, 1, 2)).extract_n (0, 2, 1, 2);
00657 }
00658
00659 static void
00660 convert_cdata_2 (bool is_scaled, double clim_0, double clim_1,
00661 const double *cmapv, double x, octave_idx_type lda,
00662 octave_idx_type nc, octave_idx_type i, double *av)
00663 {
00664 if (is_scaled)
00665 x = xround ((nc - 1) * (x - clim_0) / (clim_1 - clim_0));
00666 else
00667 x = xround (x - 1);
00668
00669 if (xisnan (x))
00670 {
00671 av[i] = x;
00672 av[i+lda] = x;
00673 av[i+2*lda] = x;
00674 }
00675 else
00676 {
00677 if (x < 0)
00678 x = 0;
00679 else if (x >= nc)
00680 x = (nc - 1);
00681
00682 octave_idx_type idx = static_cast<octave_idx_type> (x);
00683
00684 av[i] = cmapv[idx];
00685 av[i+lda] = cmapv[idx+nc];
00686 av[i+2*lda] = cmapv[idx+2*nc];
00687 }
00688 }
00689
00690 template <class T>
00691 void
00692 convert_cdata_1 (bool is_scaled, double clim_0, double clim_1,
00693 const double *cmapv, const T *cv, octave_idx_type lda,
00694 octave_idx_type nc, double *av)
00695 {
00696 for (octave_idx_type i = 0; i < lda; i++)
00697 convert_cdata_2 (is_scaled, clim_0, clim_1, cmapv, cv[i], lda, nc, i, av);
00698 }
00699
00700 static octave_value
00701 convert_cdata (const base_properties& props, const octave_value& cdata,
00702 bool is_scaled, int cdim)
00703 {
00704 dim_vector dv (cdata.dims ());
00705
00706 if (dv.length () == cdim && dv(cdim-1) == 3)
00707 return cdata;
00708
00709 Matrix cmap (1, 3, 0.0);
00710 Matrix clim (1, 2, 0.0);
00711
00712 graphics_object go = gh_manager::get_object (props.get___myhandle__ ());
00713 graphics_object fig = go.get_ancestor ("figure");
00714
00715 if (fig.valid_object ())
00716 {
00717 Matrix _cmap = fig.get (caseless_str ("colormap")).matrix_value ();
00718
00719 if (! error_state)
00720 cmap = _cmap;
00721 }
00722
00723 if (is_scaled)
00724 {
00725 graphics_object ax = go.get_ancestor ("axes");
00726
00727 if (ax.valid_object ())
00728 {
00729 Matrix _clim = ax.get (caseless_str ("clim")).matrix_value ();
00730
00731 if (! error_state)
00732 clim = _clim;
00733 }
00734 }
00735
00736 dv.resize (cdim);
00737 dv(cdim-1) = 3;
00738
00739 NDArray a (dv);
00740
00741 octave_idx_type lda = a.numel () / static_cast<octave_idx_type> (3);
00742 octave_idx_type nc = cmap.rows ();
00743
00744 double *av = a.fortran_vec ();
00745 const double *cmapv = cmap.data ();
00746
00747 double clim_0 = clim(0);
00748 double clim_1 = clim(1);
00749
00750 #define CONVERT_CDATA_1(ARRAY_T, VAL_FN) \
00751 do \
00752 { \
00753 ARRAY_T tmp = cdata. VAL_FN ## array_value (); \
00754 \
00755 convert_cdata_1 (is_scaled, clim_0, clim_1, cmapv, \
00756 tmp.data (), lda, nc, av); \
00757 } \
00758 while (0)
00759
00760 if (cdata.is_uint8_type ())
00761 CONVERT_CDATA_1 (uint8NDArray, uint8_);
00762 else if (cdata.is_single_type ())
00763 CONVERT_CDATA_1 (FloatNDArray, float_);
00764 else if (cdata.is_double_type ())
00765 CONVERT_CDATA_1 (NDArray, );
00766 else
00767 error ("unsupported type for cdata (= %s)", cdata.type_name ().c_str ());
00768
00769 #undef CONVERT_CDATA_1
00770
00771 return octave_value (a);
00772 }
00773
00774 template<class T>
00775 static void
00776 get_array_limits (const Array<T>& m, double& emin, double& emax,
00777 double& eminp, double& emaxp)
00778 {
00779 const T *data = m.data ();
00780 octave_idx_type n = m.numel ();
00781
00782 for (octave_idx_type i = 0; i < n; i++)
00783 {
00784 double e = double (data[i]);
00785
00786
00787 if (! xisinf (e))
00788 {
00789 if (e < emin)
00790 emin = e;
00791
00792 if (e > emax)
00793 emax = e;
00794
00795 if (e > 0 && e < eminp)
00796 eminp = e;
00797
00798 if (e < 0 && e > emaxp)
00799 emaxp = e;
00800 }
00801 }
00802 }
00803
00804 static bool
00805 lookup_object_name (const caseless_str& name, caseless_str& go_name,
00806 caseless_str& rest)
00807 {
00808 int len = name.length ();
00809 int offset = 0;
00810 bool result = false;
00811
00812 if (len >= 4)
00813 {
00814 caseless_str pfx = name.substr (0, 4);
00815
00816 if (pfx.compare ("axes") || pfx.compare ("line")
00817 || pfx.compare ("text"))
00818 offset = 4;
00819 else if (len >= 5)
00820 {
00821 pfx = name.substr (0, 5);
00822
00823 if (pfx.compare ("image") || pfx.compare ("patch"))
00824 offset = 5;
00825 else if (len >= 6)
00826 {
00827 pfx = name.substr (0, 6);
00828
00829 if (pfx.compare ("figure") || pfx.compare ("uimenu"))
00830 offset = 6;
00831 else if (len >= 7)
00832 {
00833 pfx = name.substr (0, 7);
00834
00835 if (pfx.compare ("surface") || pfx.compare ("hggroup")
00836 || pfx.compare ("uipanel"))
00837 offset = 7;
00838 else if (len >= 9)
00839 {
00840 pfx = name.substr (0, 9);
00841
00842 if (pfx.compare ("uicontrol")
00843 || pfx.compare ("uitoolbar"))
00844 offset = 9;
00845 else if (len >= 10)
00846 {
00847 pfx = name.substr (0, 10);
00848
00849 if (pfx.compare ("uipushtool"))
00850 offset = 10;
00851 else if (len >= 12)
00852 {
00853 pfx = name.substr (0, 12);
00854
00855 if (pfx.compare ("uitoggletool"))
00856 offset = 12;
00857 else if (len >= 13)
00858 {
00859 pfx = name.substr (0, 13);
00860
00861 if (pfx.compare ("uicontextmenu"))
00862 offset = 13;
00863 }
00864 }
00865 }
00866 }
00867 }
00868 }
00869 }
00870
00871 if (offset > 0)
00872 {
00873 go_name = pfx;
00874 rest = name.substr (offset);
00875 result = true;
00876 }
00877 }
00878
00879 return result;
00880 }
00881
00882 static base_graphics_object*
00883 make_graphics_object_from_type (const caseless_str& type,
00884 const graphics_handle& h = graphics_handle (),
00885 const graphics_handle& p = graphics_handle ())
00886 {
00887 base_graphics_object *go = 0;
00888
00889 if (type.compare ("figure"))
00890 go = new figure (h, p);
00891 else if (type.compare ("axes"))
00892 go = new axes (h, p);
00893 else if (type.compare ("line"))
00894 go = new line (h, p);
00895 else if (type.compare ("text"))
00896 go = new text (h, p);
00897 else if (type.compare ("image"))
00898 go = new image (h, p);
00899 else if (type.compare ("patch"))
00900 go = new patch (h, p);
00901 else if (type.compare ("surface"))
00902 go = new surface (h, p);
00903 else if (type.compare ("hggroup"))
00904 go = new hggroup (h, p);
00905 else if (type.compare ("uimenu"))
00906 go = new uimenu (h, p);
00907 else if (type.compare ("uicontrol"))
00908 go = new uicontrol (h, p);
00909 else if (type.compare ("uipanel"))
00910 go = new uipanel (h, p);
00911 else if (type.compare ("uicontextmenu"))
00912 go = new uicontextmenu (h, p);
00913 else if (type.compare ("uitoolbar"))
00914 go = new uitoolbar (h, p);
00915 else if (type.compare ("uipushtool"))
00916 go = new uipushtool (h, p);
00917 else if (type.compare ("uitoggletool"))
00918 go = new uitoggletool (h, p);
00919 return go;
00920 }
00921
00922
00923
00924 bool
00925 base_property::set (const octave_value& v, bool do_run, bool do_notify_toolkit)
00926 {
00927 if (do_set (v))
00928 {
00929
00930
00931 if (id >= 0 && do_notify_toolkit)
00932 {
00933 graphics_object go = gh_manager::get_object (parent);
00934 if (go)
00935 go.update (id);
00936 }
00937
00938
00939 if (do_run && ! error_state)
00940 run_listeners (POSTSET);
00941
00942 return true;
00943 }
00944
00945 return false;
00946 }
00947
00948
00949 void
00950 base_property::run_listeners (listener_mode mode)
00951 {
00952 const octave_value_list& l = listeners[mode];
00953
00954 for (int i = 0; i < l.length (); i++)
00955 {
00956 gh_manager::execute_listener (parent, l(i));
00957
00958 if (error_state)
00959 break;
00960 }
00961 }
00962
00963 radio_values::radio_values (const std::string& opt_string)
00964 : default_val (), possible_vals ()
00965 {
00966 size_t beg = 0;
00967 size_t len = opt_string.length ();
00968 bool done = len == 0;
00969
00970 while (! done)
00971 {
00972 size_t end = opt_string.find ('|', beg);
00973
00974 if (end == std::string::npos)
00975 {
00976 end = len;
00977 done = true;
00978 }
00979
00980 std::string t = opt_string.substr (beg, end-beg);
00981
00982
00983 if (t[0] == '{')
00984 {
00985 t = t.substr (1, t.length () - 2);
00986 default_val = t;
00987 }
00988 else if (beg == 0)
00989 default_val = t;
00990
00991 possible_vals.insert (t);
00992
00993 beg = end + 1;
00994 }
00995 }
00996
00997 std::string
00998 radio_values::values_as_string (void) const
00999 {
01000 std::string retval;
01001 for (std::set<caseless_str>::const_iterator it = possible_vals.begin ();
01002 it != possible_vals.end (); it++)
01003 {
01004 if (retval == "")
01005 {
01006 if (*it == default_value ())
01007 retval = "{" + *it + "}";
01008 else
01009 retval = *it;
01010 }
01011 else
01012 {
01013 if (*it == default_value ())
01014 retval += " | {" + *it + "}";
01015 else
01016 retval += " | " + *it;
01017 }
01018 }
01019 if (retval != "")
01020 retval = "[ " + retval + " ]";
01021 return retval;
01022 }
01023
01024 Cell
01025 radio_values::values_as_cell (void) const
01026 {
01027 octave_idx_type i = 0;
01028 Cell retval (nelem (), 1);
01029 for (std::set<caseless_str>::const_iterator it = possible_vals.begin ();
01030 it != possible_vals.end (); it++)
01031 retval(i++) = std::string (*it);
01032 return retval;
01033 }
01034
01035 bool
01036 color_values::str2rgb (std::string str)
01037 {
01038 double tmp_rgb[3] = {0, 0, 0};
01039 bool retval = true;
01040 unsigned int len = str.length();
01041
01042 std::transform (str.begin (), str.end (), str.begin (), tolower);
01043
01044 if (str.compare(0, len, "blue", 0, len) == 0)
01045 tmp_rgb[2] = 1;
01046 else if (str.compare(0, len, "black", 0, len) == 0
01047 || str.compare(0, len, "k", 0, len) == 0)
01048 tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 0;
01049 else if (str.compare(0, len, "red", 0, len) == 0)
01050 tmp_rgb[0] = 1;
01051 else if (str.compare(0, len, "green", 0, len) == 0)
01052 tmp_rgb[1] = 1;
01053 else if (str.compare(0, len, "yellow", 0, len) == 0)
01054 tmp_rgb[0] = tmp_rgb[1] = 1;
01055 else if (str.compare(0, len, "magenta", 0, len) == 0)
01056 tmp_rgb[0] = tmp_rgb[2] = 1;
01057 else if (str.compare(0, len, "cyan", 0, len) == 0)
01058 tmp_rgb[1] = tmp_rgb[2] = 1;
01059 else if (str.compare(0, len, "white", 0, len) == 0
01060 || str.compare(0, len, "w", 0, len) == 0)
01061 tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 1;
01062 else
01063 retval = false;
01064
01065 if (retval)
01066 {
01067 for (int i = 0; i < 3; i++)
01068 xrgb(i) = tmp_rgb[i];
01069 }
01070
01071 return retval;
01072 }
01073
01074 bool
01075 color_property::do_set (const octave_value& val)
01076 {
01077 if (val.is_string ())
01078 {
01079 std::string s = val.string_value ();
01080
01081 if (! s.empty ())
01082 {
01083 std::string match;
01084
01085 if (radio_val.contains (s, match))
01086 {
01087 if (current_type != radio_t || match != current_val)
01088 {
01089 if (s.length () != match.length ())
01090 warning_with_id ("Octave:abbreviated-property-match",
01091 "%s: allowing %s to match %s value %s",
01092 "set", s.c_str (), get_name ().c_str (),
01093 match.c_str ());
01094 current_val = match;
01095 current_type = radio_t;
01096 return true;
01097 }
01098 }
01099 else
01100 {
01101 color_values col (s);
01102 if (! error_state)
01103 {
01104 if (current_type != color_t || col != color_val)
01105 {
01106 color_val = col;
01107 current_type = color_t;
01108 return true;
01109 }
01110 }
01111 else
01112 error ("invalid value for color property \"%s\" (value = %s)",
01113 get_name ().c_str (), s.c_str ());
01114 }
01115 }
01116 else
01117 error ("invalid value for color property \"%s\"",
01118 get_name ().c_str ());
01119 }
01120 else if (val.is_numeric_type ())
01121 {
01122 Matrix m = val.matrix_value ();
01123
01124 if (m.numel () == 3)
01125 {
01126 color_values col (m (0), m (1), m(2));
01127 if (! error_state)
01128 {
01129 if (current_type != color_t || col != color_val)
01130 {
01131 color_val = col;
01132 current_type = color_t;
01133 return true;
01134 }
01135 }
01136 }
01137 else
01138 error ("invalid value for color property \"%s\"",
01139 get_name ().c_str ());
01140 }
01141 else
01142 error ("invalid value for color property \"%s\"",
01143 get_name ().c_str ());
01144
01145 return false;
01146 }
01147
01148 bool
01149 double_radio_property::do_set (const octave_value& val)
01150 {
01151 if (val.is_string ())
01152 {
01153 std::string s = val.string_value ();
01154 std::string match;
01155
01156 if (! s.empty () && radio_val.contains (s, match))
01157 {
01158 if (current_type != radio_t || match != current_val)
01159 {
01160 if (s.length () != match.length ())
01161 warning_with_id ("Octave:abbreviated-property-match",
01162 "%s: allowing %s to match %s value %s",
01163 "set", s.c_str (), get_name ().c_str (),
01164 match.c_str ());
01165 current_val = match;
01166 current_type = radio_t;
01167 return true;
01168 }
01169 }
01170 else
01171 error ("invalid value for double_radio property \"%s\"",
01172 get_name ().c_str ());
01173 }
01174 else if (val.is_scalar_type () && val.is_real_type ())
01175 {
01176 double new_dval = val.double_value ();
01177
01178 if (current_type != double_t || new_dval != dval)
01179 {
01180 dval = new_dval;
01181 current_type = double_t;
01182 return true;
01183 }
01184 }
01185 else
01186 error ("invalid value for double_radio property \"%s\"",
01187 get_name ().c_str ());
01188
01189 return false;
01190 }
01191
01192 bool
01193 array_property::validate (const octave_value& v)
01194 {
01195 bool xok = false;
01196
01197
01198 if (v.is_empty () && v.is_numeric_type ())
01199 return true;
01200
01201
01202 if (type_constraints.size () > 0)
01203 {
01204 for (std::list<std::string>::const_iterator it = type_constraints.begin ();
01205 ! xok && it != type_constraints.end (); ++it)
01206 if ((*it) == v.class_name ())
01207 xok = true;
01208 }
01209 else
01210 xok = v.is_numeric_type ();
01211
01212 if (xok)
01213 {
01214 dim_vector vdims = v.dims ();
01215 int vlen = vdims.length ();
01216
01217 xok = false;
01218
01219
01220 if (size_constraints.size () > 0)
01221 for (std::list<dim_vector>::const_iterator it = size_constraints.begin ();
01222 ! xok && it != size_constraints.end (); ++it)
01223 {
01224 dim_vector itdims = (*it);
01225
01226 if (itdims.length () == vlen)
01227 {
01228 xok = true;
01229
01230 for (int i = 0; xok && i < vlen; i++)
01231 if (itdims(i) >= 0 && itdims(i) != vdims(i))
01232 xok = false;
01233 }
01234 }
01235 else
01236 return true;
01237 }
01238
01239 return xok;
01240 }
01241
01242 bool
01243 array_property::is_equal (const octave_value& v) const
01244 {
01245 if (data.type_name () == v.type_name ())
01246 {
01247 if (data.dims () == v.dims ())
01248 {
01249
01250 #define CHECK_ARRAY_EQUAL(T,F,A) \
01251 { \
01252 if (data.numel () == 1) \
01253 return data.F ## scalar_value () == \
01254 v.F ## scalar_value (); \
01255 else \
01256 { \
01257 \
01258 \
01259 const A m1 = data.F ## array_value (); \
01260 const T* d1 = m1.data (); \
01261 const A m2 = v.F ## array_value (); \
01262 const T* d2 = m2.data ();\
01263 \
01264 bool flag = true; \
01265 \
01266 for (int i = 0; flag && i < data.numel (); i++) \
01267 if (d1[i] != d2[i]) \
01268 flag = false; \
01269 \
01270 return flag; \
01271 } \
01272 }
01273
01274 if (data.is_double_type() || data.is_bool_type ())
01275 CHECK_ARRAY_EQUAL (double, , NDArray)
01276 else if (data.is_single_type ())
01277 CHECK_ARRAY_EQUAL (float, float_, FloatNDArray)
01278 else if (data.is_int8_type ())
01279 CHECK_ARRAY_EQUAL (octave_int8, int8_, int8NDArray)
01280 else if (data.is_int16_type ())
01281 CHECK_ARRAY_EQUAL (octave_int16, int16_, int16NDArray)
01282 else if (data.is_int32_type ())
01283 CHECK_ARRAY_EQUAL (octave_int32, int32_, int32NDArray)
01284 else if (data.is_int64_type ())
01285 CHECK_ARRAY_EQUAL (octave_int64, int64_, int64NDArray)
01286 else if (data.is_uint8_type ())
01287 CHECK_ARRAY_EQUAL (octave_uint8, uint8_, uint8NDArray)
01288 else if (data.is_uint16_type ())
01289 CHECK_ARRAY_EQUAL (octave_uint16, uint16_, uint16NDArray)
01290 else if (data.is_uint32_type ())
01291 CHECK_ARRAY_EQUAL (octave_uint32, uint32_, uint32NDArray)
01292 else if (data.is_uint64_type ())
01293 CHECK_ARRAY_EQUAL (octave_uint64, uint64_, uint64NDArray)
01294 }
01295 }
01296
01297 return false;
01298 }
01299
01300 void
01301 array_property::get_data_limits (void)
01302 {
01303 xmin = xminp = octave_Inf;
01304 xmax = xmaxp = -octave_Inf;
01305
01306 if (! data.is_empty ())
01307 {
01308 if (data.is_integer_type ())
01309 {
01310 if (data.is_int8_type ())
01311 get_array_limits (data.int8_array_value (), xmin, xmax, xminp, xmaxp);
01312 else if (data.is_uint8_type ())
01313 get_array_limits (data.uint8_array_value (), xmin, xmax, xminp, xmaxp);
01314 else if (data.is_int16_type ())
01315 get_array_limits (data.int16_array_value (), xmin, xmax, xminp, xmaxp);
01316 else if (data.is_uint16_type ())
01317 get_array_limits (data.uint16_array_value (), xmin, xmax, xminp, xmaxp);
01318 else if (data.is_int32_type ())
01319 get_array_limits (data.int32_array_value (), xmin, xmax, xminp, xmaxp);
01320 else if (data.is_uint32_type ())
01321 get_array_limits (data.uint32_array_value (), xmin, xmax, xminp, xmaxp);
01322 else if (data.is_int64_type ())
01323 get_array_limits (data.int64_array_value (), xmin, xmax, xminp, xmaxp);
01324 else if (data.is_uint64_type ())
01325 get_array_limits (data.uint64_array_value (), xmin, xmax, xminp, xmaxp);
01326 }
01327 else
01328 get_array_limits (data.array_value (), xmin, xmax, xminp, xmaxp);
01329 }
01330 }
01331
01332 bool
01333 handle_property::do_set (const octave_value& v)
01334 {
01335 double dv = v.double_value ();
01336
01337 if (! error_state)
01338 {
01339 graphics_handle gh = gh_manager::lookup (dv);
01340
01341 if (xisnan (gh.value ()) || gh.ok ())
01342 {
01343 if (current_val != gh)
01344 {
01345 current_val = gh;
01346 return true;
01347 }
01348 }
01349 else
01350 error ("set: invalid graphics handle (= %g) for property \"%s\"",
01351 dv, get_name ().c_str ());
01352 }
01353 else
01354 error ("set: invalid graphics handle for property \"%s\"",
01355 get_name ().c_str ());
01356
01357 return false;
01358 }
01359
01360 Matrix
01361 children_property::do_get_children (bool return_hidden) const
01362 {
01363 Matrix retval (children_list.size (), 1);
01364 octave_idx_type k = 0;
01365
01366 graphics_object go = gh_manager::get_object (0);
01367
01368 root_figure::properties& props =
01369 dynamic_cast<root_figure::properties&> (go.get_properties ());
01370
01371 if (! props.is_showhiddenhandles ())
01372 {
01373 for (const_children_list_iterator p = children_list.begin ();
01374 p != children_list.end (); p++)
01375 {
01376 graphics_handle kid = *p;
01377
01378 if (gh_manager::is_handle_visible (kid))
01379 {
01380 if (! return_hidden)
01381 retval(k++) = *p;
01382 }
01383 else if (return_hidden)
01384 retval(k++) = *p;
01385 }
01386
01387 retval.resize (k, 1);
01388 }
01389 else
01390 {
01391 for (const_children_list_iterator p = children_list.begin ();
01392 p != children_list.end (); p++)
01393 retval(k++) = *p;
01394 }
01395
01396 return retval;
01397 }
01398
01399 void
01400 children_property::do_delete_children (bool clear)
01401 {
01402 for (children_list_iterator p = children_list.begin ();
01403 p != children_list.end (); p++)
01404 {
01405 graphics_object go = gh_manager::get_object (*p);
01406
01407 if (go.valid_object ())
01408 gh_manager::free (*p);
01409
01410 }
01411
01412 if (clear)
01413 children_list.clear ();
01414 }
01415
01416 bool
01417 callback_property::validate (const octave_value& v) const
01418 {
01419
01420
01421
01422
01423
01424
01425 if (v.is_function_handle ())
01426 return true;
01427 else if (v.is_string ())
01428
01429 return true;
01430 else if (v.is_cell () && v.length () > 0
01431 && (v.rows() == 1 || v.columns () == 1)
01432 && v.cell_value ()(0).is_function_handle ())
01433 return true;
01434 else if (v.is_empty ())
01435 return true;
01436
01437 return false;
01438 }
01439
01440
01441
01442
01443 static bool executing_callback = false;
01444
01445 void
01446 callback_property::execute (const octave_value& data) const
01447 {
01448 unwind_protect frame;
01449
01450
01451
01452
01453 frame.protect_var (executing);
01454
01455
01456
01457 frame.protect_var (executing_callback);
01458
01459 if (! executing)
01460 {
01461 executing = true;
01462 executing_callback = true;
01463
01464 if (callback.is_defined () && ! callback.is_empty ())
01465 gh_manager::execute_callback (get_parent (), callback, data);
01466 }
01467 }
01468
01469
01470
01471 static std::map<caseless_str, graphics_object> dprop_obj_map;
01472
01473 property
01474 property::create (const std::string& name, const graphics_handle& h,
01475 const caseless_str& type, const octave_value_list& args)
01476 {
01477 property retval;
01478
01479 if (type.compare ("string"))
01480 {
01481 std::string val = (args.length () > 0 ? args(0).string_value () : "");
01482
01483 if (! error_state)
01484 retval = property (new string_property (name, h, val));
01485 }
01486 else if (type.compare ("any"))
01487 {
01488 octave_value val =
01489 (args.length () > 0 ? args(0) : octave_value (Matrix ()));
01490
01491 retval = property (new any_property (name, h, val));
01492 }
01493 else if (type.compare ("radio"))
01494 {
01495 if (args.length () > 0)
01496 {
01497 std::string vals = args(0).string_value ();
01498
01499 if (! error_state)
01500 {
01501 retval = property (new radio_property (name, h, vals));
01502
01503 if (args.length () > 1)
01504 retval.set (args(1));
01505 }
01506 else
01507 error ("addproperty: invalid argument for radio property, expected a string value");
01508 }
01509 else
01510 error ("addproperty: missing possible values for radio property");
01511 }
01512 else if (type.compare ("double"))
01513 {
01514 double d = (args.length () > 0 ? args(0).double_value () : 0);
01515
01516 if (! error_state)
01517 retval = property (new double_property (name, h, d));
01518 }
01519 else if (type.compare ("handle"))
01520 {
01521 double hh = (args.length () > 0 ? args(0).double_value () : octave_NaN);
01522
01523 if (! error_state)
01524 {
01525 graphics_handle gh (hh);
01526
01527 retval = property (new handle_property (name, h, gh));
01528 }
01529 }
01530 else if (type.compare ("boolean"))
01531 {
01532 retval = property (new bool_property (name, h, false));
01533
01534 if (args.length () > 0)
01535 retval.set (args(0));
01536 }
01537 else if (type.compare ("data"))
01538 {
01539 retval = property (new array_property (name, h, Matrix ()));
01540
01541 if (args.length () > 0)
01542 {
01543 retval.set (args(0));
01544
01545
01546
01547 }
01548 }
01549 else if (type.compare ("color"))
01550 {
01551 color_values cv (0, 0, 0);
01552 radio_values rv;
01553
01554 if (args.length () > 1)
01555 rv = radio_values (args(1).string_value ());
01556
01557 if (! error_state)
01558 {
01559 retval = property (new color_property (name, h, cv, rv));
01560
01561 if (! error_state)
01562 {
01563 if (args.length () > 0 && ! args(0).is_empty ())
01564 retval.set (args(0));
01565 else
01566 retval.set (rv.default_value ());
01567 }
01568 }
01569 }
01570 else
01571 {
01572 caseless_str go_name, go_rest;
01573
01574 if (lookup_object_name (type, go_name, go_rest))
01575 {
01576 graphics_object go;
01577
01578 std::map<caseless_str, graphics_object>::const_iterator it =
01579 dprop_obj_map.find (go_name);
01580
01581 if (it == dprop_obj_map.end ())
01582 {
01583 base_graphics_object *bgo =
01584 make_graphics_object_from_type (go_name);
01585
01586 if (bgo)
01587 {
01588 go = graphics_object (bgo);
01589
01590 dprop_obj_map[go_name] = go;
01591 }
01592 }
01593 else
01594 go = it->second;
01595
01596 if (go.valid_object ())
01597 {
01598 property prop = go.get_properties ().get_property (go_rest);
01599
01600 if (! error_state)
01601 {
01602 retval = prop.clone ();
01603
01604 retval.set_parent (h);
01605 retval.set_name (name);
01606
01607 if (args.length () > 0)
01608 retval.set (args(0));
01609 }
01610 }
01611 else
01612 error ("addproperty: invalid object type (= %s)",
01613 go_name.c_str ());
01614 }
01615 else
01616 error ("addproperty: unsupported type for dynamic property (= %s)",
01617 type.c_str ());
01618 }
01619
01620 return retval;
01621 }
01622
01623 static void
01624 finalize_r (const graphics_handle& h)
01625 {
01626 graphics_object go = gh_manager::get_object (h);
01627
01628 if (go)
01629 {
01630 Matrix children = go.get_properties ().get_all_children ();
01631
01632 for (int k = 0; k < children.numel (); k++)
01633 finalize_r (children(k));
01634
01635 go.finalize ();
01636 }
01637 }
01638
01639 static void
01640 initialize_r (const graphics_handle& h)
01641 {
01642 graphics_object go = gh_manager::get_object (h);
01643
01644 if (go)
01645 {
01646 Matrix children = go.get_properties ().get_all_children ();
01647
01648 go.initialize ();
01649
01650 for (int k = 0; k < children.numel (); k++)
01651 initialize_r (children(k));
01652 }
01653 }
01654
01655 void
01656 figure::properties::set_toolkit (const graphics_toolkit& b)
01657 {
01658 if (toolkit)
01659 finalize_r (get___myhandle__ ());
01660
01661 toolkit = b;
01662 __graphics_toolkit__ = b.get_name ();
01663 __plot_stream__ = Matrix ();
01664
01665 if (toolkit)
01666 initialize_r (get___myhandle__ ());
01667
01668 mark_modified ();
01669 }
01670
01671
01672
01673 void
01674 property_list::set (const caseless_str& name, const octave_value& val)
01675 {
01676 size_t offset = 0;
01677
01678 size_t len = name.length ();
01679
01680 if (len > 4)
01681 {
01682 caseless_str pfx = name.substr (0, 4);
01683
01684 if (pfx.compare ("axes") || pfx.compare ("line")
01685 || pfx.compare ("text"))
01686 offset = 4;
01687 else if (len > 5)
01688 {
01689 pfx = name.substr (0, 5);
01690
01691 if (pfx.compare ("image") || pfx.compare ("patch"))
01692 offset = 5;
01693 else if (len > 6)
01694 {
01695 pfx = name.substr (0, 6);
01696
01697 if (pfx.compare ("figure") || pfx.compare ("uimenu"))
01698 offset = 6;
01699 else if (len > 7)
01700 {
01701 pfx = name.substr (0, 7);
01702
01703 if (pfx.compare ("surface") || pfx.compare ("hggroup")
01704 || pfx.compare ("uipanel"))
01705 offset = 7;
01706 else if (len > 9)
01707 {
01708 pfx = name.substr (0, 9);
01709
01710 if (pfx.compare ("uicontrol")
01711 || pfx.compare ("uitoolbar"))
01712 offset = 9;
01713 else if (len > 10)
01714 {
01715 pfx = name.substr (0, 10);
01716
01717 if (pfx.compare ("uipushtool"))
01718 offset = 10;
01719 else if (len > 12)
01720 {
01721 pfx = name.substr (0, 12);
01722
01723 if (pfx.compare ("uitoogletool"))
01724 offset = 12;
01725 else if (len > 13)
01726 {
01727 pfx = name.substr (0, 13);
01728
01729 if (pfx.compare ("uicontextmenu"))
01730 offset = 13;
01731 }
01732 }
01733 }
01734 }
01735 }
01736 }
01737 }
01738
01739 if (offset > 0)
01740 {
01741
01742
01743 std::string pname = name.substr (offset);
01744
01745 std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
01746 std::transform (pname.begin (), pname.end (), pname.begin (), tolower);
01747
01748 bool has_property = false;
01749 if (pfx == "axes")
01750 has_property = axes::properties::has_core_property (pname);
01751 else if (pfx == "line")
01752 has_property = line::properties::has_core_property (pname);
01753 else if (pfx == "text")
01754 has_property = text::properties::has_core_property (pname);
01755 else if (pfx == "image")
01756 has_property = image::properties::has_core_property (pname);
01757 else if (pfx == "patch")
01758 has_property = patch::properties::has_core_property (pname);
01759 else if (pfx == "figure")
01760 has_property = figure::properties::has_core_property (pname);
01761 else if (pfx == "surface")
01762 has_property = surface::properties::has_core_property (pname);
01763 else if (pfx == "hggroup")
01764 has_property = hggroup::properties::has_core_property (pname);
01765 else if (pfx == "uimenu")
01766 has_property = uimenu::properties::has_core_property (pname);
01767 else if (pfx == "uicontrol")
01768 has_property = uicontrol::properties::has_core_property (pname);
01769 else if (pfx == "uipanel")
01770 has_property = uipanel::properties::has_core_property (pname);
01771 else if (pfx == "uicontextmenu")
01772 has_property = uicontextmenu::properties::has_core_property (pname);
01773 else if (pfx == "uitoolbar")
01774 has_property = uitoolbar::properties::has_core_property (pname);
01775 else if (pfx == "uipushtool")
01776 has_property = uipushtool::properties::has_core_property (pname);
01777
01778 if (has_property)
01779 {
01780 bool remove = false;
01781 if (val.is_string ())
01782 {
01783 caseless_str tval = val.string_value ();
01784
01785 remove = tval.compare ("remove");
01786 }
01787
01788 pval_map_type& pval_map = plist_map[pfx];
01789
01790 if (remove)
01791 {
01792 pval_map_iterator p = pval_map.find (pname);
01793
01794 if (p != pval_map.end ())
01795 pval_map.erase (p);
01796 }
01797 else
01798 pval_map[pname] = val;
01799 }
01800 else
01801 error ("invalid %s property '%s'", pfx.c_str (), pname.c_str ());
01802 }
01803 }
01804
01805 if (! error_state && offset == 0)
01806 error ("invalid default property specification");
01807 }
01808
01809 octave_value
01810 property_list::lookup (const caseless_str& name) const
01811 {
01812 octave_value retval;
01813
01814 size_t offset = 0;
01815
01816 size_t len = name.length ();
01817
01818 if (len > 4)
01819 {
01820 caseless_str pfx = name.substr (0, 4);
01821
01822 if (pfx.compare ("axes") || pfx.compare ("line")
01823 || pfx.compare ("text"))
01824 offset = 4;
01825 else if (len > 5)
01826 {
01827 pfx = name.substr (0, 5);
01828
01829 if (pfx.compare ("image") || pfx.compare ("patch"))
01830 offset = 5;
01831 else if (len > 6)
01832 {
01833 pfx = name.substr (0, 6);
01834
01835 if (pfx.compare ("figure") || pfx.compare ("uimenu"))
01836 offset = 6;
01837 else if (len > 7)
01838 {
01839 pfx = name.substr (0, 7);
01840
01841 if (pfx.compare ("surface") || pfx.compare ("hggroup")
01842 || pfx.compare ("uipanel"))
01843 offset = 7;
01844 else if (len > 9)
01845 {
01846 pfx = name.substr (0, 9);
01847
01848 if (pfx.compare ("uicontrol")
01849 || pfx.compare ("uitoolbar"))
01850 offset = 9;
01851 else if (len > 10)
01852 {
01853 pfx = name.substr (0, 10);
01854
01855 if (pfx.compare ("uipushtool"))
01856 offset = 10;
01857 else if (len > 12)
01858 {
01859 pfx = name.substr (0, 12);
01860
01861 if (pfx.compare ("uitoggletool"))
01862 offset = 12;
01863 else if (len > 13)
01864 {
01865 pfx = name.substr (0, 13);
01866
01867 if (pfx.compare ("uicontextmenu"))
01868 offset = 13;
01869 }
01870 }
01871 }
01872 }
01873 }
01874 }
01875 }
01876
01877 if (offset > 0)
01878 {
01879 std::string pname = name.substr (offset);
01880
01881 std::transform (pfx.begin (), pfx.end (), pfx.begin (), tolower);
01882 std::transform (pname.begin (), pname.end (), pname.begin (), tolower);
01883
01884 plist_map_const_iterator p = find (pfx);
01885
01886 if (p != end ())
01887 {
01888 const pval_map_type& pval_map = p->second;
01889
01890 pval_map_const_iterator q = pval_map.find (pname);
01891
01892 if (q != pval_map.end ())
01893 retval = q->second;
01894 }
01895 }
01896 }
01897
01898 return retval;
01899 }
01900
01901 octave_scalar_map
01902 property_list::as_struct (const std::string& prefix_arg) const
01903 {
01904 octave_scalar_map m;
01905
01906 for (plist_map_const_iterator p = begin (); p != end (); p++)
01907 {
01908 std::string prefix = prefix_arg + p->first;
01909
01910 const pval_map_type pval_map = p->second;
01911
01912 for (pval_map_const_iterator q = pval_map.begin ();
01913 q != pval_map.end ();
01914 q++)
01915 m.assign (prefix + q->first, q->second);
01916 }
01917
01918 return m;
01919 }
01920
01921 graphics_handle::graphics_handle (const octave_value& a)
01922 : val (octave_NaN)
01923 {
01924 if (a.is_empty ())
01925 ;
01926 else
01927 {
01928 double tval = a.double_value ();
01929
01930 if (! error_state)
01931 val = tval;
01932 else
01933 error ("invalid graphics handle");
01934 }
01935 }
01936
01937
01938
01939 void
01940 graphics_object::set (const octave_value_list& args)
01941 {
01942 int nargin = args.length ();
01943
01944 if (nargin == 0)
01945 error ("graphics_object::set: Nothing to set");
01946 else if (nargin % 2 == 0)
01947 {
01948 for (int i = 0; i < nargin; i += 2)
01949 {
01950 caseless_str name = args(i).string_value ();
01951
01952 if (! error_state)
01953 {
01954 octave_value val = args(i+1);
01955
01956 set_value_or_default (name, val);
01957
01958 if (error_state)
01959 break;
01960 }
01961 else
01962 error ("set: expecting argument %d to be a property name", i);
01963 }
01964 }
01965 else
01966 error ("set: invalid number of arguments");
01967 }
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980 void
01981 graphics_object::set (const Array<std::string>& names,
01982 const Cell& values, octave_idx_type row)
01983 {
01984 if (names.numel () != values.columns ())
01985 {
01986 error("set: number of names must match number of value columns (%d != %d)",
01987 names.numel (), values.columns ());
01988 }
01989
01990 octave_idx_type k = names.columns ();
01991
01992 for (octave_idx_type column = 0; column < k; column++)
01993 {
01994 caseless_str name = names(column);
01995 octave_value val = values(row, column);
01996
01997 set_value_or_default (name, val);
01998
01999 if (error_state)
02000 break;
02001 }
02002 }
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036 void
02037 graphics_object::set (const octave_map& m)
02038 {
02039 for (octave_map::const_iterator p = m.begin ();
02040 p != m.end (); p++)
02041 {
02042 caseless_str name = m.key (p);
02043
02044 octave_value val = octave_value (m.contents (p).elem (m.numel () - 1));
02045
02046 set_value_or_default (name, val);
02047
02048 if (error_state)
02049 break;
02050 }
02051 }
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068 void
02069 graphics_object::set_value_or_default (const caseless_str& name,
02070 const octave_value& val)
02071 {
02072 if (val.is_string ())
02073 {
02074 caseless_str tval = val.string_value ();
02075
02076 octave_value default_val;
02077
02078 if (tval.compare ("default"))
02079 {
02080 default_val = get_default (name);
02081
02082 if (error_state)
02083 return;
02084
02085 rep->set (name, default_val);
02086 }
02087 else if (tval.compare ("factory"))
02088 {
02089 default_val = get_factory_default (name);
02090
02091 if (error_state)
02092 return;
02093
02094 rep->set (name, default_val);
02095 }
02096 else
02097 rep->set (name, val);
02098 }
02099 else
02100 rep->set (name, val);
02101 }
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115 static double
02116 make_handle_fraction (void)
02117 {
02118 static double maxrand = RAND_MAX + 2.0;
02119
02120 return (rand () + 1.0) / maxrand;
02121 }
02122
02123 graphics_handle
02124 gh_manager::do_get_handle (bool integer_figure_handle)
02125 {
02126 graphics_handle retval;
02127
02128 if (integer_figure_handle)
02129 {
02130
02131
02132
02133
02134
02135 retval = 1;
02136
02137 while (handle_map.find (retval) != handle_map.end ())
02138 retval++;
02139 }
02140 else
02141 {
02142
02143
02144
02145
02146
02147 free_list_iterator p = handle_free_list.begin ();
02148
02149 if (p != handle_free_list.end ())
02150 {
02151 retval = *p;
02152 handle_free_list.erase (p);
02153 }
02154 else
02155 {
02156 retval = graphics_handle (next_handle);
02157
02158 next_handle = std::ceil (next_handle) - 1.0 - make_handle_fraction ();
02159 }
02160 }
02161
02162 return retval;
02163 }
02164
02165 void
02166 gh_manager::do_free (const graphics_handle& h)
02167 {
02168 if (h.ok ())
02169 {
02170 if (h.value () != 0)
02171 {
02172 iterator p = handle_map.find (h);
02173
02174 if (p != handle_map.end ())
02175 {
02176 base_properties& bp = p->second.get_properties ();
02177
02178 bp.set_beingdeleted (true);
02179
02180 bp.delete_children ();
02181
02182 octave_value val = bp.get_deletefcn ();
02183
02184 bp.execute_deletefcn ();
02185
02186
02187 p->second.finalize ();
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198 handle_map.erase (p);
02199
02200 if (h.value () < 0)
02201 handle_free_list.insert (std::ceil (h.value ()) - make_handle_fraction ());
02202 }
02203 else
02204 error ("graphics_handle::free: invalid object %g", h.value ());
02205 }
02206 else
02207 error ("graphics_handle::free: can't delete root figure");
02208 }
02209 }
02210
02211 void
02212 gh_manager::do_renumber_figure (const graphics_handle& old_gh,
02213 const graphics_handle& new_gh)
02214 {
02215 iterator p = handle_map.find (old_gh);
02216
02217 if (p != handle_map.end ())
02218 {
02219 graphics_object go = p->second;
02220
02221 handle_map.erase (p);
02222
02223 handle_map[new_gh] = go;
02224
02225 if (old_gh.value () < 0)
02226 handle_free_list.insert (std::ceil (old_gh.value ())
02227 - make_handle_fraction ());
02228 }
02229 else
02230 error ("graphics_handle::free: invalid object %g", old_gh.value ());
02231
02232 for (figure_list_iterator q = figure_list.begin ();
02233 q != figure_list.end (); q++)
02234 {
02235 if (*q == old_gh)
02236 {
02237 *q = new_gh;
02238 break;
02239 }
02240 }
02241 }
02242
02243 gh_manager *gh_manager::instance = 0;
02244
02245 static void
02246 xset (const graphics_handle& h, const caseless_str& name,
02247 const octave_value& val)
02248 {
02249 graphics_object obj = gh_manager::get_object (h);
02250 obj.set (name, val);
02251 }
02252
02253 static void
02254 xset (const graphics_handle& h, const octave_value_list& args)
02255 {
02256 if (args.length () > 0)
02257 {
02258 graphics_object obj = gh_manager::get_object (h);
02259 obj.set (args);
02260 }
02261 }
02262
02263 static octave_value
02264 xget (const graphics_handle& h, const caseless_str& name)
02265 {
02266 graphics_object obj = gh_manager::get_object (h);
02267 return obj.get (name);
02268 }
02269
02270 static graphics_handle
02271 reparent (const octave_value& ov, const std::string& who,
02272 const std::string& property, const graphics_handle& new_parent,
02273 bool adopt = true)
02274 {
02275 graphics_handle h = octave_NaN;
02276
02277 double val = ov.double_value ();
02278
02279 if (! error_state)
02280 {
02281 h = gh_manager::lookup (val);
02282
02283 if (h.ok ())
02284 {
02285 graphics_object obj = gh_manager::get_object (h);
02286
02287 graphics_handle parent_h = obj.get_parent ();
02288
02289 graphics_object parent_obj = gh_manager::get_object (parent_h);
02290
02291 parent_obj.remove_child (h);
02292
02293 if (adopt)
02294 obj.set ("parent", new_parent.value ());
02295 else
02296 obj.reparent (new_parent);
02297 }
02298 else
02299 error ("%s: invalid graphics handle (= %g) for %s",
02300 who.c_str (), val, property.c_str ());
02301 }
02302 else
02303 error ("%s: expecting %s to be a graphics handle",
02304 who.c_str (), property.c_str ());
02305
02306 return h;
02307 }
02308
02309
02310 graphics_handle
02311 gcf (void)
02312 {
02313 octave_value val = xget (0, "currentfigure");
02314
02315 return val.is_empty () ? octave_NaN : val.double_value ();
02316 }
02317
02318
02319 graphics_handle
02320 gca (void)
02321 {
02322 octave_value val = xget (gcf (), "currentaxes");
02323
02324 return val.is_empty () ? octave_NaN : val.double_value ();
02325 }
02326
02327 static void
02328 delete_graphics_object (const graphics_handle& h)
02329 {
02330 if (h.ok ())
02331 {
02332 graphics_object obj = gh_manager::get_object (h);
02333
02334
02335 if (! obj.get_properties ().is_beingdeleted ())
02336 {
02337 graphics_handle parent_h = obj.get_parent ();
02338
02339 graphics_object parent_obj =
02340 gh_manager::get_object (parent_h);
02341
02342
02343
02344
02345
02346
02347 gh_manager::free (h);
02348
02349
02350
02351 if (parent_obj.valid_object ())
02352 parent_obj.remove_child (h);
02353
02354 Vdrawnow_requested = true;
02355 }
02356 }
02357 }
02358
02359 static void
02360 delete_graphics_object (double val)
02361 {
02362 delete_graphics_object (gh_manager::lookup (val));
02363 }
02364
02365 static void
02366 delete_graphics_objects (const NDArray vals)
02367 {
02368 for (octave_idx_type i = 0; i < vals.numel (); i++)
02369 delete_graphics_object (vals.elem (i));
02370 }
02371
02372 static void
02373 close_figure (const graphics_handle& handle)
02374 {
02375 octave_value closerequestfcn = xget (handle, "closerequestfcn");
02376
02377 OCTAVE_SAFE_CALL (gh_manager::execute_callback, (handle, closerequestfcn));
02378 }
02379
02380 static void
02381 force_close_figure (const graphics_handle& handle)
02382 {
02383
02384
02385
02386 xset (handle, "deletefcn", Matrix ());
02387 xset (handle, "closerequestfcn", Matrix ());
02388
02389 delete_graphics_object (handle);
02390 }
02391
02392 void
02393 gh_manager::do_close_all_figures (void)
02394 {
02395
02396
02397 event_queue.clear ();
02398
02399
02400
02401
02402 Matrix hlist = do_figure_handle_list (true);
02403
02404 for (octave_idx_type i = 0; i < hlist.numel (); i++)
02405 {
02406 graphics_handle h = gh_manager::lookup (hlist(i));
02407
02408 if (h.ok ())
02409 close_figure (h);
02410 }
02411
02412
02413
02414 hlist = do_figure_handle_list (true);
02415
02416 for (octave_idx_type i = 0; i < hlist.numel (); i++)
02417 {
02418 graphics_handle h = gh_manager::lookup (hlist(i));
02419
02420 if (h.ok ())
02421 force_close_figure (h);
02422 }
02423
02424
02425
02426 hlist = do_figure_handle_list (true);
02427
02428 assert (hlist.numel () == 0);
02429
02430
02431
02432 callback_objects.clear ();
02433 }
02434
02435 static void
02436 adopt (const graphics_handle& p, const graphics_handle& h)
02437 {
02438 graphics_object parent_obj = gh_manager::get_object (p);
02439 parent_obj.adopt (h);
02440 }
02441
02442 static bool
02443 is_handle (const graphics_handle& h)
02444 {
02445 return h.ok ();
02446 }
02447
02448 static bool
02449 is_handle (double val)
02450 {
02451 graphics_handle h = gh_manager::lookup (val);
02452
02453 return h.ok ();
02454 }
02455
02456 static octave_value
02457 is_handle (const octave_value& val)
02458 {
02459 octave_value retval = false;
02460
02461 if (val.is_real_scalar () && is_handle (val.double_value ()))
02462 retval = true;
02463 else if (val.is_numeric_type () && val.is_real_type ())
02464 {
02465 const NDArray handles = val.array_value ();
02466
02467 if (! error_state)
02468 {
02469 boolNDArray result (handles.dims ());
02470
02471 for (octave_idx_type i = 0; i < handles.numel (); i++)
02472 result.xelem (i) = is_handle (handles (i));
02473
02474 retval = result;
02475 }
02476 }
02477
02478 return retval;
02479 }
02480
02481 static bool
02482 is_figure (double val)
02483 {
02484 graphics_object obj = gh_manager::get_object (val);
02485
02486 return obj && obj.isa ("figure");
02487 }
02488
02489 static void
02490 xcreatefcn (const graphics_handle& h)
02491 {
02492 graphics_object obj = gh_manager::get_object (h);
02493 obj.get_properties ().execute_createfcn ();
02494 }
02495
02496 static void
02497 xinitialize (const graphics_handle& h)
02498 {
02499 graphics_object go = gh_manager::get_object (h);
02500
02501 if (go)
02502 go.initialize ();
02503 }
02504
02505
02506
02507 void
02508 base_graphics_toolkit::update (const graphics_handle& h, int id)
02509 {
02510 graphics_object go = gh_manager::get_object (h);
02511
02512 update (go, id);
02513 }
02514
02515 bool
02516 base_graphics_toolkit::initialize (const graphics_handle& h)
02517 {
02518 graphics_object go = gh_manager::get_object (h);
02519
02520 return initialize (go);
02521 }
02522
02523 void
02524 base_graphics_toolkit::finalize (const graphics_handle& h)
02525 {
02526 graphics_object go = gh_manager::get_object (h);
02527
02528 finalize (go);
02529 }
02530
02531
02532
02533 void
02534 base_properties::set_from_list (base_graphics_object& obj,
02535 property_list& defaults)
02536 {
02537 std::string go_name = graphics_object_name ();
02538
02539 property_list::plist_map_const_iterator p = defaults.find (go_name);
02540
02541 if (p != defaults.end ())
02542 {
02543 const property_list::pval_map_type pval_map = p->second;
02544
02545 for (property_list::pval_map_const_iterator q = pval_map.begin ();
02546 q != pval_map.end ();
02547 q++)
02548 {
02549 std::string pname = q->first;
02550
02551 obj.set (pname, q->second);
02552
02553 if (error_state)
02554 {
02555 error ("error setting default property %s", pname.c_str ());
02556 break;
02557 }
02558 }
02559 }
02560 }
02561
02562 octave_value
02563 base_properties::get_dynamic (const caseless_str& name) const
02564 {
02565 octave_value retval;
02566
02567 std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.find (name);
02568
02569 if (it != all_props.end ())
02570 retval = it->second.get ();
02571 else
02572 error ("get: unknown property \"%s\"", name.c_str ());
02573
02574 return retval;
02575 }
02576
02577 octave_value
02578 base_properties::get_dynamic (bool all) const
02579 {
02580 octave_scalar_map m;
02581
02582 for (std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.begin ();
02583 it != all_props.end (); ++it)
02584 if (all || ! it->second.is_hidden ())
02585 m.assign (it->second.get_name (), it->second.get ());
02586
02587 return m;
02588 }
02589
02590 std::set<std::string>
02591 base_properties::dynamic_property_names (void) const
02592 {
02593 return dynamic_properties;
02594 }
02595
02596 bool
02597 base_properties::has_dynamic_property (const std::string& pname)
02598 {
02599 const std::set<std::string>& dynprops = dynamic_property_names ();
02600
02601 if (dynprops.find (pname) != dynprops.end ())
02602 return true;
02603 else
02604 return all_props.find (pname) != all_props.end ();
02605 }
02606
02607 void
02608 base_properties::set_dynamic (const caseless_str& pname,
02609 const octave_value& val)
02610 {
02611 std::map<caseless_str, property, cmp_caseless_str>::iterator it = all_props.find (pname);
02612
02613 if (it != all_props.end ())
02614 it->second.set (val);
02615 else
02616 error ("set: unknown property \"%s\"", pname.c_str ());
02617
02618 if (! error_state)
02619 {
02620 dynamic_properties.insert (pname);
02621
02622 mark_modified ();
02623 }
02624 }
02625
02626 property
02627 base_properties::get_property_dynamic (const caseless_str& name)
02628 {
02629 std::map<caseless_str, property, cmp_caseless_str>::const_iterator it = all_props.find (name);
02630
02631 if (it == all_props.end ())
02632 {
02633 error ("get_property: unknown property \"%s\"", name.c_str ());
02634 return property ();
02635 }
02636 else
02637 return it->second;
02638 }
02639
02640 void
02641 base_properties::set_parent (const octave_value& val)
02642 {
02643 double tmp = val.double_value ();
02644
02645 graphics_handle new_parent = octave_NaN;
02646
02647 if (! error_state)
02648 {
02649 new_parent = gh_manager::lookup (tmp);
02650
02651 if (new_parent.ok ())
02652 {
02653 graphics_object parent_obj = gh_manager::get_object (get_parent ());
02654
02655 parent_obj.remove_child (__myhandle__);
02656
02657 parent = new_parent.as_octave_value ();
02658
02659 ::adopt (parent.handle_value (), __myhandle__);
02660 }
02661 else
02662 error ("set: invalid graphics handle (= %g) for parent", tmp);
02663 }
02664 else
02665 error ("set: expecting parent to be a graphics handle");
02666 }
02667
02668 void
02669 base_properties::mark_modified (void)
02670 {
02671 __modified__ = "on";
02672 graphics_object parent_obj = gh_manager::get_object (get_parent ());
02673 if (parent_obj)
02674 parent_obj.mark_modified ();
02675 }
02676
02677 void
02678 base_properties::override_defaults (base_graphics_object& obj)
02679 {
02680 graphics_object parent_obj = gh_manager::get_object (get_parent ());
02681
02682 if (parent_obj)
02683 parent_obj.override_defaults (obj);
02684 }
02685
02686 void
02687 base_properties::update_axis_limits (const std::string& axis_type) const
02688 {
02689 graphics_object obj = gh_manager::get_object (__myhandle__);
02690
02691 if (obj)
02692 obj.update_axis_limits (axis_type);
02693 }
02694
02695 void
02696 base_properties::update_axis_limits (const std::string& axis_type,
02697 const graphics_handle& h) const
02698 {
02699 graphics_object obj = gh_manager::get_object (__myhandle__);
02700
02701 if (obj)
02702 obj.update_axis_limits (axis_type, h);
02703 }
02704
02705 bool
02706 base_properties::is_handle_visible (void) const
02707 {
02708 return (handlevisibility.is ("on")
02709 || (executing_callback && ! handlevisibility.is ("off")));
02710 }
02711
02712 graphics_toolkit
02713 base_properties::get_toolkit (void) const
02714 {
02715 graphics_object go = gh_manager::get_object (get_parent ());
02716
02717 if (go)
02718 return go.get_toolkit ();
02719 else
02720 return graphics_toolkit ();
02721 }
02722
02723 void
02724 base_properties::update_boundingbox (void)
02725 {
02726 Matrix kids = get_children ();
02727
02728 for (int i = 0; i < kids.numel (); i++)
02729 {
02730 graphics_object go = gh_manager::get_object (kids(i));
02731
02732 if (go.valid_object ())
02733 go.get_properties ().update_boundingbox ();
02734 }
02735 }
02736
02737 void
02738 base_properties::update_autopos (const std::string& elem_type)
02739 {
02740 graphics_object parent_obj = gh_manager::get_object (get_parent ());
02741
02742 if (parent_obj.valid_object ())
02743 parent_obj.get_properties ().update_autopos (elem_type);
02744 }
02745
02746 void
02747 base_properties::add_listener (const caseless_str& nm, const octave_value& v,
02748 listener_mode mode)
02749 {
02750 property p = get_property (nm);
02751
02752 if (! error_state && p.ok ())
02753 p.add_listener (v, mode);
02754 }
02755
02756 void
02757 base_properties::delete_listener (const caseless_str& nm,
02758 const octave_value& v, listener_mode mode)
02759 {
02760 property p = get_property (nm);
02761
02762 if (! error_state && p.ok ())
02763 p.delete_listener (v, mode);
02764 }
02765
02766
02767
02768 void
02769 base_graphics_object::update_axis_limits (const std::string& axis_type)
02770 {
02771 if (valid_object ())
02772 {
02773 graphics_object parent_obj = gh_manager::get_object (get_parent ());
02774
02775 if (parent_obj)
02776 parent_obj.update_axis_limits (axis_type);
02777 }
02778 else
02779 error ("base_graphics_object::update_axis_limits: invalid graphics object");
02780 }
02781
02782 void
02783 base_graphics_object::update_axis_limits (const std::string& axis_type,
02784 const graphics_handle& h)
02785 {
02786 if (valid_object ())
02787 {
02788 graphics_object parent_obj = gh_manager::get_object (get_parent ());
02789
02790 if (parent_obj)
02791 parent_obj.update_axis_limits (axis_type, h);
02792 }
02793 else
02794 error ("base_graphics_object::update_axis_limits: invalid graphics object");
02795 }
02796
02797 void
02798 base_graphics_object::remove_all_listeners (void)
02799 {
02800 octave_map m = get (true).map_value ();
02801
02802 for (octave_map::const_iterator pa = m.begin (); pa != m.end (); pa++)
02803 {
02804
02805
02806
02807
02808 unwind_protect frame;
02809
02810 frame.protect_var (error_state);
02811 frame.protect_var (discard_error_messages);
02812 frame.protect_var (Vdebug_on_error);
02813 frame.protect_var (Vdebug_on_warning);
02814
02815 discard_error_messages = true;
02816 Vdebug_on_error = false;
02817 Vdebug_on_warning = false;
02818
02819 property p = get_properties ().get_property (pa->first);
02820
02821 if (! error_state && p.ok ())
02822 p.delete_listener ();
02823 }
02824 }
02825
02826 std::string
02827 base_graphics_object::values_as_string (void)
02828 {
02829 std::string retval;
02830
02831 if (valid_object ())
02832 {
02833 octave_map m = get ().map_value ();
02834
02835 for (octave_map::const_iterator pa = m.begin (); pa != m.end (); pa++)
02836 {
02837 if (pa->first != "children")
02838 {
02839 property p = get_properties ().get_property (pa->first);
02840
02841 if (p.ok () && ! p.is_hidden ())
02842 {
02843 retval += "\n\t" + std::string (pa->first) + ": ";
02844 if (p.is_radio ())
02845 retval += p.values_as_string ();
02846 }
02847 }
02848 }
02849 if (retval != "")
02850 retval += "\n";
02851 }
02852 else
02853 error ("base_graphics_object::values_as_string: invalid graphics object");
02854
02855 return retval;
02856 }
02857
02858 octave_scalar_map
02859 base_graphics_object::values_as_struct (void)
02860 {
02861 octave_scalar_map retval;
02862
02863 if (valid_object ())
02864 {
02865 octave_scalar_map m = get ().scalar_map_value ();
02866
02867 for (octave_scalar_map::const_iterator pa = m.begin ();
02868 pa != m.end (); pa++)
02869 {
02870 if (pa->first != "children")
02871 {
02872 property p = get_properties ().get_property (pa->first);
02873
02874 if (p.ok () && ! p.is_hidden ())
02875 {
02876 if (p.is_radio ())
02877 retval.assign (p.get_name (), p.values_as_cell ());
02878 else
02879 retval.assign (p.get_name (), Cell ());
02880 }
02881 }
02882 }
02883 }
02884 else
02885 error ("base_graphics_object::values_as_struct: invalid graphics object");
02886
02887 return retval;
02888 }
02889
02890 graphics_object
02891 graphics_object::get_ancestor (const std::string& obj_type) const
02892 {
02893 if (valid_object ())
02894 {
02895 if (isa (obj_type))
02896 return *this;
02897 else
02898 return gh_manager::get_object (get_parent ()).get_ancestor (obj_type);
02899 }
02900 else
02901 return graphics_object ();
02902 }
02903
02904
02905
02906 #include "graphics-props.cc"
02907
02908
02909
02910 void
02911 root_figure::properties::set_currentfigure (const octave_value& v)
02912 {
02913 graphics_handle val (v);
02914
02915 if (error_state)
02916 return;
02917
02918 if (xisnan (val.value ()) || is_handle (val))
02919 {
02920 currentfigure = val;
02921
02922 if (val.ok ())
02923 gh_manager::push_figure (val);
02924 }
02925 else
02926 gripe_set_invalid ("currentfigure");
02927 }
02928
02929 void
02930 root_figure::properties::set_callbackobject (const octave_value& v)
02931 {
02932 graphics_handle val (v);
02933
02934 if (error_state)
02935 return;
02936
02937 if (xisnan (val.value ()))
02938 {
02939 if (! cbo_stack.empty ())
02940 {
02941 val = cbo_stack.front ();
02942
02943 cbo_stack.pop_front ();
02944 }
02945
02946 callbackobject = val;
02947 }
02948 else if (is_handle (val))
02949 {
02950 if (get_callbackobject ().ok ())
02951 cbo_stack.push_front (get_callbackobject ());
02952
02953 callbackobject = val;
02954 }
02955 else
02956 gripe_set_invalid ("callbackobject");
02957 }
02958
02959 void
02960 figure::properties::set_integerhandle (const octave_value& val)
02961 {
02962 if (! error_state)
02963 {
02964 if (integerhandle.set (val, true))
02965 {
02966 bool int_fig_handle = integerhandle.is_on ();
02967
02968 graphics_object this_go = gh_manager::get_object (__myhandle__);
02969
02970 graphics_handle old_myhandle = __myhandle__;
02971
02972 __myhandle__ = gh_manager::get_handle (int_fig_handle);
02973
02974 gh_manager::renumber_figure (old_myhandle, __myhandle__);
02975
02976 graphics_object parent_go = gh_manager::get_object (get_parent ());
02977
02978 base_properties& props = parent_go.get_properties ();
02979
02980 props.renumber_child (old_myhandle, __myhandle__);
02981
02982 Matrix kids = get_children ();
02983
02984 for (octave_idx_type i = 0; i < kids.numel (); i++)
02985 {
02986 graphics_object kid = gh_manager::get_object (kids(i));
02987
02988 kid.get_properties ().renumber_parent (__myhandle__);
02989 }
02990
02991 graphics_handle cf = gh_manager::current_figure ();
02992
02993 if (__myhandle__ == cf)
02994 xset (0, "currentfigure", __myhandle__.value ());
02995
02996 this_go.update (integerhandle.get_id ());
02997
02998 mark_modified ();
02999 }
03000 }
03001 }
03002
03003
03004
03005
03006 void
03007 root_figure::properties::update_units (void)
03008 {
03009 caseless_str xunits = get_units ();
03010
03011 Matrix ss = default_screensize ();
03012
03013 double dpi = get_screenpixelsperinch ();
03014
03015 if (xunits.compare ("inches"))
03016 {
03017 ss(0) = 0;
03018 ss(1) = 0;
03019 ss(2) /= dpi;
03020 ss(3) /= dpi;
03021 }
03022 else if (xunits.compare ("centimeters"))
03023 {
03024 ss(0) = 0;
03025 ss(1) = 0;
03026 ss(2) *= 2.54 / dpi;
03027 ss(3) *= 2.54 / dpi;
03028 }
03029 else if (xunits.compare ("normalized"))
03030 {
03031 ss = Matrix (1, 4, 1.0);
03032 }
03033 else if (xunits.compare ("points"))
03034 {
03035 ss(0) = 0;
03036 ss(1) = 0;
03037 ss(2) *= 72 / dpi;
03038 ss(3) *= 72 / dpi;
03039 }
03040
03041 set_screensize (ss);
03042 }
03043
03044 void
03045 root_figure::properties::remove_child (const graphics_handle& gh)
03046 {
03047 gh_manager::pop_figure (gh);
03048
03049 graphics_handle cf = gh_manager::current_figure ();
03050
03051 xset (0, "currentfigure", cf.value ());
03052
03053 base_properties::remove_child (gh);
03054 }
03055
03056 property_list
03057 root_figure::factory_properties = root_figure::init_factory_properties ();
03058
03059 static void
03060 reset_default_properties (property_list& default_properties)
03061 {
03062 property_list new_defaults;
03063
03064 for (property_list::plist_map_const_iterator p = default_properties.begin ();
03065 p != default_properties.end (); p++)
03066 {
03067 const property_list::pval_map_type pval_map = p->second;
03068 std::string prefix = p->first;
03069
03070 for (property_list::pval_map_const_iterator q = pval_map.begin ();
03071 q != pval_map.end ();
03072 q++)
03073 {
03074 std::string s = q->first;
03075
03076 if (prefix == "axes" && (s == "position" || s == "units"))
03077 new_defaults.set (prefix + s, q->second);
03078 else if (prefix == "figure" && (s == "position" || s == "units"
03079 || s == "windowstyle"
03080 || s == "paperunits"))
03081 new_defaults.set (prefix + s, q->second);
03082 }
03083 }
03084
03085 default_properties = new_defaults;
03086 }
03087
03088 void
03089 root_figure::reset_default_properties (void)
03090 {
03091 ::reset_default_properties (default_properties);
03092 }
03093
03094
03095
03096 void
03097 figure::properties::set_currentaxes (const octave_value& v)
03098 {
03099 graphics_handle val (v);
03100
03101 if (error_state)
03102 return;
03103
03104 if (xisnan (val.value ()) || is_handle (val))
03105 currentaxes = val;
03106 else
03107 gripe_set_invalid ("currentaxes");
03108 }
03109
03110 void
03111 figure::properties::remove_child (const graphics_handle& gh)
03112 {
03113 base_properties::remove_child (gh);
03114
03115 if (gh == currentaxes.handle_value ())
03116 {
03117 graphics_handle new_currentaxes;
03118
03119 Matrix kids = get_children ();
03120
03121 for (octave_idx_type i = 0; i < kids.numel (); i++)
03122 {
03123 graphics_handle kid = kids(i);
03124
03125 graphics_object go = gh_manager::get_object (kid);
03126
03127 if (go.isa ("axes"))
03128 {
03129 new_currentaxes = kid;
03130 break;
03131 }
03132 }
03133
03134 currentaxes = new_currentaxes;
03135 }
03136 }
03137
03138 void
03139 figure::properties::set_visible (const octave_value& val)
03140 {
03141 std::string s = val.string_value ();
03142
03143 if (! error_state)
03144 {
03145 if (s == "on")
03146 xset (0, "currentfigure", __myhandle__.value ());
03147
03148 visible = val;
03149 }
03150 }
03151
03152 Matrix
03153 figure::properties::get_boundingbox (bool internal, const Matrix&) const
03154 {
03155 Matrix screen_size = screen_size_pixels ();
03156 Matrix pos = (internal ?
03157 get_position ().matrix_value () :
03158 get_outerposition ().matrix_value ());
03159
03160 pos = convert_position (pos, get_units (), "pixels", screen_size);
03161
03162 pos(0)--;
03163 pos(1)--;
03164 pos(1) = screen_size(1) - pos(1) - pos(3);
03165
03166 return pos;
03167 }
03168
03169 void
03170 figure::properties::set_boundingbox (const Matrix& bb, bool internal,
03171 bool do_notify_toolkit)
03172 {
03173 Matrix screen_size = screen_size_pixels ();
03174 Matrix pos = bb;
03175
03176 pos(1) = screen_size(1) - pos(1) - pos(3);
03177 pos(1)++;
03178 pos(0)++;
03179 pos = convert_position (pos, "pixels", get_units (), screen_size);
03180
03181 if (internal)
03182 set_position (pos, do_notify_toolkit);
03183 else
03184 set_outerposition (pos, do_notify_toolkit);
03185 }
03186
03187 Matrix
03188 figure::properties::map_from_boundingbox (double x, double y) const
03189 {
03190 Matrix bb = get_boundingbox (true);
03191 Matrix pos (1, 2, 0);
03192
03193 pos(0) = x;
03194 pos(1) = y;
03195
03196 pos(1) = bb(3) - pos(1);
03197 pos(0)++;
03198 pos = convert_position (pos, "pixels", get_units (),
03199 bb.extract_n (0, 2, 1, 2));
03200
03201 return pos;
03202 }
03203
03204 Matrix
03205 figure::properties::map_to_boundingbox (double x, double y) const
03206 {
03207 Matrix bb = get_boundingbox (true);
03208 Matrix pos (1, 2, 0);
03209
03210 pos(0) = x;
03211 pos(1) = y;
03212
03213 pos = convert_position (pos, get_units (), "pixels",
03214 bb.extract_n (0, 2, 1, 2));
03215 pos(0)--;
03216 pos(1) = bb(3) - pos(1);
03217
03218 return pos;
03219 }
03220
03221 void
03222 figure::properties::set_position (const octave_value& v,
03223 bool do_notify_toolkit)
03224 {
03225 if (! error_state)
03226 {
03227 Matrix old_bb, new_bb;
03228
03229 old_bb = get_boundingbox ();
03230 position.set (v, true, do_notify_toolkit);
03231 new_bb = get_boundingbox ();
03232
03233 if (old_bb != new_bb)
03234 {
03235 if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
03236 {
03237 execute_resizefcn ();
03238 update_boundingbox ();
03239 }
03240 }
03241
03242 mark_modified ();
03243 }
03244 }
03245
03246 void
03247 figure::properties::set_outerposition (const octave_value& v,
03248 bool do_notify_toolkit)
03249 {
03250 if (! error_state)
03251 {
03252 if (outerposition.set (v, true, do_notify_toolkit))
03253 {
03254 mark_modified ();
03255 }
03256 }
03257 }
03258
03259 void
03260 figure::properties::set_paperunits (const octave_value& v)
03261 {
03262 if (! error_state)
03263 {
03264 caseless_str typ = get_papertype ();
03265 caseless_str punits = v.string_value ();
03266 if (! error_state)
03267 {
03268 if (punits.compare ("normalized") && typ.compare ("<custom>"))
03269 error ("set: can't set the paperunits to normalized when the papertype is custom");
03270 else
03271 {
03272 caseless_str old_paperunits = get_paperunits ();
03273 if (paperunits.set (v, true))
03274 {
03275 update_paperunits (old_paperunits);
03276 mark_modified ();
03277 }
03278 }
03279 }
03280 }
03281 }
03282
03283 void
03284 figure::properties::set_papertype (const octave_value& v)
03285 {
03286 if (! error_state)
03287 {
03288 caseless_str typ = v.string_value ();
03289 caseless_str punits = get_paperunits ();
03290 if (! error_state)
03291 {
03292 if (punits.compare ("normalized") && typ.compare ("<custom>"))
03293 error ("set: can't set the paperunits to normalized when the papertype is custom");
03294 else
03295 {
03296 if (papertype.set (v, true))
03297 {
03298 update_papertype ();
03299 mark_modified ();
03300 }
03301 }
03302 }
03303 }
03304 }
03305
03306 static Matrix
03307 papersize_from_type (const caseless_str punits, const caseless_str typ)
03308 {
03309 Matrix ret (1, 2, 1.0);
03310
03311 if (! punits.compare ("normalized"))
03312 {
03313 double in2units;
03314 double mm2units;
03315
03316 if (punits.compare ("inches"))
03317 {
03318 in2units = 1.0;
03319 mm2units = 1 / 25.4 ;
03320 }
03321 else if (punits.compare ("centimeters"))
03322 {
03323 in2units = 2.54;
03324 mm2units = 1 / 10.0;
03325 }
03326 else
03327 {
03328 in2units = 72.0;
03329 mm2units = 72.0 / 25.4;
03330 }
03331
03332 if (typ.compare ("usletter"))
03333 {
03334 ret (0) = 8.5 * in2units;
03335 ret (1) = 11.0 * in2units;
03336 }
03337 else if (typ.compare ("uslegal"))
03338 {
03339 ret (0) = 8.5 * in2units;
03340 ret (1) = 14.0 * in2units;
03341 }
03342 else if (typ.compare ("tabloid"))
03343 {
03344 ret (0) = 11.0 * in2units;
03345 ret (1) = 17.0 * in2units;
03346 }
03347 else if (typ.compare ("a0"))
03348 {
03349 ret (0) = 841.0 * mm2units;
03350 ret (1) = 1189.0 * mm2units;
03351 }
03352 else if (typ.compare ("a1"))
03353 {
03354 ret (0) = 594.0 * mm2units;
03355 ret (1) = 841.0 * mm2units;
03356 }
03357 else if (typ.compare ("a2"))
03358 {
03359 ret (0) = 420.0 * mm2units;
03360 ret (1) = 594.0 * mm2units;
03361 }
03362 else if (typ.compare ("a3"))
03363 {
03364 ret (0) = 297.0 * mm2units;
03365 ret (1) = 420.0 * mm2units;
03366 }
03367 else if (typ.compare ("a4"))
03368 {
03369 ret (0) = 210.0 * mm2units;
03370 ret (1) = 297.0 * mm2units;
03371 }
03372 else if (typ.compare ("a5"))
03373 {
03374 ret (0) = 148.0 * mm2units;
03375 ret (1) = 210.0 * mm2units;
03376 }
03377 else if (typ.compare ("b0"))
03378 {
03379 ret (0) = 1029.0 * mm2units;
03380 ret (1) = 1456.0 * mm2units;
03381 }
03382 else if (typ.compare ("b1"))
03383 {
03384 ret (0) = 728.0 * mm2units;
03385 ret (1) = 1028.0 * mm2units;
03386 }
03387 else if (typ.compare ("b2"))
03388 {
03389 ret (0) = 514.0 * mm2units;
03390 ret (1) = 728.0 * mm2units;
03391 }
03392 else if (typ.compare ("b3"))
03393 {
03394 ret (0) = 364.0 * mm2units;
03395 ret (1) = 514.0 * mm2units;
03396 }
03397 else if (typ.compare ("b4"))
03398 {
03399 ret (0) = 257.0 * mm2units;
03400 ret (1) = 364.0 * mm2units;
03401 }
03402 else if (typ.compare ("b5"))
03403 {
03404 ret (0) = 182.0 * mm2units;
03405 ret (1) = 257.0 * mm2units;
03406 }
03407 else if (typ.compare ("arch-a"))
03408 {
03409 ret (0) = 9.0 * in2units;
03410 ret (1) = 12.0 * in2units;
03411 }
03412 else if (typ.compare ("arch-b"))
03413 {
03414 ret (0) = 12.0 * in2units;
03415 ret (1) = 18.0 * in2units;
03416 }
03417 else if (typ.compare ("arch-c"))
03418 {
03419 ret (0) = 18.0 * in2units;
03420 ret (1) = 24.0 * in2units;
03421 }
03422 else if (typ.compare ("arch-d"))
03423 {
03424 ret (0) = 24.0 * in2units;
03425 ret (1) = 36.0 * in2units;
03426 }
03427 else if (typ.compare ("arch-e"))
03428 {
03429 ret (0) = 36.0 * in2units;
03430 ret (1) = 48.0 * in2units;
03431 }
03432 else if (typ.compare ("a"))
03433 {
03434 ret (0) = 8.5 * in2units;
03435 ret (1) = 11.0 * in2units;
03436 }
03437 else if (typ.compare ("b"))
03438 {
03439 ret (0) = 11.0 * in2units;
03440 ret (1) = 17.0 * in2units;
03441 }
03442 else if (typ.compare ("c"))
03443 {
03444 ret (0) = 17.0 * in2units;
03445 ret (1) = 22.0 * in2units;
03446 }
03447 else if (typ.compare ("d"))
03448 {
03449 ret (0) = 22.0 * in2units;
03450 ret (1) = 34.0 * in2units;
03451 }
03452 else if (typ.compare ("e"))
03453 {
03454 ret (0) = 34.0 * in2units;
03455 ret (1) = 43.0 * in2units;
03456 }
03457 }
03458
03459 return ret;
03460 }
03461
03462 void
03463 figure::properties::update_paperunits (const caseless_str& old_paperunits)
03464 {
03465 Matrix pos = get_paperposition ().matrix_value ();
03466 Matrix sz = get_papersize ().matrix_value ();
03467
03468 pos (0) = pos (0) / sz(0);
03469 pos (1) = pos (1) / sz(1);
03470 pos (2) = pos (2) / sz(0);
03471 pos (3) = pos (3) / sz(1);
03472
03473 caseless_str punits = get_paperunits ();
03474 caseless_str typ = get_papertype ();
03475
03476 if (typ.compare ("<custom>"))
03477 {
03478 if (old_paperunits.compare ("centimeters"))
03479 {
03480 sz (0) = sz (0) / 2.54;
03481 sz (1) = sz (1) / 2.54;
03482 }
03483 else if (old_paperunits.compare ("points"))
03484 {
03485 sz (0) = sz (0) / 72.0;
03486 sz (1) = sz (1) / 72.0;
03487 }
03488
03489 if (punits.compare ("centimeters"))
03490 {
03491 sz(0) = sz(0) * 2.54;
03492 sz(1) = sz(1) * 2.54;
03493 }
03494 else if (old_paperunits.compare ("points"))
03495 {
03496 sz (0) = sz (0) * 72.0;
03497 sz (1) = sz (1) * 72.0;
03498 }
03499 }
03500 else
03501 sz = papersize_from_type (punits, typ);
03502
03503 pos (0) = pos (0) * sz(0);
03504 pos (1) = pos (1) * sz(1);
03505 pos (2) = pos (2) * sz(0);
03506 pos (3) = pos (3) * sz(1);
03507
03508 papersize.set (octave_value (sz));
03509 paperposition.set (octave_value (pos));
03510 }
03511
03512 void
03513 figure::properties::update_papertype (void)
03514 {
03515 caseless_str typ = get_papertype ();
03516
03517 if (! typ.compare ("<custom>"))
03518
03519
03520 papersize.set (octave_value (papersize_from_type (get_paperunits (), typ)));
03521 }
03522
03523 void
03524 figure::properties::update_papersize (void)
03525 {
03526 papertype.set ("<custom>");
03527 }
03528
03529 void
03530 figure::properties::set_units (const octave_value& v)
03531 {
03532 if (! error_state)
03533 {
03534 caseless_str old_units = get_units ();
03535 if (units.set (v, true))
03536 {
03537 update_units (old_units);
03538 mark_modified ();
03539 }
03540 }
03541 }
03542
03543 void
03544 figure::properties::update_units (const caseless_str& old_units)
03545 {
03546 set_position (convert_position (get_position ().matrix_value (), old_units,
03547 get_units (), screen_size_pixels ()));
03548 }
03549
03550 std::string
03551 figure::properties::get_title (void) const
03552 {
03553 if (is_numbertitle ())
03554 {
03555 std::ostringstream os;
03556 std::string nm = get_name ();
03557
03558 os << "Figure " << __myhandle__.value ();
03559 if (! nm.empty ())
03560 os << ": " << get_name ();
03561
03562 return os.str ();
03563 }
03564 else
03565 return get_name ();
03566 }
03567
03568 octave_value
03569 figure::get_default (const caseless_str& name) const
03570 {
03571 octave_value retval = default_properties.lookup (name);
03572
03573 if (retval.is_undefined ())
03574 {
03575 graphics_handle parent = get_parent ();
03576 graphics_object parent_obj = gh_manager::get_object (parent);
03577
03578 retval = parent_obj.get_default (name);
03579 }
03580
03581 return retval;
03582 }
03583
03584 void
03585 figure::reset_default_properties (void)
03586 {
03587 ::reset_default_properties (default_properties);
03588 }
03589
03590
03591
03592 void
03593 axes::properties::init (void)
03594 {
03595 position.add_constraint (dim_vector (1, 4));
03596 position.add_constraint (dim_vector (0, 0));
03597 outerposition.add_constraint (dim_vector (1, 4));
03598 colororder.add_constraint (dim_vector (-1, 3));
03599 dataaspectratio.add_constraint (dim_vector (1, 3));
03600 plotboxaspectratio.add_constraint (dim_vector (1, 3));
03601 xlim.add_constraint (2);
03602 ylim.add_constraint (2);
03603 zlim.add_constraint (2);
03604 clim.add_constraint (2);
03605 alim.add_constraint (2);
03606 xtick.add_constraint (dim_vector (1, -1));
03607 ytick.add_constraint (dim_vector (1, -1));
03608 ztick.add_constraint (dim_vector (1, -1));
03609 Matrix vw (1, 2, 0);
03610 vw(1) = 90;
03611 view = vw;
03612 view.add_constraint (dim_vector (1, 2));
03613 cameraposition.add_constraint (dim_vector (1, 3));
03614 Matrix upv (1, 3, 0.0);
03615 upv(2) = 1.0;
03616 cameraupvector = upv;
03617 cameraupvector.add_constraint (dim_vector (1, 3));
03618 currentpoint.add_constraint (dim_vector (2, 3));
03619 ticklength.add_constraint (dim_vector (1, 2));
03620 tightinset.add_constraint (dim_vector (1, 4));
03621 looseinset.add_constraint (dim_vector (1, 4));
03622 update_font ();
03623
03624 x_zlim.resize (1, 2);
03625
03626 sx = "linear";
03627 sy = "linear";
03628 sz = "linear";
03629
03630 calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
03631 calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
03632 calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
03633
03634 xset (xlabel.handle_value (), "handlevisibility", "off");
03635 xset (ylabel.handle_value (), "handlevisibility", "off");
03636 xset (zlabel.handle_value (), "handlevisibility", "off");
03637 xset (title.handle_value (), "handlevisibility", "off");
03638
03639 xset (xlabel.handle_value (), "horizontalalignment", "center");
03640 xset (xlabel.handle_value (), "horizontalalignmentmode", "auto");
03641 xset (ylabel.handle_value (), "horizontalalignment", "center");
03642 xset (ylabel.handle_value (), "horizontalalignmentmode", "auto");
03643 xset (zlabel.handle_value (), "horizontalalignment", "right");
03644 xset (zlabel.handle_value (), "horizontalalignmentmode", "auto");
03645 xset (title.handle_value (), "horizontalalignment", "center");
03646 xset (title.handle_value (), "horizontalalignmentmode", "auto");
03647
03648 xset (xlabel.handle_value (), "verticalalignment", "cap");
03649 xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
03650 xset (ylabel.handle_value (), "verticalalignment", "bottom");
03651 xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
03652 xset (title.handle_value (), "verticalalignment", "bottom");
03653 xset (title.handle_value (), "verticalalignmentmode", "auto");
03654
03655 xset (ylabel.handle_value (), "rotation", 90.0);
03656 xset (ylabel.handle_value (), "rotationmode", "auto");
03657
03658 xset (zlabel.handle_value (), "visible", "off");
03659
03660 xset (xlabel.handle_value (), "clipping", "off");
03661 xset (ylabel.handle_value (), "clipping", "off");
03662 xset (zlabel.handle_value (), "clipping", "off");
03663 xset (title.handle_value (), "clipping", "off");
03664
03665 xset (xlabel.handle_value (), "autopos_tag", "xlabel");
03666 xset (ylabel.handle_value (), "autopos_tag", "ylabel");
03667 xset (zlabel.handle_value (), "autopos_tag", "zlabel");
03668 xset (title.handle_value (), "autopos_tag", "title");
03669
03670 adopt (xlabel.handle_value ());
03671 adopt (ylabel.handle_value ());
03672 adopt (zlabel.handle_value ());
03673 adopt (title.handle_value ());
03674
03675 Matrix tlooseinset = default_axes_position ();
03676 tlooseinset(2) = 1-tlooseinset(0)-tlooseinset(2);
03677 tlooseinset(3) = 1-tlooseinset(1)-tlooseinset(3);
03678 looseinset = tlooseinset;
03679 }
03680
03681 Matrix
03682 axes::properties::calc_tightbox (const Matrix& init_pos)
03683 {
03684 Matrix pos = init_pos;
03685 graphics_object obj = gh_manager::get_object (get_parent ());
03686 Matrix parent_bb = obj.get_properties ().get_boundingbox (true);
03687 Matrix ext = get_extent (true, true);
03688 ext(1) = parent_bb(3) - ext(1) - ext(3);
03689 ext(0)++;
03690 ext(1)++;
03691 ext = convert_position (ext, "pixels", get_units (),
03692 parent_bb.extract_n (0, 2, 1, 2));
03693 if (ext(0) < pos(0))
03694 {
03695 pos(2) += pos(0)-ext(0);
03696 pos(0) = ext(0);
03697 }
03698 if (ext(0)+ext(2) > pos(0)+pos(2))
03699 pos(2) = ext(0)+ext(2)-pos(0);
03700
03701 if (ext(1) < pos(1))
03702 {
03703 pos(3) += pos(1)-ext(1);
03704 pos(1) = ext(1);
03705 }
03706 if (ext(1)+ext(3) > pos(1)+pos(3))
03707 pos(3) = ext(1)+ext(3)-pos(1);
03708 return pos;
03709 }
03710
03711 void
03712 axes::properties::sync_positions (void)
03713 {
03714 Matrix ref_linset = looseinset.get ().matrix_value ();
03715 if (autopos_tag_is ("subplot"))
03716 {
03717 graphics_object parent_obj = gh_manager::get_object (get_parent ());
03718 if (parent_obj.isa ("figure"))
03719 {
03720
03721
03722 std::string fig_units = parent_obj.get ("units").string_value ();
03723 parent_obj.set ("units", "pixels");
03724
03725 Matrix ref_outbox = outerposition.get ().matrix_value ();
03726 ref_outbox(2) += ref_outbox(0);
03727 ref_outbox(3) += ref_outbox(1);
03728
03729
03730
03731 Matrix kids = parent_obj.get_properties ().get_children ();
03732 std::vector<octave_value> aligned;
03733 std::vector<bool> l_aligned, b_aligned, r_aligned, t_aligned;
03734 for (octave_idx_type i = 0; i < kids.numel (); i++)
03735 {
03736 graphics_object go = gh_manager::get_object (kids(i));
03737 if (go.isa ("axes"))
03738 {
03739 axes::properties& props =
03740 dynamic_cast<axes::properties&> (go.get_properties ());
03741 if (props.autopos_tag_is("subplot"))
03742 {
03743 Matrix outpos = go.get ("outerposition").matrix_value ();
03744 bool l_align=(std::abs (outpos(0)-ref_outbox(0)) < 1e-15);
03745 bool b_align=(std::abs (outpos(1)-ref_outbox(1)) < 1e-15);
03746 bool r_align=(std::abs (outpos(0)+outpos(2)-ref_outbox(2)) < 1e-15);
03747 bool t_align=(std::abs (outpos(1)+outpos(3)-ref_outbox(3)) < 1e-15);
03748 if (l_align || b_align || r_align || t_align)
03749 {
03750 aligned.push_back(kids(i));
03751 l_aligned.push_back(l_align);
03752 b_aligned.push_back(b_align);
03753 r_aligned.push_back(r_align);
03754 t_aligned.push_back(t_align);
03755
03756
03757 props.set_autopos_tag ("none");
03758 }
03759 }
03760 }
03761 }
03762
03763 Matrix ref_box(1, 4, 0.);
03764 ref_box(2) = 1.;
03765 ref_box(3) = 1.;
03766 for (size_t i = 0; i < aligned.size (); i++)
03767 {
03768 graphics_object go = gh_manager::get_object (aligned[i]);
03769 axes::properties& props =
03770 dynamic_cast<axes::properties&> (go.get_properties ());
03771 Matrix linset = props.get_looseinset ().matrix_value ();
03772 if (l_aligned[i])
03773 linset(0) = std::min (0., linset(0)-0.01);
03774 if (b_aligned[i])
03775 linset(1) = std::min (0., linset(1)-0.01);
03776 if (r_aligned[i])
03777 linset(2) = std::min (0., linset(2)-0.01);
03778 if (t_aligned[i])
03779 linset(3) = std::min (0., linset(3)-0.01);
03780 props.set_looseinset (linset);
03781 Matrix pos = props.get_position ().matrix_value ();
03782 if (l_aligned[i])
03783 ref_box(0) = std::max (ref_box(0), pos(0));
03784 if (b_aligned[i])
03785 ref_box(1) = std::max (ref_box(1), pos(1));
03786 if (r_aligned[i])
03787 ref_box(2) = std::min (ref_box(2), pos(0)+pos(2));
03788 if (t_aligned[i])
03789 ref_box(3) = std::min (ref_box(3), pos(1)+pos(3));
03790 }
03791
03792
03793 for (size_t i = 0; i < aligned.size (); i++)
03794 {
03795 graphics_object go = gh_manager::get_object (aligned[i]);
03796 axes::properties& props =
03797 dynamic_cast<axes::properties&> (go.get_properties ());
03798 Matrix outpos = props.get_outerposition ().matrix_value ();
03799 Matrix linset = props.get_looseinset ().matrix_value ();
03800 if (l_aligned[i])
03801 linset(0) = (ref_box(0)-outpos(0))/outpos(2);
03802 if (b_aligned[i])
03803 linset(1) = (ref_box(1)-outpos(1))/outpos(3);
03804 if (r_aligned[i])
03805 linset(2) = (outpos(0)+outpos(2)-ref_box(2))/outpos(2);
03806 if (t_aligned[i])
03807 linset(3) = (outpos(1)+outpos(3)-ref_box(3))/outpos(3);
03808 props.set_looseinset (linset);
03809 props.set_autopos_tag ("subplot");
03810 }
03811 parent_obj.set ("units", fig_units);
03812 }
03813 }
03814 else
03815 sync_positions (ref_linset);
03816 }
03817
03818 void
03819 axes::properties::sync_positions (const Matrix& linset)
03820 {
03821 Matrix pos = position.get ().matrix_value ();
03822 Matrix outpos = outerposition.get ().matrix_value ();
03823 double lratio = linset(0);
03824 double bratio = linset(1);
03825 double wratio = 1-linset(0)-linset(2);
03826 double hratio = 1-linset(1)-linset(3);
03827 if (activepositionproperty.is ("outerposition"))
03828 {
03829 pos = outpos;
03830 pos(0) = outpos(0)+lratio*outpos(2);
03831 pos(1) = outpos(1)+bratio*outpos(3);
03832 pos(2) = wratio*outpos(2);
03833 pos(3) = hratio*outpos(3);
03834
03835 position = pos;
03836 update_transform ();
03837 Matrix tightpos = calc_tightbox (pos);
03838
03839 double thrshldx = 0.005*outpos(2);
03840 double thrshldy = 0.005*outpos(3);
03841 double minsizex = 0.2*outpos(2);
03842 double minsizey = 0.2*outpos(3);
03843 bool updatex = true, updatey = true;
03844 for (int i = 0; i < 10; i++)
03845 {
03846 double dt;
03847 bool modified = false;
03848 dt = outpos(0)+outpos(2)-tightpos(0)-tightpos(2);
03849 if (dt < -thrshldx && updatex)
03850 {
03851 pos(2) += dt;
03852 modified = true;
03853 }
03854 dt = outpos(1)+outpos(3)-tightpos(1)-tightpos(3);
03855 if (dt < -thrshldy && updatey)
03856 {
03857 pos(3) += dt;
03858 modified = true;
03859 }
03860 dt = outpos(0)-tightpos(0);
03861 if (dt > thrshldx && updatex)
03862 {
03863 pos(0) += dt;
03864 pos(2) -= dt;
03865 modified = true;
03866 }
03867 dt = outpos(1)-tightpos(1);
03868 if (dt > thrshldy && updatey)
03869 {
03870 pos(1) += dt;
03871 pos(3) -= dt;
03872 modified = true;
03873 }
03874
03875
03876 if (pos(2) < minsizex)
03877 {
03878 pos(0) -= 0.5*(minsizex-pos(2));
03879 pos(2) = minsizex;
03880 updatex = false;
03881 }
03882 if (pos(3) < minsizey)
03883 {
03884 pos(1) -= 0.5*(minsizey-pos(3));
03885 pos(3) = minsizey;
03886 updatey = false;
03887 }
03888
03889 if (modified)
03890 {
03891 position = pos;
03892 update_transform ();
03893 tightpos = calc_tightbox (pos);
03894 }
03895 else
03896 break;
03897 }
03898 }
03899 else
03900 {
03901 update_transform ();
03902
03903 outpos(0) = pos(0)-pos(2)*lratio/wratio;
03904 outpos(1) = pos(1)-pos(3)*bratio/hratio;
03905 outpos(2) = pos(2)/wratio;
03906 outpos(3) = pos(3)/hratio;
03907
03908 outerposition = calc_tightbox (outpos);
03909 }
03910
03911 Matrix inset (1, 4, 1.0);
03912 inset(0) = pos(0)-outpos(0);
03913 inset(1) = pos(1)-outpos(1);
03914 inset(2) = outpos(0)+outpos(2)-pos(0)-pos(2);
03915 inset(3) = outpos(1)+outpos(3)-pos(1)-pos(3);
03916
03917 tightinset = inset;
03918 }
03919
03920 void
03921 axes::properties::set_text_child (handle_property& hp,
03922 const std::string& who,
03923 const octave_value& v)
03924 {
03925 graphics_handle val;
03926
03927 if (v.is_string ())
03928 {
03929 val = gh_manager::make_graphics_handle ("text", __myhandle__,
03930 false, false);
03931
03932 xset (val, "string", v);
03933 }
03934 else
03935 {
03936 graphics_object go = gh_manager::get_object (gh_manager::lookup (v));
03937
03938 if (go.isa ("text"))
03939 val = ::reparent (v, "set", who, __myhandle__, false);
03940 else
03941 {
03942 std::string cname = v.class_name ();
03943
03944 error ("set: expecting text graphics object or character string for %s property, found %s",
03945 who.c_str (), cname.c_str ());
03946 }
03947 }
03948
03949 if (! error_state)
03950 {
03951 xset (val, "handlevisibility", "off");
03952
03953 gh_manager::free (hp.handle_value ());
03954
03955 base_properties::remove_child (hp.handle_value ());
03956
03957 hp = val;
03958
03959 adopt (hp.handle_value ());
03960 }
03961 }
03962
03963 void
03964 axes::properties::set_xlabel (const octave_value& v)
03965 {
03966 set_text_child (xlabel, "xlabel", v);
03967 xset (xlabel.handle_value (), "positionmode", "auto");
03968 xset (xlabel.handle_value (), "rotationmode", "auto");
03969 xset (xlabel.handle_value (), "horizontalalignmentmode", "auto");
03970 xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
03971 xset (xlabel.handle_value (), "clipping", "off");
03972 xset (xlabel.handle_value (), "color", get_xcolor ());
03973 xset (xlabel.handle_value (), "autopos_tag", "xlabel");
03974 update_xlabel_position ();
03975 }
03976
03977 void
03978 axes::properties::set_ylabel (const octave_value& v)
03979 {
03980 set_text_child (ylabel, "ylabel", v);
03981 xset (ylabel.handle_value (), "positionmode", "auto");
03982 xset (ylabel.handle_value (), "rotationmode", "auto");
03983 xset (ylabel.handle_value (), "horizontalalignmentmode", "auto");
03984 xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
03985 xset (ylabel.handle_value (), "clipping", "off");
03986 xset (ylabel.handle_value (), "color", get_ycolor ());
03987 xset (ylabel.handle_value (), "autopos_tag", "ylabel");
03988 update_ylabel_position ();
03989 }
03990
03991 void
03992 axes::properties::set_zlabel (const octave_value& v)
03993 {
03994 set_text_child (zlabel, "zlabel", v);
03995 xset (zlabel.handle_value (), "positionmode", "auto");
03996 xset (zlabel.handle_value (), "rotationmode", "auto");
03997 xset (zlabel.handle_value (), "horizontalalignmentmode", "auto");
03998 xset (zlabel.handle_value (), "verticalalignmentmode", "auto");
03999 xset (zlabel.handle_value (), "clipping", "off");
04000 xset (zlabel.handle_value (), "color", get_zcolor ());
04001 xset (zlabel.handle_value (), "autopos_tag", "zlabel");
04002 update_zlabel_position ();
04003 }
04004
04005 void
04006 axes::properties::set_title (const octave_value& v)
04007 {
04008 set_text_child (title, "title", v);
04009 xset (title.handle_value (), "positionmode", "auto");
04010 xset (title.handle_value (), "horizontalalignment", "center");
04011 xset (title.handle_value (), "horizontalalignmentmode", "auto");
04012 xset (title.handle_value (), "verticalalignment", "bottom");
04013 xset (title.handle_value (), "verticalalignmentmode", "auto");
04014 xset (title.handle_value (), "clipping", "off");
04015 xset (title.handle_value (), "autopos_tag", "title");
04016 update_title_position ();
04017 }
04018
04019 void
04020 axes::properties::set_defaults (base_graphics_object& obj,
04021 const std::string& mode)
04022 {
04023 box = "on";
04024 colororder = default_colororder ();
04025 dataaspectratio = Matrix (1, 3, 1.0);
04026 dataaspectratiomode = "auto";
04027 layer = "bottom";
04028
04029 Matrix tlim (1, 2, 0.0);
04030 tlim(1) = 1;
04031 xlim = tlim;
04032 ylim = tlim;
04033 zlim = tlim;
04034
04035 Matrix cl (1, 2, 0);
04036 cl(1) = 1;
04037 clim = cl;
04038
04039 xlimmode = "auto";
04040 ylimmode = "auto";
04041 zlimmode = "auto";
04042 climmode = "auto";
04043
04044 xgrid = "off";
04045 ygrid = "off";
04046 zgrid = "off";
04047 xminorgrid = "off";
04048 yminorgrid = "off";
04049 zminorgrid = "off";
04050 xtick = Matrix ();
04051 ytick = Matrix ();
04052 ztick = Matrix ();
04053 xtickmode = "auto";
04054 ytickmode = "auto";
04055 ztickmode = "auto";
04056 xticklabel = "";
04057 yticklabel = "";
04058 zticklabel = "";
04059 xticklabelmode = "auto";
04060 yticklabelmode = "auto";
04061 zticklabelmode = "auto";
04062 color = "none";
04063 xcolor = color_values ("black");
04064 ycolor = color_values ("black");
04065 zcolor = color_values ("black");
04066 xscale = "linear";
04067 yscale = "linear";
04068 zscale = "linear";
04069 xdir = "normal";
04070 ydir = "normal";
04071 zdir = "normal";
04072 yaxislocation = "left";
04073 xaxislocation = "bottom";
04074
04075
04076 camerapositionmode = "auto";
04077 cameratargetmode = "auto";
04078 cameraupvectormode = "auto";
04079 cameraviewanglemode = "auto";
04080 plotboxaspectratio = Matrix (1, 3, 1.0);
04081 drawmode = "normal";
04082 gridlinestyle = ":";
04083 linestyleorder = "-";
04084 linewidth = 0.5;
04085 minorgridlinestyle = ":";
04086
04087 plotboxaspectratiomode = "auto";
04088 projection = "orthographic";
04089 tickdir = "in";
04090 tickdirmode = "auto";
04091 ticklength = default_axes_ticklength ();
04092 tightinset = Matrix (1, 4, 0.0);
04093
04094 sx = "linear";
04095 sy = "linear";
04096 sz = "linear";
04097
04098 Matrix tview (1, 2, 0.0);
04099 tview(1) = 90;
04100 view = tview;
04101
04102 visible = "on";
04103 nextplot = "replace";
04104
04105 if (mode != "replace")
04106 {
04107 fontangle = "normal";
04108 fontname = OCTAVE_DEFAULT_FONTNAME;
04109 fontsize = 10;
04110 fontunits = "points";
04111 fontweight = "normal";
04112
04113 Matrix touterposition (1, 4, 0.0);
04114 touterposition(2) = 1;
04115 touterposition(3) = 1;
04116 outerposition = touterposition;
04117
04118 position = default_axes_position ();
04119
04120 Matrix tlooseinset = default_axes_position ();
04121 tlooseinset(2) = 1-tlooseinset(0)-tlooseinset(2);
04122 tlooseinset(3) = 1-tlooseinset(1)-tlooseinset(3);
04123 looseinset = tlooseinset;
04124
04125 activepositionproperty = "outerposition";
04126 }
04127
04128 delete_children (true);
04129
04130 xlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
04131 false, false);
04132
04133 ylabel = gh_manager::make_graphics_handle ("text", __myhandle__,
04134 false, false);
04135
04136 zlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
04137 false, false);
04138
04139 title = gh_manager::make_graphics_handle ("text", __myhandle__,
04140 false, false);
04141
04142 xset (xlabel.handle_value (), "handlevisibility", "off");
04143 xset (ylabel.handle_value (), "handlevisibility", "off");
04144 xset (zlabel.handle_value (), "handlevisibility", "off");
04145 xset (title.handle_value (), "handlevisibility", "off");
04146
04147 xset (xlabel.handle_value (), "horizontalalignment", "center");
04148 xset (xlabel.handle_value (), "horizontalalignmentmode", "auto");
04149 xset (ylabel.handle_value (), "horizontalalignment", "center");
04150 xset (ylabel.handle_value (), "horizontalalignmentmode", "auto");
04151 xset (zlabel.handle_value (), "horizontalalignment", "right");
04152 xset (zlabel.handle_value (), "horizontalalignmentmode", "auto");
04153 xset (title.handle_value (), "horizontalalignment", "center");
04154 xset (title.handle_value (), "horizontalalignmentmode", "auto");
04155
04156 xset (xlabel.handle_value (), "verticalalignment", "cap");
04157 xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
04158 xset (ylabel.handle_value (), "verticalalignment", "bottom");
04159 xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
04160 xset (title.handle_value (), "verticalalignment", "bottom");
04161 xset (title.handle_value (), "verticalalignmentmode", "auto");
04162
04163 xset (ylabel.handle_value (), "rotation", 90.0);
04164 xset (ylabel.handle_value (), "rotationmode", "auto");
04165
04166 xset (zlabel.handle_value (), "visible", "off");
04167
04168 xset (xlabel.handle_value (), "clipping", "off");
04169 xset (ylabel.handle_value (), "clipping", "off");
04170 xset (zlabel.handle_value (), "clipping", "off");
04171 xset (title.handle_value (), "clipping", "off");
04172
04173 xset (xlabel.handle_value (), "autopos_tag", "xlabel");
04174 xset (ylabel.handle_value (), "autopos_tag", "ylabel");
04175 xset (zlabel.handle_value (), "autopos_tag", "zlabel");
04176 xset (title.handle_value (), "autopos_tag", "title");
04177
04178 adopt (xlabel.handle_value ());
04179 adopt (ylabel.handle_value ());
04180 adopt (zlabel.handle_value ());
04181 adopt (title.handle_value ());
04182
04183 update_transform ();
04184
04185 override_defaults (obj);
04186 }
04187
04188 void
04189 axes::properties::delete_text_child (handle_property& hp)
04190 {
04191 graphics_handle h = hp.handle_value ();
04192
04193 if (h.ok ())
04194 {
04195 graphics_object go = gh_manager::get_object (h);
04196
04197 if (go.valid_object ())
04198 gh_manager::free (h);
04199
04200 base_properties::remove_child (h);
04201 }
04202
04203
04204
04205
04206
04207
04208 if (! is_beingdeleted ())
04209 {
04210 hp = gh_manager::make_graphics_handle ("text", __myhandle__,
04211 false, false);
04212
04213 xset (hp.handle_value (), "handlevisibility", "off");
04214
04215 adopt (hp.handle_value ());
04216 }
04217 }
04218
04219 void
04220 axes::properties::remove_child (const graphics_handle& h)
04221 {
04222 if (xlabel.handle_value ().ok () && h == xlabel.handle_value ())
04223 delete_text_child (xlabel);
04224 else if (ylabel.handle_value ().ok () && h == ylabel.handle_value ())
04225 delete_text_child (ylabel);
04226 else if (zlabel.handle_value ().ok () && h == zlabel.handle_value ())
04227 delete_text_child (zlabel);
04228 else if (title.handle_value ().ok () && h == title.handle_value ())
04229 delete_text_child (title);
04230 else
04231 base_properties::remove_child (h);
04232 }
04233
04234 inline Matrix
04235 xform_matrix (void)
04236 {
04237 Matrix m (4, 4, 0.0);
04238 for (int i = 0; i < 4; i++)
04239 m(i,i) = 1;
04240 return m;
04241 }
04242
04243 inline ColumnVector
04244 xform_vector (void)
04245 {
04246 ColumnVector v (4, 0.0);
04247 v(3) = 1;
04248 return v;
04249 }
04250
04251 inline ColumnVector
04252 xform_vector (double x, double y, double z)
04253 {
04254 ColumnVector v (4, 1.0);
04255 v(0) = x; v(1) = y; v(2) = z;
04256 return v;
04257 }
04258
04259 inline ColumnVector
04260 transform (const Matrix& m, double x, double y, double z)
04261 {
04262 return (m * xform_vector (x, y, z));
04263 }
04264
04265 inline Matrix
04266 xform_scale (double x, double y, double z)
04267 {
04268 Matrix m (4, 4, 0.0);
04269 m(0,0) = x; m(1,1) = y; m(2,2) = z; m(3,3) = 1;
04270 return m;
04271 }
04272
04273 inline Matrix
04274 xform_translate (double x, double y, double z)
04275 {
04276 Matrix m = xform_matrix ();
04277 m(0,3) = x; m(1,3) = y; m(2,3) = z; m(3,3) = 1;
04278 return m;
04279 }
04280
04281 inline void
04282 scale (Matrix& m, double x, double y, double z)
04283 {
04284 m = m * xform_scale (x, y, z);
04285 }
04286
04287 inline void
04288 translate (Matrix& m, double x, double y, double z)
04289 {
04290 m = m * xform_translate (x, y, z);
04291 }
04292
04293 inline void
04294 xform (ColumnVector& v, const Matrix& m)
04295 {
04296 v = m*v;
04297 }
04298
04299 inline void
04300 scale (ColumnVector& v, double x, double y, double z)
04301 {
04302 v(0) *= x;
04303 v(1) *= y;
04304 v(2) *= z;
04305 }
04306
04307 inline void
04308 translate (ColumnVector& v, double x, double y, double z)
04309 {
04310 v(0) += x;
04311 v(1) += y;
04312 v(2) += z;
04313 }
04314
04315 inline void
04316 normalize (ColumnVector& v)
04317 {
04318 double fact = 1.0/sqrt(v(0)*v(0)+v(1)*v(1)+v(2)*v(2));
04319 scale (v, fact, fact, fact);
04320 }
04321
04322 inline double
04323 dot (const ColumnVector& v1, const ColumnVector& v2)
04324 {
04325 return (v1(0)*v2(0)+v1(1)*v2(1)+v1(2)*v2(2));
04326 }
04327
04328 inline double
04329 norm (const ColumnVector& v)
04330 {
04331 return sqrt (dot (v, v));
04332 }
04333
04334 inline ColumnVector
04335 cross (const ColumnVector& v1, const ColumnVector& v2)
04336 {
04337 ColumnVector r = xform_vector ();
04338 r(0) = v1(1)*v2(2)-v1(2)*v2(1);
04339 r(1) = v1(2)*v2(0)-v1(0)*v2(2);
04340 r(2) = v1(0)*v2(1)-v1(1)*v2(0);
04341 return r;
04342 }
04343
04344 inline Matrix
04345 unit_cube (void)
04346 {
04347 static double data[32] = {
04348 0,0,0,1,
04349 1,0,0,1,
04350 0,1,0,1,
04351 0,0,1,1,
04352 1,1,0,1,
04353 1,0,1,1,
04354 0,1,1,1,
04355 1,1,1,1};
04356 Matrix m (4, 8);
04357 memcpy (m.fortran_vec (), data, sizeof(double)*32);
04358 return m;
04359 }
04360
04361 inline ColumnVector
04362 cam2xform (const Array<double>& m)
04363 {
04364 ColumnVector retval (4, 1.0);
04365 memcpy (retval.fortran_vec (), m.fortran_vec (), sizeof(double)*3);
04366 return retval;
04367 }
04368
04369 inline RowVector
04370 xform2cam (const ColumnVector& v)
04371 {
04372 return v.extract_n (0, 3).transpose ();
04373 }
04374
04375 void
04376 axes::properties::update_camera (void)
04377 {
04378 double xd = (xdir_is ("normal") ? 1 : -1);
04379 double yd = (ydir_is ("normal") ? 1 : -1);
04380 double zd = (zdir_is ("normal") ? 1 : -1);
04381
04382 Matrix xlimits = sx.scale (get_xlim ().matrix_value ());
04383 Matrix ylimits = sy.scale (get_ylim ().matrix_value ());
04384 Matrix zlimits = sz.scale (get_zlim ().matrix_value ());
04385
04386 double xo = xlimits(xd > 0 ? 0 : 1);
04387 double yo = ylimits(yd > 0 ? 0 : 1);
04388 double zo = zlimits(zd > 0 ? 0 : 1);
04389
04390 Matrix pb = get_plotboxaspectratio ().matrix_value ();
04391
04392 bool autocam = (camerapositionmode_is ("auto")
04393 && cameratargetmode_is ("auto")
04394 && cameraupvectormode_is ("auto")
04395 && cameraviewanglemode_is ("auto"));
04396 bool dowarp = (autocam && dataaspectratiomode_is("auto")
04397 && plotboxaspectratiomode_is ("auto"));
04398
04399 ColumnVector c_eye (xform_vector ());
04400 ColumnVector c_center (xform_vector ());
04401 ColumnVector c_upv (xform_vector ());
04402
04403 if (cameratargetmode_is ("auto"))
04404 {
04405 c_center(0) = (xlimits(0)+xlimits(1))/2;
04406 c_center(1) = (ylimits(0)+ylimits(1))/2;
04407 c_center(2) = (zlimits(0)+zlimits(1))/2;
04408
04409 cameratarget = xform2cam (c_center);
04410 }
04411 else
04412 c_center = cam2xform (get_cameratarget ().matrix_value ());
04413
04414 if (camerapositionmode_is ("auto"))
04415 {
04416 Matrix tview = get_view ().matrix_value ();
04417 double az = tview(0), el = tview(1);
04418 double d = 5*sqrt(pb(0)*pb(0)+pb(1)*pb(1)+pb(2)*pb(2));
04419
04420 if (el == 90 || el == -90)
04421 c_eye(2) = d*signum(el);
04422 else
04423 {
04424 az *= M_PI/180.0;
04425 el *= M_PI/180.0;
04426 c_eye(0) = d*cos(el)*sin(az);
04427 c_eye(1) = -d*cos(el)*cos(az);
04428 c_eye(2) = d*sin(el);
04429 }
04430 c_eye(0) = c_eye(0)*(xlimits(1)-xlimits(0))/(xd*pb(0))+c_center(0);
04431 c_eye(1) = c_eye(1)*(ylimits(1)-ylimits(0))/(yd*pb(1))+c_center(1);
04432 c_eye(2) = c_eye(2)*(zlimits(1)-zlimits(0))/(zd*pb(2))+c_center(2);
04433
04434 cameraposition = xform2cam (c_eye);
04435 }
04436 else
04437 c_eye = cam2xform (get_cameraposition ().matrix_value ());
04438
04439 if (cameraupvectormode_is ("auto"))
04440 {
04441 Matrix tview = get_view ().matrix_value ();
04442 double az = tview(0), el = tview(1);
04443
04444 if (el == 90 || el == -90)
04445 {
04446 c_upv(0) =
04447 -signum(el)*sin(az*M_PI/180.0)*(xlimits(1)-xlimits(0))/pb(0);
04448 c_upv(1) =
04449 signum(el)*cos(az*M_PI/180.0)*(ylimits(1)-ylimits(0))/pb(1);
04450 }
04451 else
04452 c_upv(2) = 1;
04453
04454 cameraupvector = xform2cam (c_upv);
04455 }
04456 else
04457 c_upv = cam2xform (get_cameraupvector ().matrix_value ());
04458
04459 Matrix x_view = xform_matrix ();
04460 Matrix x_projection = xform_matrix ();
04461 Matrix x_viewport = xform_matrix ();
04462 Matrix x_normrender = xform_matrix ();
04463 Matrix x_pre = xform_matrix ();
04464
04465 x_render = xform_matrix ();
04466 x_render_inv = xform_matrix ();
04467
04468 scale (x_pre, pb(0), pb(1), pb(2));
04469 translate (x_pre, -0.5, -0.5, -0.5);
04470 scale (x_pre, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
04471 zd/(zlimits(1)-zlimits(0)));
04472 translate (x_pre, -xo, -yo, -zo);
04473
04474 xform (c_eye, x_pre);
04475 xform (c_center, x_pre);
04476 scale (c_upv, pb(0)/(xlimits(1)-xlimits(0)), pb(1)/(ylimits(1)-ylimits(0)),
04477 pb(2)/(zlimits(1)-zlimits(0)));
04478 translate (c_center, -c_eye(0), -c_eye(1), -c_eye(2));
04479
04480 ColumnVector F (c_center), f (F), UP (c_upv);
04481 normalize (f);
04482 normalize (UP);
04483
04484 if (std::abs (dot (f, UP)) > 1e-15)
04485 {
04486 double fa = 1/sqrt(1-f(2)*f(2));
04487 scale (UP, fa, fa, fa);
04488 }
04489
04490 ColumnVector s = cross (f, UP);
04491 ColumnVector u = cross (s, f);
04492
04493 scale (x_view, 1, 1, -1);
04494 Matrix l = xform_matrix ();
04495 l(0,0) = s(0); l(0,1) = s(1); l(0,2) = s(2);
04496 l(1,0) = u(0); l(1,1) = u(1); l(1,2) = u(2);
04497 l(2,0) = -f(0); l(2,1) = -f(1); l(2,2) = -f(2);
04498 x_view = x_view * l;
04499 translate (x_view, -c_eye(0), -c_eye(1), -c_eye(2));
04500 scale (x_view, pb(0), pb(1), pb(2));
04501 translate (x_view, -0.5, -0.5, -0.5);
04502
04503 Matrix x_cube = x_view * unit_cube ();
04504 ColumnVector cmin = x_cube.row_min (), cmax = x_cube.row_max ();
04505 double xM = cmax(0)-cmin(0);
04506 double yM = cmax(1)-cmin(1);
04507
04508 Matrix bb = get_boundingbox (true);
04509
04510 double v_angle;
04511
04512 if (cameraviewanglemode_is ("auto"))
04513 {
04514 double af;
04515
04516
04517
04518
04519 if (false && dowarp)
04520 af = 1.0 / (xM > yM ? xM : yM);
04521 else
04522 {
04523 if ((bb(2)/bb(3)) > (xM/yM))
04524 af = 1.0 / yM;
04525 else
04526 af = 1.0 / xM;
04527 }
04528 v_angle = 2 * (180.0 / M_PI) * atan (1 / (2 * af * norm (F)));
04529
04530 cameraviewangle = v_angle;
04531 }
04532 else
04533 v_angle = get_cameraviewangle ();
04534
04535 double pf = 1 / (2 * tan ((v_angle / 2) * M_PI / 180.0) * norm (F));
04536 scale (x_projection, pf, pf, 1);
04537
04538 if (dowarp)
04539 {
04540 xM *= pf;
04541 yM *= pf;
04542 translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
04543 scale (x_viewport, bb(2)/xM, -bb(3)/yM, 1);
04544 }
04545 else
04546 {
04547 double pix = 1;
04548 if (autocam)
04549 {
04550 if ((bb(2)/bb(3)) > (xM/yM))
04551 pix = bb(3);
04552 else
04553 pix = bb(2);
04554 }
04555 else
04556 pix = (bb(2) < bb(3) ? bb(2) : bb(3));
04557 translate (x_viewport, bb(0)+bb(2)/2, bb(1)+bb(3)/2, 0);
04558 scale (x_viewport, pix, -pix, 1);
04559 }
04560
04561 x_normrender = x_viewport * x_projection * x_view;
04562
04563 x_cube = x_normrender * unit_cube ();
04564 cmin = x_cube.row_min ();
04565 cmax = x_cube.row_max ();
04566 x_zlim.resize (1, 2);
04567 x_zlim(0) = cmin(2);
04568 x_zlim(1) = cmax(2);
04569
04570 x_render = x_normrender;
04571 scale (x_render, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
04572 zd/(zlimits(1)-zlimits(0)));
04573 translate (x_render, -xo, -yo, -zo);
04574
04575 x_viewtransform = x_view;
04576 x_projectiontransform = x_projection;
04577 x_viewporttransform = x_viewport;
04578 x_normrendertransform = x_normrender;
04579 x_rendertransform = x_render;
04580
04581 x_render_inv = x_render.inverse ();
04582
04583
04584
04585
04586 x_gl_mat1 = x_view;
04587 scale (x_gl_mat1, xd/(xlimits(1)-xlimits(0)), yd/(ylimits(1)-ylimits(0)),
04588 zd/(zlimits(1)-zlimits(0)));
04589 translate (x_gl_mat1, -xo, -yo, -zo);
04590 x_gl_mat2 = x_viewport * x_projection;
04591 }
04592
04593 static bool updating_axes_layout = false;
04594
04595 void
04596 axes::properties::update_axes_layout (void)
04597 {
04598 if (updating_axes_layout)
04599 return;
04600
04601 graphics_xform xform = get_transform ();
04602
04603 double xd = (xdir_is ("normal") ? 1 : -1);
04604 double yd = (ydir_is ("normal") ? 1 : -1);
04605 double zd = (zdir_is ("normal") ? 1 : -1);
04606
04607 const Matrix xlims = xform.xscale (get_xlim ().matrix_value ());
04608 const Matrix ylims = xform.yscale (get_ylim ().matrix_value ());
04609 const Matrix zlims = xform.zscale (get_zlim ().matrix_value ());
04610 double x_min = xlims(0), x_max = xlims(1);
04611 double y_min = ylims(0), y_max = ylims(1);
04612 double z_min = zlims(0), z_max = zlims(1);
04613
04614 ColumnVector p1, p2, dir (3);
04615
04616 xstate = ystate = zstate = AXE_ANY_DIR;
04617
04618 p1 = xform.transform (x_min, (y_min+y_max)/2, (z_min+z_max)/2, false);
04619 p2 = xform.transform (x_max, (y_min+y_max)/2, (z_min+z_max)/2, false);
04620 dir(0) = xround (p2(0)-p1(0));
04621 dir(1) = xround (p2(1)-p1(1));
04622 dir(2) = (p2(2)-p1(2));
04623 if (dir(0) == 0 && dir(1) == 0)
04624 xstate = AXE_DEPTH_DIR;
04625 else if (dir(2) == 0)
04626 {
04627 if (dir(0) == 0)
04628 xstate = AXE_VERT_DIR;
04629 else if (dir(1) == 0)
04630 xstate = AXE_HORZ_DIR;
04631 }
04632
04633 if (dir(2) == 0)
04634 {
04635 if (dir(1) == 0)
04636 xPlane = (dir(0) > 0 ? x_max : x_min);
04637 else
04638 xPlane = (dir(1) < 0 ? x_max : x_min);
04639 }
04640 else
04641 xPlane = (dir(2) < 0 ? x_min : x_max);
04642
04643 xPlaneN = (xPlane == x_min ? x_max : x_min);
04644 fx = (x_max-x_min)/sqrt(dir(0)*dir(0)+dir(1)*dir(1));
04645
04646 p1 = xform.transform ((x_min+x_max)/2, y_min, (z_min+z_max)/2, false);
04647 p2 = xform.transform ((x_min+x_max)/2, y_max, (z_min+z_max)/2, false);
04648 dir(0) = xround (p2(0)-p1(0));
04649 dir(1) = xround (p2(1)-p1(1));
04650 dir(2) = (p2(2)-p1(2));
04651 if (dir(0) == 0 && dir(1) == 0)
04652 ystate = AXE_DEPTH_DIR;
04653 else if (dir(2) == 0)
04654 {
04655 if (dir(0) == 0)
04656 ystate = AXE_VERT_DIR;
04657 else if (dir(1) == 0)
04658 ystate = AXE_HORZ_DIR;
04659 }
04660
04661 if (dir(2) == 0)
04662 {
04663 if (dir(1) == 0)
04664 yPlane = (dir(0) > 0 ? y_max : y_min);
04665 else
04666 yPlane = (dir(1) < 0 ? y_max : y_min);
04667 }
04668 else
04669 yPlane = (dir(2) < 0 ? y_min : y_max);
04670
04671 yPlaneN = (yPlane == y_min ? y_max : y_min);
04672 fy = (y_max-y_min)/sqrt(dir(0)*dir(0)+dir(1)*dir(1));
04673
04674 p1 = xform.transform((x_min+x_max)/2, (y_min+y_max)/2, z_min, false);
04675 p2 = xform.transform((x_min+x_max)/2, (y_min+y_max)/2, z_max, false);
04676 dir(0) = xround(p2(0)-p1(0));
04677 dir(1) = xround (p2(1)-p1(1));
04678 dir(2) = (p2(2)-p1(2));
04679 if (dir(0) == 0 && dir(1) == 0)
04680 zstate = AXE_DEPTH_DIR;
04681 else if (dir(2) == 0)
04682 {
04683 if (dir(0) == 0)
04684 zstate = AXE_VERT_DIR;
04685 else if (dir(1) == 0)
04686 zstate = AXE_HORZ_DIR;
04687 }
04688
04689 if (dir(2) == 0)
04690 {
04691 if (dir(1) == 0)
04692 zPlane = (dir(0) > 0 ? z_min : z_max);
04693 else
04694 zPlane = (dir(1) < 0 ? z_min : z_max);
04695 }
04696 else
04697 zPlane = (dir(2) < 0 ? z_min : z_max);
04698
04699 zPlaneN = (zPlane == z_min ? z_max : z_min);
04700 fz = (z_max-z_min)/sqrt(dir(0)*dir(0)+dir(1)*dir(1));
04701
04702 unwind_protect frame;
04703 frame.protect_var (updating_axes_layout);
04704 updating_axes_layout = true;
04705
04706 xySym = (xd*yd*(xPlane-xPlaneN)*(yPlane-yPlaneN) > 0);
04707 zSign = (zd*(zPlane-zPlaneN) <= 0);
04708 xyzSym = zSign ? xySym : !xySym;
04709 xpTick = (zSign ? xPlaneN : xPlane);
04710 ypTick = (zSign ? yPlaneN : yPlane);
04711 zpTick = (zSign ? zPlane : zPlaneN);
04712 xpTickN = (zSign ? xPlane : xPlaneN);
04713 ypTickN = (zSign ? yPlane : yPlaneN);
04714 zpTickN = (zSign ? zPlaneN : zPlane);
04715
04716
04717 x2Dtop = false;
04718 y2Dright = false;
04719 layer2Dtop = false;
04720 if (xstate == AXE_HORZ_DIR && ystate == AXE_VERT_DIR)
04721 {
04722 if (xaxislocation_is ("top"))
04723 {
04724 double tmp = yPlane;
04725 yPlane = yPlaneN;
04726 yPlaneN = tmp;
04727 x2Dtop = true;
04728 }
04729 ypTick = yPlaneN;
04730 ypTickN = yPlane;
04731 if (yaxislocation_is ("right"))
04732 {
04733 double tmp = xPlane;
04734 xPlane = xPlaneN;
04735 xPlaneN = tmp;
04736 y2Dright = true;
04737 }
04738 xpTick = xPlaneN;
04739 xpTickN = xPlane;
04740 if (layer_is ("top"))
04741 {
04742 zpTick = zPlaneN;
04743 layer2Dtop = true;
04744 }
04745 else
04746 zpTick = zPlane;
04747 }
04748
04749 Matrix viewmat = get_view ().matrix_value ();
04750 nearhoriz = std::abs(viewmat(1)) <= 5;
04751
04752 update_ticklengths ();
04753 }
04754
04755 void
04756 axes::properties::update_ticklengths (void)
04757 {
04758 bool mode2d = (((xstate > AXE_DEPTH_DIR ? 1 : 0) +
04759 (ystate > AXE_DEPTH_DIR ? 1 : 0) +
04760 (zstate > AXE_DEPTH_DIR ? 1 : 0)) == 2);
04761 if (tickdirmode_is ("auto"))
04762 {
04763
04764
04765
04766
04767
04768 }
04769
04770
04771 double ticksign = (tickdirmode_is ("auto") ?
04772 (mode2d ? -1 : 1) :
04773 (tickdir_is ("in") ? -1 : 1));
04774
04775 xticklen = ticksign*7;
04776 yticklen = ticksign*7;
04777 zticklen = ticksign*7;
04778
04779 xtickoffset = (mode2d ? std::max (0., xticklen) : std::abs (xticklen)) + 5;
04780 ytickoffset = (mode2d ? std::max (0., yticklen) : std::abs (yticklen)) + 5;
04781 ztickoffset = (mode2d ? std::max (0., zticklen) : std::abs (zticklen)) + 5;
04782
04783 update_xlabel_position ();
04784 update_ylabel_position ();
04785 update_zlabel_position ();
04786 update_title_position ();
04787 }
04788
04789 static bool updating_xlabel_position = false;
04790
04791 void
04792 axes::properties::update_xlabel_position (void)
04793 {
04794 if (updating_xlabel_position)
04795 return;
04796
04797 text::properties& xlabel_props = reinterpret_cast<text::properties&>
04798 (gh_manager::get_object (get_xlabel ()).get_properties ());
04799
04800 bool is_empty = xlabel_props.get_string ().is_empty ();
04801
04802 unwind_protect frame;
04803 frame.protect_var (updating_xlabel_position);
04804 updating_xlabel_position = true;
04805
04806 if (! is_empty)
04807 {
04808 if (xlabel_props.horizontalalignmentmode_is ("auto"))
04809 {
04810 xlabel_props.set_horizontalalignment
04811 (xstate > AXE_DEPTH_DIR
04812 ? "center" : (xyzSym ? "left" : "right"));
04813
04814 xlabel_props.set_horizontalalignmentmode ("auto");
04815 }
04816
04817 if (xlabel_props.verticalalignmentmode_is ("auto"))
04818 {
04819 xlabel_props.set_verticalalignment
04820 (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
04821
04822 xlabel_props.set_verticalalignmentmode ("auto");
04823 }
04824 }
04825
04826 if (xlabel_props.positionmode_is ("auto")
04827 || xlabel_props.rotationmode_is ("auto"))
04828 {
04829 graphics_xform xform = get_transform ();
04830
04831 Matrix ext (1, 2, 0.0);
04832 ext = get_ticklabel_extents (get_xtick ().matrix_value (),
04833 get_xticklabel ().all_strings (),
04834 get_xlim ().matrix_value ());
04835
04836 double wmax = ext(0), hmax = ext(1), angle = 0;
04837 ColumnVector p =
04838 graphics_xform::xform_vector ((xpTickN+xpTick)/2, ypTick, zpTick);
04839
04840 bool tick_along_z = nearhoriz || xisinf (fy);
04841 if (tick_along_z)
04842 p(2) += (signum(zpTick-zpTickN)*fz*xtickoffset);
04843 else
04844 p(1) += (signum(ypTick-ypTickN)*fy*xtickoffset);
04845
04846 p = xform.transform (p(0), p(1), p(2), false);
04847
04848 switch (xstate)
04849 {
04850 case AXE_ANY_DIR:
04851 p(0) += (xyzSym ? wmax : -wmax);
04852 p(1) += hmax;
04853 break;
04854
04855 case AXE_VERT_DIR:
04856 p(0) -= wmax;
04857 angle = 90;
04858 break;
04859
04860 case AXE_HORZ_DIR:
04861 p(1) += (x2Dtop ? -hmax : hmax);
04862 break;
04863 }
04864
04865 if (xlabel_props.positionmode_is ("auto"))
04866 {
04867 p = xform.untransform (p(0), p(1), p(2), true);
04868 xlabel_props.set_position (p.extract_n (0, 3).transpose ());
04869 xlabel_props.set_positionmode ("auto");
04870 }
04871
04872 if (! is_empty && xlabel_props.rotationmode_is ("auto"))
04873 {
04874 xlabel_props.set_rotation (angle);
04875 xlabel_props.set_rotationmode ("auto");
04876 }
04877 }
04878 }
04879
04880 static bool updating_ylabel_position = false;
04881
04882 void
04883 axes::properties::update_ylabel_position (void)
04884 {
04885 if (updating_ylabel_position)
04886 return;
04887
04888 text::properties& ylabel_props = reinterpret_cast<text::properties&>
04889 (gh_manager::get_object (get_ylabel ()).get_properties ());
04890
04891 bool is_empty = ylabel_props.get_string ().is_empty ();
04892
04893 unwind_protect frame;
04894 frame.protect_var (updating_ylabel_position);
04895 updating_ylabel_position = true;
04896
04897 if (! is_empty)
04898 {
04899 if (ylabel_props.horizontalalignmentmode_is ("auto"))
04900 {
04901 ylabel_props.set_horizontalalignment
04902 (ystate > AXE_DEPTH_DIR
04903 ? "center" : (!xyzSym ? "left" : "right"));
04904
04905 ylabel_props.set_horizontalalignmentmode ("auto");
04906 }
04907
04908 if (ylabel_props.verticalalignmentmode_is ("auto"))
04909 {
04910 ylabel_props.set_verticalalignment
04911 (ystate == AXE_VERT_DIR && !y2Dright ? "bottom" : "top");
04912
04913 ylabel_props.set_verticalalignmentmode ("auto");
04914 }
04915 }
04916
04917 if (ylabel_props.positionmode_is ("auto")
04918 || ylabel_props.rotationmode_is ("auto"))
04919 {
04920 graphics_xform xform = get_transform ();
04921
04922 Matrix ext (1, 2, 0.0);
04923 ext = get_ticklabel_extents (get_ytick ().matrix_value (),
04924 get_yticklabel ().all_strings (),
04925 get_ylim ().matrix_value ());
04926
04927 double wmax = ext(0), hmax = ext(1), angle = 0;
04928 ColumnVector p =
04929 graphics_xform::xform_vector (xpTick, (ypTickN+ypTick)/2, zpTick);
04930
04931 bool tick_along_z = nearhoriz || xisinf (fx);
04932 if (tick_along_z)
04933 p(2) += (signum(zpTick-zpTickN)*fz*ytickoffset);
04934 else
04935 p(0) += (signum(xpTick-xpTickN)*fx*ytickoffset);
04936
04937 p = xform.transform (p(0), p(1), p(2), false);
04938
04939 switch (ystate)
04940 {
04941 case AXE_ANY_DIR:
04942 p(0) += (!xyzSym ? wmax : -wmax);
04943 p(1) += hmax;
04944 break;
04945
04946 case AXE_VERT_DIR:
04947 p(0) += (y2Dright ? wmax : -wmax);
04948 angle = 90;
04949 break;
04950
04951 case AXE_HORZ_DIR:
04952 p(1) += hmax;
04953 break;
04954 }
04955
04956 if (ylabel_props.positionmode_is ("auto"))
04957 {
04958 p = xform.untransform (p(0), p(1), p(2), true);
04959 ylabel_props.set_position (p.extract_n (0, 3).transpose ());
04960 ylabel_props.set_positionmode ("auto");
04961 }
04962
04963 if (! is_empty && ylabel_props.rotationmode_is ("auto"))
04964 {
04965 ylabel_props.set_rotation (angle);
04966 ylabel_props.set_rotationmode ("auto");
04967 }
04968 }
04969 }
04970
04971 static bool updating_zlabel_position = false;
04972
04973 void
04974 axes::properties::update_zlabel_position (void)
04975 {
04976 if (updating_zlabel_position)
04977 return;
04978
04979 text::properties& zlabel_props = reinterpret_cast<text::properties&>
04980 (gh_manager::get_object (get_zlabel ()).get_properties ());
04981
04982 bool camAuto = cameraupvectormode_is ("auto");
04983 bool is_empty = zlabel_props.get_string ().is_empty ();
04984
04985 unwind_protect frame;
04986 frame.protect_var (updating_zlabel_position);
04987 updating_zlabel_position = true;
04988
04989 if (! is_empty)
04990 {
04991 if (zlabel_props.horizontalalignmentmode_is ("auto"))
04992 {
04993 zlabel_props.set_horizontalalignment
04994 ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
04995
04996 zlabel_props.set_horizontalalignmentmode ("auto");
04997 }
04998
04999 if (zlabel_props.verticalalignmentmode_is ("auto"))
05000 {
05001 zlabel_props.set_verticalalignment
05002 (zstate == AXE_VERT_DIR
05003 ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
05004
05005 zlabel_props.set_verticalalignmentmode ("auto");
05006 }
05007 }
05008
05009 if (zlabel_props.positionmode_is ("auto")
05010 || zlabel_props.rotationmode_is ("auto"))
05011 {
05012 graphics_xform xform = get_transform ();
05013
05014 Matrix ext (1, 2, 0.0);
05015 ext = get_ticklabel_extents (get_ztick ().matrix_value (),
05016 get_zticklabel ().all_strings (),
05017 get_zlim ().matrix_value ());
05018
05019 double wmax = ext(0), hmax = ext(1), angle = 0;
05020 ColumnVector p;
05021
05022 if (xySym)
05023 {
05024 p = graphics_xform::xform_vector (xPlaneN, yPlane,
05025 (zpTickN+zpTick)/2);
05026 if (xisinf (fy))
05027 p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset);
05028 else
05029 p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset);
05030 }
05031 else
05032 {
05033 p = graphics_xform::xform_vector (xPlane, yPlaneN,
05034 (zpTickN+zpTick)/2);
05035 if (xisinf (fx))
05036 p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset);
05037 else
05038 p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset);
05039 }
05040
05041 p = xform.transform (p(0), p(1), p(2), false);
05042
05043 switch (zstate)
05044 {
05045 case AXE_ANY_DIR:
05046 if (camAuto)
05047 {
05048 p(0) -= wmax;
05049 angle = 90;
05050 }
05051
05052
05053
05054
05055
05056
05057 break;
05058
05059 case AXE_VERT_DIR:
05060 p(0) -= wmax;
05061 angle = 90;
05062 break;
05063
05064 case AXE_HORZ_DIR:
05065 p(1) += hmax;
05066 break;
05067 }
05068
05069 if (zlabel_props.positionmode_is ("auto"))
05070 {
05071 p = xform.untransform (p(0), p(1), p(2), true);
05072 zlabel_props.set_position (p.extract_n (0, 3).transpose ());
05073 zlabel_props.set_positionmode ("auto");
05074 }
05075
05076 if (! is_empty && zlabel_props.rotationmode_is ("auto"))
05077 {
05078 zlabel_props.set_rotation (angle);
05079 zlabel_props.set_rotationmode ("auto");
05080 }
05081 }
05082 }
05083
05084 static bool updating_title_position = false;
05085
05086 void
05087 axes::properties::update_title_position (void)
05088 {
05089 if (updating_title_position)
05090 return;
05091
05092 text::properties& title_props = reinterpret_cast<text::properties&>
05093 (gh_manager::get_object (get_title ()).get_properties ());
05094
05095 unwind_protect frame;
05096 frame.protect_var (updating_title_position);
05097 updating_title_position = true;
05098
05099 if (title_props.positionmode_is ("auto"))
05100 {
05101 graphics_xform xform = get_transform ();
05102
05103
05104 Matrix bbox = get_extent (false);
05105
05106 ColumnVector p =
05107 graphics_xform::xform_vector (bbox(0)+bbox(2)/2,
05108 bbox(1)-10,
05109 (x_zlim(0)+x_zlim(1))/2);
05110
05111 if (x2Dtop)
05112 {
05113 Matrix ext (1, 2, 0.0);
05114 ext = get_ticklabel_extents (get_xtick ().matrix_value (),
05115 get_xticklabel ().all_strings (),
05116 get_xlim ().matrix_value ());
05117 p(1) -= ext(1);
05118 }
05119
05120 p = xform.untransform (p(0), p(1), p(2), true);
05121
05122 title_props.set_position (p.extract_n(0, 3).transpose ());
05123 title_props.set_positionmode ("auto");
05124 }
05125 }
05126
05127 void
05128 axes::properties::update_autopos (const std::string& elem_type)
05129 {
05130 if (elem_type == "xlabel")
05131 update_xlabel_position ();
05132 else if (elem_type == "ylabel")
05133 update_ylabel_position ();
05134 else if (elem_type == "zlabel")
05135 update_zlabel_position ();
05136 else if (elem_type == "title")
05137 update_title_position ();
05138 else if (elem_type == "sync")
05139 sync_positions ();
05140 }
05141
05142 static void
05143 normalized_aspectratios (Matrix& aspectratios, const Matrix& scalefactors,
05144 double xlength, double ylength, double zlength)
05145 {
05146 double xval = xlength/scalefactors(0);
05147 double yval = ylength/scalefactors(1);
05148 double zval = zlength/scalefactors(2);
05149
05150 double minval = xmin (xmin (xval, yval), zval);
05151
05152 aspectratios(0) = xval/minval;
05153 aspectratios(1) = yval/minval;
05154 aspectratios(2) = zval/minval;
05155 }
05156
05157 static void
05158 max_axes_scale (double& s, Matrix& limits, const Matrix& kids,
05159 double pbfactor, double dafactor, char limit_type, bool tight)
05160 {
05161 if (tight)
05162 {
05163 double minval = octave_Inf;
05164 double maxval = -octave_Inf;
05165 double min_pos = octave_Inf;
05166 double max_neg = -octave_Inf;
05167 get_children_limits (minval, maxval, min_pos, max_neg, kids, limit_type);
05168 if (!xisinf (minval) && !xisnan (minval)
05169 && !xisinf (maxval) && !xisnan (maxval))
05170 {
05171 limits(0) = minval;
05172 limits(1) = maxval;
05173 s = xmax(s, (maxval - minval) / (pbfactor * dafactor));
05174 }
05175 }
05176 else
05177 s = xmax(s, (limits(1) - limits(0)) / (pbfactor * dafactor));
05178 }
05179
05180 static bool updating_aspectratios = false;
05181
05182 void
05183 axes::properties::update_aspectratios (void)
05184 {
05185 if (updating_aspectratios)
05186 return;
05187
05188 Matrix xlimits = get_xlim ().matrix_value ();
05189 Matrix ylimits = get_ylim ().matrix_value ();
05190 Matrix zlimits = get_zlim ().matrix_value ();
05191
05192 double dx = (xlimits(1)-xlimits(0));
05193 double dy = (ylimits(1)-ylimits(0));
05194 double dz = (zlimits(1)-zlimits(0));
05195
05196 Matrix da = get_dataaspectratio ().matrix_value ();
05197 Matrix pba = get_plotboxaspectratio ().matrix_value ();
05198
05199 if (dataaspectratiomode_is ("auto"))
05200 {
05201 if (plotboxaspectratiomode_is ("auto"))
05202 {
05203 pba = Matrix (1, 3, 1.0);
05204 plotboxaspectratio.set (pba, false);
05205 }
05206
05207 normalized_aspectratios (da, pba, dx, dy, dz);
05208 dataaspectratio.set (da, false);
05209 }
05210 else if (plotboxaspectratiomode_is ("auto"))
05211 {
05212 normalized_aspectratios (pba, da, dx, dy, dz);
05213 plotboxaspectratio.set (pba, false);
05214 }
05215 else
05216 {
05217 double s = -octave_Inf;
05218 bool modified_limits = false;
05219 Matrix kids;
05220
05221 if (xlimmode_is ("auto") && ylimmode_is ("auto") && zlimmode_is ("auto"))
05222 {
05223 modified_limits = true;
05224 kids = get_children ();
05225 max_axes_scale (s, xlimits, kids, pba(0), da(0), 'x', true);
05226 max_axes_scale (s, ylimits, kids, pba(1), da(1), 'y', true);
05227 max_axes_scale (s, zlimits, kids, pba(2), da(2), 'z', true);
05228 }
05229 else if (xlimmode_is ("auto") && ylimmode_is ("auto"))
05230 {
05231 modified_limits = true;
05232 max_axes_scale (s, zlimits, kids, pba(2), da(2), 'z', false);
05233 }
05234 else if (ylimmode_is ("auto") && zlimmode_is ("auto"))
05235 {
05236 modified_limits = true;
05237 max_axes_scale (s, xlimits, kids, pba(0), da(0), 'x', false);
05238 }
05239 else if (zlimmode_is ("auto") && xlimmode_is ("auto"))
05240 {
05241 modified_limits = true;
05242 max_axes_scale (s, ylimits, kids, pba(1), da(1), 'y', false);
05243 }
05244
05245 if (modified_limits)
05246 {
05247
05248 unwind_protect frame;
05249 frame.protect_var (updating_aspectratios);
05250
05251 updating_aspectratios = true;
05252
05253 dx = pba(0) *da(0);
05254 dy = pba(1) *da(1);
05255 dz = pba(2) *da(2);
05256 if (xisinf (s))
05257 s = 1 / xmin (xmin (dx, dy), dz);
05258
05259 if (xlimmode_is ("auto"))
05260 {
05261 dx = s * dx;
05262 xlimits(0) = 0.5 * (xlimits(0) + xlimits(1) - dx);
05263 xlimits(1) = xlimits(0) + dx;
05264 set_xlim (xlimits);
05265 set_xlimmode ("auto");
05266 }
05267
05268 if (ylimmode_is ("auto"))
05269 {
05270 dy = s * dy;
05271 ylimits(0) = 0.5 * (ylimits(0) + ylimits(1) - dy);
05272 ylimits(1) = ylimits(0) + dy;
05273 set_ylim (ylimits);
05274 set_ylimmode ("auto");
05275 }
05276
05277 if (zlimmode_is ("auto"))
05278 {
05279 dz = s * dz;
05280 zlimits(0) = 0.5 * (zlimits(0) + zlimits(1) - dz);
05281 zlimits(1) = zlimits(0) + dz;
05282 set_zlim (zlimits);
05283 set_zlimmode ("auto");
05284 }
05285 }
05286 else
05287 {
05288 normalized_aspectratios (pba, da, dx, dy, dz);
05289 plotboxaspectratio.set (pba, false);
05290 }
05291 }
05292 }
05293
05294 void
05295 axes::properties::update_font (void)
05296 {
05297 #ifdef HAVE_FREETYPE
05298 #ifdef HAVE_FONTCONFIG
05299 text_renderer.set_font (get ("fontname").string_value (),
05300 get ("fontweight").string_value (),
05301 get ("fontangle").string_value (),
05302 get ("fontsize").double_value ());
05303 #endif
05304 #endif
05305 }
05306
05307
05308
05309 Matrix
05310 axes::properties::get_boundingbox (bool internal,
05311 const Matrix& parent_pix_size) const
05312 {
05313 Matrix pos = (internal ?
05314 get_position ().matrix_value ()
05315 : get_outerposition ().matrix_value ());
05316 Matrix parent_size (parent_pix_size);
05317
05318 if (parent_size.numel () == 0)
05319 {
05320 graphics_object obj = gh_manager::get_object (get_parent ());
05321
05322 parent_size =
05323 obj.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
05324 }
05325
05326 pos = convert_position (pos, get_units (), "pixels", parent_size);
05327
05328 pos(0)--;
05329 pos(1)--;
05330 pos(1) = parent_size(1) - pos(1) - pos(3);
05331
05332 return pos;
05333 }
05334
05335 Matrix
05336 axes::properties::get_extent (bool with_text, bool only_text_height) const
05337 {
05338 graphics_xform xform = get_transform ();
05339
05340 Matrix ext (1, 4, 0.0);
05341 ext(0) = octave_Inf;
05342 ext(1) = octave_Inf;
05343 ext(2) = -octave_Inf;
05344 ext(3) = -octave_Inf;
05345 for (int i = 0; i <= 1; i++)
05346 for (int j = 0; j <= 1; j++)
05347 for (int k = 0; k <= 1; k++)
05348 {
05349 ColumnVector p = xform.transform (i ? xPlaneN : xPlane,
05350 j ? yPlaneN : yPlane,
05351 k ? zPlaneN : zPlane, false);
05352 ext(0) = std::min (ext(0), p(0));
05353 ext(1) = std::min (ext(1), p(1));
05354 ext(2) = std::max (ext(2), p(0));
05355 ext(3) = std::max (ext(3), p(1));
05356 }
05357
05358 if (with_text)
05359 {
05360 for (int i = 0; i < 4; i++)
05361 {
05362 graphics_handle text_handle;
05363 if (i == 0)
05364 text_handle = get_title ();
05365 else if (i == 1)
05366 text_handle = get_xlabel ();
05367 else if (i == 2)
05368 text_handle = get_ylabel ();
05369 else if (i == 3)
05370 text_handle = get_zlabel ();
05371
05372 text::properties& text_props = reinterpret_cast<text::properties&>
05373 (gh_manager::get_object (text_handle).get_properties ());
05374
05375 Matrix text_pos = text_props.get_position ().matrix_value ();
05376 text_pos = xform.transform (text_pos(0), text_pos(1), text_pos(2));
05377 if (text_props.get_string ().is_empty ())
05378 {
05379 ext(0) = std::min (ext(0), text_pos(0));
05380 ext(1) = std::min (ext(1), text_pos(1));
05381 ext(2) = std::max (ext(2), text_pos(0));
05382 ext(3) = std::max (ext(3), text_pos(1));
05383 }
05384 else
05385 {
05386 Matrix text_ext = text_props.get_extent_matrix ();
05387
05388 bool ignore_horizontal = false;
05389 bool ignore_vertical = false;
05390 if (only_text_height)
05391 {
05392 double text_rotation = text_props.get_rotation();
05393 if (text_rotation == 0. || text_rotation == 180.)
05394 ignore_horizontal = true;
05395 else if (text_rotation == 90. || text_rotation == 270.)
05396 ignore_vertical = true;
05397 }
05398
05399 if (! ignore_horizontal)
05400 {
05401 ext(0) = std::min (ext(0), text_pos(0)+text_ext(0));
05402 ext(2) = std::max (ext(2), text_pos(0)+text_ext(0)+text_ext(2));
05403 }
05404
05405 if (! ignore_vertical)
05406 {
05407 ext(1) = std::min (ext(1), text_pos(1)-text_ext(1)-text_ext(3));
05408 ext(3) = std::max (ext(3), text_pos(1)-text_ext(1));
05409 }
05410 }
05411 }
05412 }
05413
05414 ext(2) = ext(2)-ext(0);
05415 ext(3) = ext(3)-ext(1);
05416
05417 return ext;
05418 }
05419
05420 void
05421 axes::properties::set_units (const octave_value& v)
05422 {
05423 if (! error_state)
05424 {
05425 caseless_str old_units = get_units ();
05426 if (units.set (v, true))
05427 {
05428 update_units (old_units);
05429 mark_modified ();
05430 }
05431 }
05432 }
05433
05434 void
05435 axes::properties::update_units (const caseless_str& old_units)
05436 {
05437 graphics_object obj = gh_manager::get_object (get_parent ());
05438 Matrix parent_bb = obj.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
05439 caseless_str new_units = get_units ();
05440 position.set (octave_value (convert_position (get_position().matrix_value(), old_units, new_units, parent_bb)), false);
05441 outerposition.set (octave_value (convert_position (get_outerposition().matrix_value(), old_units, new_units, parent_bb)), false);
05442 tightinset.set (octave_value (convert_position (get_tightinset().matrix_value(), old_units, new_units, parent_bb)), false);
05443 }
05444
05445 void
05446 axes::properties::set_fontunits (const octave_value& v)
05447 {
05448 if (! error_state)
05449 {
05450 caseless_str old_fontunits = get_fontunits ();
05451 if (fontunits.set (v, true))
05452 {
05453 update_fontunits (old_fontunits);
05454 mark_modified ();
05455 }
05456 }
05457 }
05458
05459 void
05460 axes::properties::update_fontunits (const caseless_str& old_units)
05461 {
05462 caseless_str new_units = get_fontunits ();
05463 double parent_height = get_boundingbox (true).elem (3);
05464 double fsz = get_fontsize ();
05465
05466 fsz = convert_font_size (fsz, old_units, new_units, parent_height);
05467
05468 set_fontsize (octave_value (fsz));
05469 }
05470
05471 double
05472 axes::properties::get_fontsize_points (double box_pix_height) const
05473 {
05474 double fs = get_fontsize ();
05475 double parent_height = box_pix_height;
05476
05477 if (fontunits_is ("normalized") && parent_height <= 0)
05478 parent_height = get_boundingbox (true).elem(3);
05479
05480 return convert_font_size (fs, get_fontunits (), "points", parent_height);
05481 }
05482
05483 ColumnVector
05484 graphics_xform::xform_vector (double x, double y, double z)
05485 {
05486 return ::xform_vector (x, y, z);
05487 }
05488
05489 Matrix
05490 graphics_xform::xform_eye (void)
05491 {
05492 return ::xform_matrix ();
05493 }
05494
05495 ColumnVector
05496 graphics_xform::transform (double x, double y, double z,
05497 bool use_scale) const
05498 {
05499 if (use_scale)
05500 {
05501 x = sx.scale (x);
05502 y = sy.scale (y);
05503 z = sz.scale (z);
05504 }
05505
05506 return ::transform (xform, x, y, z);
05507 }
05508
05509 ColumnVector
05510 graphics_xform::untransform (double x, double y, double z,
05511 bool use_scale) const
05512 {
05513 ColumnVector v = ::transform (xform_inv, x, y, z);
05514
05515 if (use_scale)
05516 {
05517 v(0) = sx.unscale (v(0));
05518 v(1) = sy.unscale (v(1));
05519 v(2) = sz.unscale (v(2));
05520 }
05521
05522 return v;
05523 }
05524
05525 octave_value
05526 axes::get_default (const caseless_str& name) const
05527 {
05528 octave_value retval = default_properties.lookup (name);
05529
05530 if (retval.is_undefined ())
05531 {
05532 graphics_handle parent = get_parent ();
05533 graphics_object parent_obj = gh_manager::get_object (parent);
05534
05535 retval = parent_obj.get_default (name);
05536 }
05537
05538 return retval;
05539 }
05540
05541
05542
05543
05544
05545
05546
05547
05548
05549
05550
05551
05552
05553
05554
05555
05556
05557
05558
05559
05560
05561
05562
05563
05564 static void
05565 check_limit_vals (double& min_val, double& max_val,
05566 double& min_pos, double& max_neg,
05567 const octave_value& data)
05568 {
05569 if (data.is_matrix_type ())
05570 {
05571 Matrix m = data.matrix_value ();
05572
05573 if (! error_state && m.numel () == 4)
05574 {
05575 double val;
05576
05577 val = m(0);
05578 if (! (xisinf (val) || xisnan (val)) && val < min_val)
05579 min_val = val;
05580
05581 val = m(1);
05582 if (! (xisinf (val) || xisnan (val)) && val > max_val)
05583 max_val = val;
05584
05585 val = m(2);
05586 if (! (xisinf (val) || xisnan (val)) && val > 0 && val < min_pos)
05587 min_pos = val;
05588
05589 val = m(3);
05590 if (! (xisinf (val) || xisnan (val)) && val < 0 && val > max_neg)
05591 max_neg = val;
05592 }
05593 }
05594 }
05595
05596
05597
05598
05599 static void
05600 magform (double x, double& a, int& b)
05601 {
05602 if (x == 0)
05603 {
05604 a = 0;
05605 b = 0;
05606 }
05607 else
05608 {
05609 b = static_cast<int> (gnulib::floor (std::log10 (std::abs (x))));
05610 a = x / std::pow (10.0, b);
05611 }
05612 }
05613
05614
05615
05616
05617
05618 double
05619 axes::properties::calc_tick_sep (double lo, double hi)
05620 {
05621 int ticint = 5;
05622
05623
05624
05625
05626
05627
05628 double a;
05629 int b, x;
05630
05631 magform ((hi-lo)/ticint, a, b);
05632
05633 static const double sqrt_2 = sqrt (2.0);
05634 static const double sqrt_10 = sqrt (10.0);
05635 static const double sqrt_50 = sqrt (50.0);
05636
05637 if (a < sqrt_2)
05638 x = 1;
05639 else if (a < sqrt_10)
05640 x = 2;
05641 else if (a < sqrt_50)
05642 x = 5;
05643 else
05644 x = 10;
05645
05646 return x * std::pow (10., b);
05647
05648 }
05649
05650
05651
05652
05653
05654 Matrix
05655 axes::properties::get_axis_limits (double xmin, double xmax,
05656 double min_pos, double max_neg,
05657 bool logscale)
05658 {
05659 Matrix retval;
05660
05661 double min_val = xmin;
05662 double max_val = xmax;
05663
05664 if (xisinf (min_val) && min_val > 0 && xisinf (max_val) && max_val < 0)
05665 {
05666 retval = default_lim (logscale);
05667 return retval;
05668 }
05669 else if (! (xisinf (min_val) || xisinf (max_val)))
05670 {
05671 if (logscale)
05672 {
05673 if (xisinf (min_pos) && xisinf (max_neg))
05674 {
05675
05676
05677
05678 retval = default_lim ();
05679 retval(0) = pow (10., retval(0));
05680 retval(1) = pow (10., retval(1));
05681 return retval;
05682 }
05683 if ((min_val <= 0 && max_val > 0))
05684 {
05685 warning ("axis: omitting non-positive data in log plot");
05686 min_val = min_pos;
05687 }
05688
05689 if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
05690 {
05691 min_val *= 0.9;
05692 max_val *= 1.1;
05693 }
05694 if (min_val > 0)
05695 {
05696
05697 min_val = pow (10, gnulib::floor (log10 (min_val)));
05698 max_val = pow (10, std::ceil (log10 (max_val)));
05699 }
05700 else
05701 {
05702
05703 min_val = -pow (10, std::ceil (log10 (-min_val)));
05704 max_val = -pow (10, gnulib::floor (log10 (-max_val)));
05705 }
05706 }
05707 else
05708 {
05709 if (min_val == 0 && max_val == 0)
05710 {
05711 min_val = -1;
05712 max_val = 1;
05713 }
05714
05715 else if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
05716 {
05717 min_val -= 0.1 * std::abs (min_val);
05718 max_val += 0.1 * std::abs (max_val);
05719 }
05720
05721 double tick_sep = calc_tick_sep (min_val , max_val);
05722 double min_tick = gnulib::floor (min_val / tick_sep);
05723 double max_tick = std::ceil (max_val / tick_sep);
05724
05725 min_val = std::min (min_val, tick_sep * min_tick);
05726 max_val = std::max (max_val, tick_sep * max_tick);
05727 }
05728 }
05729
05730 retval.resize (1, 2);
05731
05732 retval(1) = max_val;
05733 retval(0) = min_val;
05734
05735 return retval;
05736 }
05737
05738 void
05739 axes::properties::calc_ticks_and_lims (array_property& lims,
05740 array_property& ticks,
05741 array_property& mticks,
05742 bool limmode_is_auto, bool is_logscale)
05743 {
05744
05745
05746 if (lims.get ().is_empty ())
05747 return;
05748
05749 double lo = (lims.get ().matrix_value ()) (0);
05750 double hi = (lims.get ().matrix_value ()) (1);
05751 bool is_negative = lo < 0 && hi < 0;
05752 double tmp;
05753
05754 if (hi < lo)
05755 {
05756 tmp = hi;
05757 hi = lo;
05758 lo = tmp;
05759 }
05760
05761 if (is_logscale)
05762 {
05763 if (is_negative)
05764 {
05765 tmp = hi;
05766 hi = std::log10 (-lo);
05767 lo = std::log10 (-tmp);
05768 }
05769 else
05770 {
05771 hi = std::log10 (hi);
05772 lo = std::log10 (lo);
05773 }
05774 }
05775
05776 double tick_sep = calc_tick_sep (lo , hi);
05777
05778 if (is_logscale && ! (xisinf (hi) || xisinf (lo)))
05779 {
05780
05781
05782 tick_sep = std::max (tick_sep, 1.);
05783 tick_sep = std::ceil (tick_sep);
05784 }
05785
05786 int i1 = static_cast<int> (gnulib::floor (lo / tick_sep));
05787 int i2 = static_cast<int> (std::ceil (hi / tick_sep));
05788
05789 if (limmode_is_auto)
05790 {
05791
05792 Matrix tmp_lims (1,2);
05793 tmp_lims(0) = std::min (tick_sep * i1, lo);
05794 tmp_lims(1) = std::max (tick_sep * i2, hi);
05795
05796 if (is_logscale)
05797 {
05798 tmp_lims(0) = std::pow (10.,tmp_lims(0));
05799 tmp_lims(1) = std::pow (10.,tmp_lims(1));
05800 if (tmp_lims(0) <= 0)
05801 tmp_lims(0) = std::pow (10., lo);
05802 if (is_negative)
05803 {
05804 tmp = tmp_lims(0);
05805 tmp_lims(0) = -tmp_lims(1);
05806 tmp_lims(1) = -tmp;
05807 }
05808 }
05809 lims = tmp_lims;
05810 }
05811
05812 Matrix tmp_ticks (1, i2-i1+1);
05813 for (int i = 0; i <= i2-i1; i++)
05814 {
05815 tmp_ticks (i) = tick_sep * (i+i1);
05816 if (is_logscale)
05817 tmp_ticks (i) = std::pow (10., tmp_ticks (i));
05818 }
05819 if (is_logscale && is_negative)
05820 {
05821 Matrix rev_ticks (1, i2-i1+1);
05822 rev_ticks = -tmp_ticks;
05823 for (int i = 0; i <= i2-i1; i++)
05824 tmp_ticks (i) = rev_ticks (i2-i1-i);
05825 }
05826
05827 ticks = tmp_ticks;
05828
05829 int n = is_logscale ? 8 : 4;
05830 Matrix tmp_mticks (1, n * (tmp_ticks.numel () - 1));
05831
05832 for (int i = 0; i < tmp_ticks.numel ()-1; i++)
05833 {
05834 double d = (tmp_ticks (i+1) - tmp_ticks (i)) / (n+1);
05835 for (int j = 0; j < n; j++)
05836 {
05837 tmp_mticks (n*i+j) = tmp_ticks (i) + d * (j+1);
05838 }
05839 }
05840 mticks = tmp_mticks;
05841 }
05842
05843 void
05844 axes::properties::calc_ticklabels (const array_property& ticks,
05845 any_property& labels, bool logscale)
05846 {
05847 Matrix values = ticks.get ().matrix_value ();
05848 Cell c (values.dims ());
05849 std::ostringstream os;
05850
05851 if (logscale)
05852 {
05853 double significand;
05854 double exponent;
05855 double exp_max = 0.;
05856 double exp_min = 0.;
05857
05858 for (int i = 0; i < values.numel (); i++)
05859 {
05860 exp_max = std::max (exp_max, std::log10 (values(i)));
05861 exp_min = std::max (exp_min, std::log10 (values(i)));
05862 }
05863
05864 for (int i = 0; i < values.numel (); i++)
05865 {
05866 if (values(i) < 0.)
05867 exponent = gnulib::floor (std::log10 (-values(i)));
05868 else
05869 exponent = gnulib::floor (std::log10 (values(i)));
05870 significand = values(i) * std::pow (10., -exponent);
05871 os.str (std::string ());
05872 os << significand;
05873 if (exponent < 0.)
05874 {
05875 os << "e-";
05876 exponent = -exponent;
05877 }
05878 else
05879 os << "e+";
05880 if (exponent < 10. && (exp_max > 9 || exp_min < -9))
05881 os << "0";
05882 os << exponent;
05883 c(i) = os.str ();
05884 }
05885 }
05886 else
05887 {
05888 for (int i = 0; i < values.numel (); i++)
05889 {
05890 os.str (std::string ());
05891 os << values(i);
05892 c(i) = os.str ();
05893 }
05894 }
05895
05896 labels = c;
05897 }
05898
05899 Matrix
05900 axes::properties::get_ticklabel_extents (const Matrix& ticks,
05901 const string_vector& ticklabels,
05902 const Matrix& limits)
05903 {
05904 #ifndef HAVE_FREETYPE
05905 double fontsize = get ("fontsize").double_value ();
05906 #endif
05907
05908 Matrix ext (1, 2, 0.0);
05909 double wmax = 0., hmax = 0.;
05910 int n = std::min (ticklabels.numel (), ticks.numel ());
05911 for (int i = 0; i < n; i++)
05912 {
05913 double val = ticks(i);
05914 if (limits(0) <= val && val <= limits(1))
05915 {
05916 #ifdef HAVE_FREETYPE
05917 ext = text_renderer.get_extent (ticklabels(i));
05918 wmax = std::max (wmax, ext(0));
05919 hmax = std::max (hmax, ext(1));
05920 #else
05921
05922 int len = ticklabels(i).length();
05923 wmax = std::max (wmax, 0.5*fontsize*len);
05924 hmax = fontsize;
05925 #endif
05926 }
05927 }
05928
05929 ext(0) = wmax;
05930 ext(1) = hmax;
05931 return ext;
05932 }
05933
05934 void
05935 get_children_limits (double& min_val, double& max_val,
05936 double& min_pos, double& max_neg,
05937 const Matrix& kids, char limit_type)
05938 {
05939 octave_idx_type n = kids.numel ();
05940
05941 switch (limit_type)
05942 {
05943 case 'x':
05944 for (octave_idx_type i = 0; i < n; i++)
05945 {
05946 graphics_object obj = gh_manager::get_object (kids(i));
05947
05948 if (obj.is_xliminclude ())
05949 {
05950 octave_value lim = obj.get_xlim ();
05951
05952 check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
05953 }
05954 }
05955 break;
05956
05957 case 'y':
05958 for (octave_idx_type i = 0; i < n; i++)
05959 {
05960 graphics_object obj = gh_manager::get_object (kids(i));
05961
05962 if (obj.is_yliminclude ())
05963 {
05964 octave_value lim = obj.get_ylim ();
05965
05966 check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
05967 }
05968 }
05969 break;
05970
05971 case 'z':
05972 for (octave_idx_type i = 0; i < n; i++)
05973 {
05974 graphics_object obj = gh_manager::get_object (kids(i));
05975
05976 if (obj.is_zliminclude ())
05977 {
05978 octave_value lim = obj.get_zlim ();
05979
05980 check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
05981 }
05982 }
05983 break;
05984
05985 case 'c':
05986 for (octave_idx_type i = 0; i < n; i++)
05987 {
05988 graphics_object obj = gh_manager::get_object (kids(i));
05989
05990 if (obj.is_climinclude ())
05991 {
05992 octave_value lim = obj.get_clim ();
05993
05994 check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
05995 }
05996 }
05997 break;
05998
05999 case 'a':
06000 for (octave_idx_type i = 0; i < n; i++)
06001 {
06002 graphics_object obj = gh_manager::get_object (kids(i));
06003
06004 if (obj.is_aliminclude ())
06005 {
06006 octave_value lim = obj.get_alim ();
06007
06008 check_limit_vals (min_val, max_val, min_pos, max_neg, lim);
06009 }
06010 }
06011 break;
06012
06013 default:
06014 break;
06015 }
06016 }
06017
06018 static bool updating_axis_limits = false;
06019
06020 void
06021 axes::update_axis_limits (const std::string& axis_type,
06022 const graphics_handle& h)
06023 {
06024 if (updating_axis_limits)
06025 return;
06026
06027 Matrix kids = Matrix (1, 1, h.value ());
06028
06029 double min_val = octave_Inf;
06030 double max_val = -octave_Inf;
06031 double min_pos = octave_Inf;
06032 double max_neg = -octave_Inf;
06033
06034 char update_type = 0;
06035
06036 Matrix limits;
06037 double val;
06038
06039 #define FIX_LIMITS \
06040 if (limits.numel() == 4) \
06041 { \
06042 val = limits(0); \
06043 if (! (xisinf (val) || xisnan (val))) \
06044 min_val = val; \
06045 val = limits(1); \
06046 if (! (xisinf (val) || xisnan (val))) \
06047 max_val = val; \
06048 val = limits(2); \
06049 if (! (xisinf (val) || xisnan (val))) \
06050 min_pos = val; \
06051 val = limits(3); \
06052 if (! (xisinf (val) || xisnan (val))) \
06053 max_neg = val; \
06054 } \
06055 else \
06056 { \
06057 limits.resize(4, 1); \
06058 limits(0) = min_val; \
06059 limits(1) = max_val; \
06060 limits(2) = min_pos; \
06061 limits(3) = max_neg; \
06062 }
06063
06064 if (axis_type == "xdata" || axis_type == "xscale"
06065 || axis_type == "xlimmode" || axis_type == "xliminclude"
06066 || axis_type == "xlim")
06067 {
06068 if (xproperties.xlimmode_is ("auto"))
06069 {
06070 limits = xproperties.get_xlim ().matrix_value ();
06071 FIX_LIMITS ;
06072
06073 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x');
06074
06075 limits = xproperties.get_axis_limits (min_val, max_val,
06076 min_pos, max_neg,
06077 xproperties.xscale_is ("log"));
06078
06079 update_type = 'x';
06080 }
06081 }
06082 else if (axis_type == "ydata" || axis_type == "yscale"
06083 || axis_type == "ylimmode" || axis_type == "yliminclude"
06084 || axis_type == "ylim")
06085 {
06086 if (xproperties.ylimmode_is ("auto"))
06087 {
06088 limits = xproperties.get_ylim ().matrix_value ();
06089 FIX_LIMITS ;
06090
06091 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y');
06092
06093 limits = xproperties.get_axis_limits (min_val, max_val,
06094 min_pos, max_neg,
06095 xproperties.yscale_is ("log"));
06096
06097 update_type = 'y';
06098 }
06099 }
06100 else if (axis_type == "zdata" || axis_type == "zscale"
06101 || axis_type == "zlimmode" || axis_type == "zliminclude"
06102 || axis_type == "zlim")
06103 {
06104 if (xproperties.zlimmode_is ("auto"))
06105 {
06106 limits = xproperties.get_zlim ().matrix_value ();
06107 FIX_LIMITS ;
06108
06109 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z');
06110
06111 limits = xproperties.get_axis_limits (min_val, max_val,
06112 min_pos, max_neg,
06113 xproperties.zscale_is ("log"));
06114
06115 update_type = 'z';
06116 }
06117 }
06118 else if (axis_type == "cdata" || axis_type == "climmode"
06119 || axis_type == "cdatamapping" || axis_type == "climinclude"
06120 || axis_type == "clim")
06121 {
06122 if (xproperties.climmode_is ("auto"))
06123 {
06124 limits = xproperties.get_clim ().matrix_value ();
06125 FIX_LIMITS ;
06126
06127 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c');
06128
06129 if (min_val > max_val)
06130 {
06131 min_val = min_pos = 0;
06132 max_val = 1;
06133 }
06134 else if (min_val == max_val)
06135 {
06136 max_val = min_val + 1;
06137 min_val -= 1;
06138 }
06139
06140 limits.resize (1, 2);
06141
06142 limits(0) = min_val;
06143 limits(1) = max_val;
06144
06145 update_type = 'c';
06146 }
06147
06148 }
06149 else if (axis_type == "alphadata" || axis_type == "alimmode"
06150 || axis_type == "alphadatamapping" || axis_type == "aliminclude"
06151 || axis_type == "alim")
06152 {
06153 if (xproperties.alimmode_is ("auto"))
06154 {
06155 limits = xproperties.get_alim ().matrix_value ();
06156 FIX_LIMITS ;
06157
06158 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a');
06159
06160 if (min_val > max_val)
06161 {
06162 min_val = min_pos = 0;
06163 max_val = 1;
06164 }
06165 else if (min_val == max_val)
06166 max_val = min_val + 1;
06167
06168 limits.resize (1, 2);
06169
06170 limits(0) = min_val;
06171 limits(1) = max_val;
06172
06173 update_type = 'a';
06174 }
06175
06176 }
06177
06178 #undef FIX_LIMITS
06179
06180 unwind_protect frame;
06181 frame.protect_var (updating_axis_limits);
06182
06183 updating_axis_limits = true;
06184
06185 switch (update_type)
06186 {
06187 case 'x':
06188 xproperties.set_xlim (limits);
06189 xproperties.set_xlimmode ("auto");
06190 xproperties.update_xlim ();
06191 break;
06192
06193 case 'y':
06194 xproperties.set_ylim (limits);
06195 xproperties.set_ylimmode ("auto");
06196 xproperties.update_ylim ();
06197 break;
06198
06199 case 'z':
06200 xproperties.set_zlim (limits);
06201 xproperties.set_zlimmode ("auto");
06202 xproperties.update_zlim ();
06203 break;
06204
06205 case 'c':
06206 xproperties.set_clim (limits);
06207 xproperties.set_climmode ("auto");
06208 break;
06209
06210 case 'a':
06211 xproperties.set_alim (limits);
06212 xproperties.set_alimmode ("auto");
06213 break;
06214
06215 default:
06216 break;
06217 }
06218
06219 xproperties.update_transform ();
06220
06221 }
06222
06223 void
06224 axes::update_axis_limits (const std::string& axis_type)
06225 {
06226 if (updating_axis_limits || updating_aspectratios)
06227 return;
06228
06229 Matrix kids = xproperties.get_children ();
06230
06231 double min_val = octave_Inf;
06232 double max_val = -octave_Inf;
06233 double min_pos = octave_Inf;
06234 double max_neg = -octave_Inf;
06235
06236 char update_type = 0;
06237
06238 Matrix limits;
06239
06240 if (axis_type == "xdata" || axis_type == "xscale"
06241 || axis_type == "xlimmode" || axis_type == "xliminclude"
06242 || axis_type == "xlim")
06243 {
06244 if (xproperties.xlimmode_is ("auto"))
06245 {
06246 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x');
06247
06248 limits = xproperties.get_axis_limits (min_val, max_val,
06249 min_pos, max_neg,
06250 xproperties.xscale_is ("log"));
06251
06252 update_type = 'x';
06253 }
06254 }
06255 else if (axis_type == "ydata" || axis_type == "yscale"
06256 || axis_type == "ylimmode" || axis_type == "yliminclude"
06257 || axis_type == "ylim")
06258 {
06259 if (xproperties.ylimmode_is ("auto"))
06260 {
06261 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y');
06262
06263 limits = xproperties.get_axis_limits (min_val, max_val,
06264 min_pos, max_neg,
06265 xproperties.yscale_is ("log"));
06266
06267 update_type = 'y';
06268 }
06269 }
06270 else if (axis_type == "zdata" || axis_type == "zscale"
06271 || axis_type == "zlimmode" || axis_type == "zliminclude"
06272 || axis_type == "zlim")
06273 {
06274 if (xproperties.zlimmode_is ("auto"))
06275 {
06276 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z');
06277
06278 limits = xproperties.get_axis_limits (min_val, max_val,
06279 min_pos, max_neg,
06280 xproperties.zscale_is ("log"));
06281
06282 update_type = 'z';
06283 }
06284 }
06285 else if (axis_type == "cdata" || axis_type == "climmode"
06286 || axis_type == "cdatamapping" || axis_type == "climinclude"
06287 || axis_type == "clim")
06288 {
06289 if (xproperties.climmode_is ("auto"))
06290 {
06291 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c');
06292
06293 if (min_val > max_val)
06294 {
06295 min_val = min_pos = 0;
06296 max_val = 1;
06297 }
06298 else if (min_val == max_val)
06299 {
06300 max_val = min_val + 1;
06301 min_val -= 1;
06302 }
06303
06304 limits.resize (1, 2);
06305
06306 limits(0) = min_val;
06307 limits(1) = max_val;
06308
06309 update_type = 'c';
06310 }
06311
06312 }
06313 else if (axis_type == "alphadata" || axis_type == "alimmode"
06314 || axis_type == "alphadatamapping" || axis_type == "aliminclude"
06315 || axis_type == "alim")
06316 {
06317 if (xproperties.alimmode_is ("auto"))
06318 {
06319 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a');
06320
06321 if (min_val > max_val)
06322 {
06323 min_val = min_pos = 0;
06324 max_val = 1;
06325 }
06326 else if (min_val == max_val)
06327 max_val = min_val + 1;
06328
06329 limits.resize (1, 2);
06330
06331 limits(0) = min_val;
06332 limits(1) = max_val;
06333
06334 update_type = 'a';
06335 }
06336
06337 }
06338
06339 unwind_protect frame;
06340 frame.protect_var (updating_axis_limits);
06341
06342 updating_axis_limits = true;
06343
06344 switch (update_type)
06345 {
06346 case 'x':
06347 xproperties.set_xlim (limits);
06348 xproperties.set_xlimmode ("auto");
06349 xproperties.update_xlim ();
06350 break;
06351
06352 case 'y':
06353 xproperties.set_ylim (limits);
06354 xproperties.set_ylimmode ("auto");
06355 xproperties.update_ylim ();
06356 break;
06357
06358 case 'z':
06359 xproperties.set_zlim (limits);
06360 xproperties.set_zlimmode ("auto");
06361 xproperties.update_zlim ();
06362 break;
06363
06364 case 'c':
06365 xproperties.set_clim (limits);
06366 xproperties.set_climmode ("auto");
06367 break;
06368
06369 case 'a':
06370 xproperties.set_alim (limits);
06371 xproperties.set_alimmode ("auto");
06372 break;
06373
06374 default:
06375 break;
06376 }
06377
06378 xproperties.update_transform ();
06379 }
06380
06381 inline
06382 double force_in_range (const double x, const double lower, const double upper)
06383 {
06384 if (x < lower)
06385 { return lower; }
06386 else if (x > upper)
06387 { return upper; }
06388 else
06389 { return x; }
06390 }
06391
06392 static Matrix
06393 do_zoom (double val, double factor, const Matrix& lims, bool is_logscale)
06394 {
06395 Matrix new_lims = lims;
06396
06397 double lo = lims(0);
06398 double hi = lims(1);
06399
06400 bool is_negative = lo < 0 && hi < 0;
06401
06402 if (is_logscale)
06403 {
06404 if (is_negative)
06405 {
06406 double tmp = hi;
06407 hi = std::log10 (-lo);
06408 lo = std::log10 (-tmp);
06409 val = std::log10 (-val);
06410 }
06411 else
06412 {
06413 hi = std::log10 (hi);
06414 lo = std::log10 (lo);
06415 val = std::log10 (val);
06416 }
06417 }
06418
06419
06420 lo = val + factor * (lo - val);
06421 hi = val + factor * (hi - val);
06422
06423 if (is_logscale)
06424 {
06425 if (is_negative)
06426 {
06427 double tmp = -std::pow (10.0, hi);
06428 hi = -std::pow (10.0, lo);
06429 lo = tmp;
06430 }
06431 else
06432 {
06433 lo = std::pow (10.0, lo);
06434 hi = std::pow (10.0, hi);
06435 }
06436 }
06437
06438 new_lims(0) = lo;
06439 new_lims(1) = hi;
06440
06441 return new_lims;
06442 }
06443
06444 void
06445 axes::properties::zoom_about_point (double x, double y, double factor,
06446 bool push_to_zoom_stack)
06447 {
06448
06449 Matrix xlims = get_xlim ().matrix_value ();
06450 Matrix ylims = get_ylim ().matrix_value ();
06451
06452
06453 Matrix kids = get_children ();
06454 double minx = octave_Inf;
06455 double maxx = -octave_Inf;
06456 double min_pos_x = octave_Inf;
06457 double max_neg_x = -octave_Inf;
06458 get_children_limits (minx, maxx, min_pos_x, max_neg_x, kids, 'x');
06459
06460 double miny = octave_Inf;
06461 double maxy = -octave_Inf;
06462 double min_pos_y = octave_Inf;
06463 double max_neg_y = -octave_Inf;
06464 get_children_limits (miny, maxy, min_pos_y, max_neg_y, kids, 'y');
06465
06466 if (! (xscale_is ("log") && xlims(0) < 0 && xlims(1) < 0))
06467 xlims = do_zoom (x, factor, xlims, xscale_is ("log"));
06468
06469 if (! (yscale_is ("log") && ylims(0) < 0 && ylims(1) < 0))
06470 ylims = do_zoom (y, factor, ylims, yscale_is ("log"));
06471
06472 zoom (xlims, ylims, push_to_zoom_stack);
06473 }
06474
06475 void
06476 axes::properties::zoom (const Matrix& xl, const Matrix& yl, bool push_to_zoom_stack)
06477 {
06478
06479 Matrix xlims = get_xlim ().matrix_value ();
06480 Matrix ylims = get_ylim ().matrix_value ();
06481
06482 if ((xscale_is ("log") && xlims(0) < 0 && xlims(1) < 0)
06483 || (yscale_is ("log") && ylims(0) < 0 && ylims(1) < 0))
06484 return;
06485
06486 if (push_to_zoom_stack)
06487 {
06488 zoom_stack.push_front (xlimmode.get ());
06489 zoom_stack.push_front (xlim.get ());
06490 zoom_stack.push_front (ylimmode.get ());
06491 zoom_stack.push_front (ylim.get ());
06492 }
06493
06494 xlim = xl;
06495 xlimmode = "manual";
06496 ylim = yl;
06497 ylimmode = "manual";
06498
06499 update_transform ();
06500 update_xlim (false);
06501 update_ylim (false);
06502 }
06503
06504 void
06505 axes::properties::translate_view (double delta_x, double delta_y)
06506 {
06507
06508 Matrix xlims = get_xlim ().matrix_value ();
06509 Matrix ylims = get_ylim ().matrix_value ();
06510
06511
06512 Matrix kids = get_children ();
06513 double minx = octave_Inf;
06514 double maxx = -octave_Inf;
06515 double min_pos_x = octave_Inf;
06516 double max_neg_x = -octave_Inf;
06517 get_children_limits (minx, maxx, min_pos_x, max_neg_x, kids, 'x');
06518
06519 double miny = octave_Inf;
06520 double maxy = -octave_Inf;
06521 double min_pos_y = octave_Inf;
06522 double max_neg_y = -octave_Inf;
06523 get_children_limits (miny, maxy, min_pos_y, max_neg_y, kids, 'y');
06524
06525 if (! xscale_is ("log"))
06526 {
06527 xlims (0) += delta_x;
06528 xlims (1) += delta_x;
06529 }
06530
06531 if (! yscale_is ("log"))
06532 {
06533 ylims (0) += delta_y;
06534 ylims (1) += delta_y;
06535 }
06536
06537 zoom (xlims, ylims, false);
06538 }
06539
06540 void
06541 axes::properties::rotate_view (double delta_el, double delta_az)
06542 {
06543 Matrix v = get_view ().matrix_value ();
06544
06545 v (1) += delta_el;
06546
06547 if(v(1) > 90)
06548 v(1) = 90;
06549 if(v(1) < -90)
06550 v(1) = -90;
06551
06552 v (0) = fmod(v(0) - delta_az + 720,360);
06553
06554 set_view(v);
06555 update_transform();
06556 }
06557
06558 void
06559 axes::properties::unzoom (void)
06560 {
06561 if (zoom_stack.size () >= 4)
06562 {
06563 ylim = zoom_stack.front ();
06564 zoom_stack.pop_front ();
06565 ylimmode = zoom_stack.front ();
06566 zoom_stack.pop_front ();
06567 xlim = zoom_stack.front ();
06568 zoom_stack.pop_front ();
06569 xlimmode = zoom_stack.front ();
06570 zoom_stack.pop_front ();
06571
06572 update_transform ();
06573 update_xlim (false);
06574 update_ylim (false);
06575 }
06576 }
06577
06578 void
06579 axes::properties::clear_zoom_stack (void)
06580 {
06581 while (zoom_stack.size () > 4)
06582 zoom_stack.pop_front ();
06583
06584 unzoom ();
06585 }
06586
06587 void
06588 axes::reset_default_properties (void)
06589 {
06590 ::reset_default_properties (default_properties);
06591 }
06592
06593 void
06594 axes::initialize (const graphics_object& go)
06595 {
06596 base_graphics_object::initialize (go);
06597
06598 xinitialize (xproperties.get_title ());
06599 xinitialize (xproperties.get_xlabel ());
06600 xinitialize (xproperties.get_ylabel ());
06601 xinitialize (xproperties.get_zlabel ());
06602 }
06603
06604
06605
06606 Matrix
06607 line::properties::compute_xlim (void) const
06608 {
06609 Matrix m (1, 4);
06610
06611 m(0) = xdata.min_val ();
06612 m(1) = xdata.max_val ();
06613 m(2) = xdata.min_pos ();
06614 m(3) = xdata.max_neg ();
06615
06616 return m;
06617 }
06618
06619 Matrix
06620 line::properties::compute_ylim (void) const
06621 {
06622 Matrix m (1, 4);
06623
06624 m(0) = ydata.min_val ();
06625 m(1) = ydata.max_val ();
06626 m(2) = ydata.min_pos ();
06627 m(3) = ydata.max_neg ();
06628
06629 return m;
06630 }
06631
06632
06633
06634 Matrix
06635 text::properties::get_data_position (void) const
06636 {
06637 Matrix pos = get_position ().matrix_value ();
06638
06639 if (! units_is ("data"))
06640 pos = convert_text_position (pos, *this, get_units (), "data");
06641
06642 return pos;
06643 }
06644
06645 Matrix
06646 text::properties::get_extent_matrix (void) const
06647 {
06648 return extent.get ().matrix_value ();
06649 }
06650
06651 octave_value
06652 text::properties::get_extent (void) const
06653 {
06654 Matrix m = extent.get ().matrix_value ();
06655
06656 return convert_text_position (m, *this, "pixels", get_units ());
06657 }
06658
06659 void
06660 text::properties::update_font (void)
06661 {
06662 #ifdef HAVE_FREETYPE
06663 #ifdef HAVE_FONTCONFIG
06664 renderer.set_font (get ("fontname").string_value (),
06665 get ("fontweight").string_value (),
06666 get ("fontangle").string_value (),
06667 get ("fontsize").double_value ());
06668 #endif
06669 renderer.set_color (get_color_rgb ());
06670 #endif
06671 }
06672
06673 void
06674 text::properties::update_text_extent (void)
06675 {
06676 #ifdef HAVE_FREETYPE
06677
06678 int halign = 0, valign = 0;
06679
06680 if (horizontalalignment_is ("center"))
06681 halign = 1;
06682 else if (horizontalalignment_is ("right"))
06683 halign = 2;
06684
06685 if (verticalalignment_is ("top"))
06686 valign = 2;
06687 else if (verticalalignment_is ("baseline"))
06688 valign = 3;
06689 else if (verticalalignment_is ("middle"))
06690 valign = 1;
06691
06692 Matrix bbox;
06693
06694
06695
06696 octave_value string_prop = get_string ();
06697
06698 string_vector sv = string_prop.all_strings ();
06699
06700 renderer.text_to_pixels (sv.join ("\n"), pixels, bbox,
06701 halign, valign, get_rotation ());
06702 set_extent (bbox);
06703
06704 #endif
06705
06706 if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel") ||
06707 autopos_tag_is ("zlabel") || autopos_tag_is ("title"))
06708 update_autopos ("sync");
06709 }
06710
06711 void
06712 text::properties::request_autopos (void)
06713 {
06714 if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel") ||
06715 autopos_tag_is ("zlabel") || autopos_tag_is ("title"))
06716 update_autopos (get_autopos_tag ());
06717 }
06718
06719 void
06720 text::properties::update_units (void)
06721 {
06722 if (! units_is ("data"))
06723 {
06724 set_xliminclude ("off");
06725 set_yliminclude ("off");
06726 set_zliminclude ("off");
06727 }
06728
06729 Matrix pos = get_position ().matrix_value ();
06730
06731 pos = convert_text_position (pos, *this, cached_units, get_units ());
06732
06733
06734
06735 set_position (pos);
06736
06737 if (units_is ("data"))
06738 {
06739 set_xliminclude ("on");
06740 set_yliminclude ("on");
06741
06742 set_zliminclude ("off");
06743 }
06744
06745 cached_units = get_units ();
06746 }
06747
06748 double
06749 text::properties::get_fontsize_points (double box_pix_height) const
06750 {
06751 double fs = get_fontsize ();
06752 double parent_height = box_pix_height;
06753
06754 if (fontunits_is ("normalized") && parent_height <= 0)
06755 {
06756 graphics_object go (gh_manager::get_object (get___myhandle__ ()));
06757 graphics_object ax (go.get_ancestor ("axes"));
06758
06759 parent_height = ax.get_properties ().get_boundingbox (true).elem(3);
06760 }
06761
06762 return convert_font_size (fs, get_fontunits (), "points", parent_height);
06763 }
06764
06765
06766
06767 octave_value
06768 image::properties::get_color_data (void) const
06769 {
06770 return convert_cdata (*this, get_cdata (),
06771 cdatamapping_is ("scaled"), 3);
06772 }
06773
06774
06775
06776 octave_value
06777 patch::properties::get_color_data (void) const
06778 {
06779 octave_value fvc = get_facevertexcdata();
06780 if (fvc.is_undefined () || fvc.is_empty ())
06781 return Matrix ();
06782 else
06783 return convert_cdata (*this, fvc,cdatamapping_is ("scaled"), 2);
06784 }
06785
06786
06787
06788 octave_value
06789 surface::properties::get_color_data (void) const
06790 {
06791 return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
06792 }
06793
06794 inline void
06795 cross_product (double x1, double y1, double z1,
06796 double x2, double y2, double z2,
06797 double& x, double& y, double& z)
06798 {
06799 x += (y1 * z2 - z1 * y2);
06800 y += (z1 * x2 - x1 * z2);
06801 z += (x1 * y2 - y1 * x2);
06802 }
06803
06804 void
06805 surface::properties::update_normals (void)
06806 {
06807 if (normalmode_is ("auto"))
06808 {
06809 Matrix x = get_xdata ().matrix_value ();
06810 Matrix y = get_ydata ().matrix_value ();
06811 Matrix z = get_zdata ().matrix_value ();
06812
06813
06814 int p = z.columns (), q = z.rows ();
06815 int i1 = 0, i2 = 0, i3 = 0;
06816 int j1 = 0, j2 = 0, j3 = 0;
06817
06818 bool x_mat = (x.rows () == q);
06819 bool y_mat = (y.columns () == p);
06820
06821 NDArray n (dim_vector (q, p, 3), 0.0);
06822
06823 for (int i = 0; i < p; i++)
06824 {
06825 if (y_mat)
06826 {
06827 i1 = i - 1;
06828 i2 = i;
06829 i3 = i + 1;
06830 }
06831
06832 for (int j = 0; j < q; j++)
06833 {
06834 if (x_mat)
06835 {
06836 j1 = j - 1;
06837 j2 = j;
06838 j3 = j + 1;
06839 }
06840
06841 double& nx = n(j, i, 0);
06842 double& ny = n(j, i, 1);
06843 double& nz = n(j, i, 2);
06844
06845 if ((j > 0) && (i > 0))
06846
06847 cross_product (x(j1,i-1)-x(j2,i), y(j-1,i1)-y(j,i2), z(j-1,i-1)-z(j,i),
06848 x(j2,i-1)-x(j1,i), y(j,i1)-y(j-1,i2), z(j,i-1)-z(j-1,i),
06849 nx, ny, nz);
06850
06851 if ((j > 0) && (i < (p -1)))
06852
06853 cross_product (x(j1,i+1)-x(j2,i), y(j-1,i3)-y(j,i2), z(j-1,i+1)-z(j,i),
06854 x(j1,i)-x(j2,i+1), y(j-1,i2)-y(j,i3), z(j-1,i)-z(j,i+1),
06855 nx, ny, nz);
06856
06857 if ((j < (q - 1)) && (i > 0))
06858
06859 cross_product (x(j2,i-1)-x(j3,i), y(j,i1)-y(j+1,i2), z(j,i-1)-z(j+1,i),
06860 x(j3,i-1)-x(j2,i), y(j+1,i1)-y(j,i2), z(j+1,i-1)-z(j,i),
06861 nx, ny, nz);
06862
06863 if ((j < (q - 1)) && (i < (p -1)))
06864
06865 cross_product (x(j3,i)-x(j2,i+1), y(j+1,i2)-y(j,i3), z(j+1,i)-z(j,i+1),
06866 x(j3,i+1)-x(j2,i), y(j+1,i3)-y(j,i2), z(j+1,i+1)-z(j,i),
06867 nx, ny, nz);
06868
06869 double d = -std::max (std::max (fabs (nx), fabs (ny)), fabs (nz));
06870
06871 nx /= d;
06872 ny /= d;
06873 nz /= d;
06874 }
06875 }
06876 vertexnormals = n;
06877 }
06878 }
06879
06880
06881
06882 void
06883 hggroup::properties::update_limits (void) const
06884 {
06885 graphics_object obj = gh_manager::get_object (__myhandle__);
06886
06887 if (obj)
06888 {
06889 obj.update_axis_limits ("xlim");
06890 obj.update_axis_limits ("ylim");
06891 obj.update_axis_limits ("zlim");
06892 obj.update_axis_limits ("clim");
06893 obj.update_axis_limits ("alim");
06894 }
06895 }
06896
06897 void
06898 hggroup::properties::update_limits (const graphics_handle& h) const
06899 {
06900 graphics_object obj = gh_manager::get_object (__myhandle__);
06901
06902 if (obj)
06903 {
06904 obj.update_axis_limits ("xlim", h);
06905 obj.update_axis_limits ("ylim", h);
06906 obj.update_axis_limits ("zlim", h);
06907 obj.update_axis_limits ("clim", h);
06908 obj.update_axis_limits ("alim", h);
06909 }
06910 }
06911
06912 static bool updating_hggroup_limits = false;
06913
06914 void
06915 hggroup::update_axis_limits (const std::string& axis_type,
06916 const graphics_handle& h)
06917 {
06918 if (updating_hggroup_limits)
06919 return;
06920
06921 Matrix kids = Matrix (1, 1, h.value ());
06922
06923 double min_val = octave_Inf;
06924 double max_val = -octave_Inf;
06925 double min_pos = octave_Inf;
06926 double max_neg = -octave_Inf;
06927
06928 Matrix limits;
06929 double val;
06930
06931 char update_type = 0;
06932
06933 if (axis_type == "xlim" || axis_type == "xliminclude")
06934 {
06935 limits = xproperties.get_xlim ().matrix_value ();
06936 update_type = 'x';
06937 }
06938 else if (axis_type == "ylim" || axis_type == "yliminclude")
06939 {
06940 limits = xproperties.get_ylim ().matrix_value ();
06941 update_type = 'y';
06942 }
06943 else if (axis_type == "zlim" || axis_type == "zliminclude")
06944 {
06945 limits = xproperties.get_zlim ().matrix_value ();
06946 update_type = 'z';
06947 }
06948 else if (axis_type == "clim" || axis_type == "climinclude")
06949 {
06950 limits = xproperties.get_clim ().matrix_value ();
06951 update_type = 'c';
06952 }
06953 else if (axis_type == "alim" || axis_type == "aliminclude")
06954 {
06955 limits = xproperties.get_alim ().matrix_value ();
06956 update_type = 'a';
06957 }
06958
06959 if (limits.numel() == 4)
06960 {
06961 val = limits(0);
06962 if (! (xisinf (val) || xisnan (val)))
06963 min_val = val;
06964 val = limits(1);
06965 if (! (xisinf (val) || xisnan (val)))
06966 max_val = val;
06967 val = limits(2);
06968 if (! (xisinf (val) || xisnan (val)))
06969 min_pos = val;
06970 val = limits(3);
06971 if (! (xisinf (val) || xisnan (val)))
06972 max_neg = val;
06973 }
06974 else
06975 {
06976 limits.resize(4,1);
06977 limits(0) = min_val;
06978 limits(1) = max_val;
06979 limits(2) = min_pos;
06980 limits(3) = max_neg;
06981 }
06982
06983 get_children_limits (min_val, max_val, min_pos, max_neg, kids, update_type);
06984
06985 unwind_protect frame;
06986 frame.protect_var (updating_hggroup_limits);
06987
06988 updating_hggroup_limits = true;
06989
06990 if (limits(0) != min_val || limits(1) != max_val
06991 || limits(2) != min_pos || limits(3) != max_neg)
06992 {
06993 limits(0) = min_val;
06994 limits(1) = max_val;
06995 limits(2) = min_pos;
06996 limits(3) = max_neg;
06997
06998 switch (update_type)
06999 {
07000 case 'x':
07001 xproperties.set_xlim (limits);
07002 break;
07003
07004 case 'y':
07005 xproperties.set_ylim (limits);
07006 break;
07007
07008 case 'z':
07009 xproperties.set_zlim (limits);
07010 break;
07011
07012 case 'c':
07013 xproperties.set_clim (limits);
07014 break;
07015
07016 case 'a':
07017 xproperties.set_alim (limits);
07018 break;
07019
07020 default:
07021 break;
07022 }
07023
07024 base_graphics_object::update_axis_limits (axis_type, h);
07025 }
07026 }
07027
07028 void
07029 hggroup::update_axis_limits (const std::string& axis_type)
07030 {
07031 if (updating_hggroup_limits)
07032 return;
07033
07034 Matrix kids = xproperties.get_children ();
07035
07036 double min_val = octave_Inf;
07037 double max_val = -octave_Inf;
07038 double min_pos = octave_Inf;
07039 double max_neg = -octave_Inf;
07040
07041 char update_type = 0;
07042
07043 if (axis_type == "xlim" || axis_type == "xliminclude")
07044 {
07045 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'x');
07046
07047 update_type = 'x';
07048 }
07049 else if (axis_type == "ylim" || axis_type == "yliminclude")
07050 {
07051 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'y');
07052
07053 update_type = 'y';
07054 }
07055 else if (axis_type == "zlim" || axis_type == "zliminclude")
07056 {
07057 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'z');
07058
07059 update_type = 'z';
07060 }
07061 else if (axis_type == "clim" || axis_type == "climinclude")
07062 {
07063 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'c');
07064
07065 update_type = 'c';
07066 }
07067 else if (axis_type == "alim" || axis_type == "aliminclude")
07068 {
07069 get_children_limits (min_val, max_val, min_pos, max_neg, kids, 'a');
07070
07071 update_type = 'a';
07072 }
07073
07074 unwind_protect frame;
07075 frame.protect_var (updating_hggroup_limits);
07076
07077 updating_hggroup_limits = true;
07078
07079 Matrix limits (1, 4, 0.0);
07080
07081 limits(0) = min_val;
07082 limits(1) = max_val;
07083 limits(2) = min_pos;
07084 limits(3) = max_neg;
07085
07086 switch (update_type)
07087 {
07088 case 'x':
07089 xproperties.set_xlim (limits);
07090 break;
07091
07092 case 'y':
07093 xproperties.set_ylim (limits);
07094 break;
07095
07096 case 'z':
07097 xproperties.set_zlim (limits);
07098 break;
07099
07100 case 'c':
07101 xproperties.set_clim (limits);
07102 break;
07103
07104 case 'a':
07105 xproperties.set_alim (limits);
07106 break;
07107
07108 default:
07109 break;
07110 }
07111
07112 base_graphics_object::update_axis_limits (axis_type);
07113 }
07114
07115
07116
07117 octave_value
07118 uicontrol::properties::get_extent (void) const
07119 {
07120 Matrix m = extent.get ().matrix_value ();
07121
07122 graphics_object parent_obj =
07123 gh_manager::get_object (get_parent ());
07124 Matrix parent_bbox = parent_obj.get_properties ().get_boundingbox (true),
07125 parent_size = parent_bbox.extract_n (0, 2, 1, 2);
07126
07127 return convert_position (m, "pixels", get_units (), parent_size);
07128 }
07129
07130 void
07131 uicontrol::properties::update_text_extent (void)
07132 {
07133 #ifdef HAVE_FREETYPE
07134
07135 text_element *elt;
07136 ft_render text_renderer;
07137 Matrix box;
07138
07139
07140
07141
07142 elt = text_parser_none ().parse (get_string_string ());
07143 #ifdef HAVE_FONTCONFIG
07144 text_renderer.set_font (get_fontname (),
07145 get_fontweight (),
07146 get_fontangle (),
07147 get_fontsize ());
07148 #endif
07149 box = text_renderer.get_extent (elt, 0);
07150
07151 Matrix ext (1, 4, 0.0);
07152
07153
07154
07155 ext(0) = ext(1) = 1;
07156 ext(2) = box(0);
07157 ext(3) = box(1);
07158
07159 set_extent (ext);
07160
07161 #endif
07162 }
07163
07164 void
07165 uicontrol::properties::update_units (void)
07166 {
07167 Matrix pos = get_position ().matrix_value ();
07168
07169 graphics_object parent_obj = gh_manager::get_object (get_parent ());
07170 Matrix parent_bbox = parent_obj.get_properties ().get_boundingbox (true),
07171 parent_size = parent_bbox.extract_n (0, 2, 1, 2);
07172
07173 pos = convert_position (pos, cached_units, get_units (), parent_size);
07174 set_position (pos);
07175
07176 cached_units = get_units ();
07177 }
07178
07179 void
07180 uicontrol::properties::set_style (const octave_value& st)
07181 {
07182 if (get___object__ ().is_empty())
07183 style = st;
07184 else
07185 error ("set: cannot change the style of a uicontrol object after creation.");
07186 }
07187
07188 Matrix
07189 uicontrol::properties::get_boundingbox (bool,
07190 const Matrix& parent_pix_size) const
07191 {
07192 Matrix pos = get_position ().matrix_value ();
07193 Matrix parent_size (parent_pix_size);
07194
07195 if (parent_size.numel () == 0)
07196 {
07197 graphics_object obj = gh_manager::get_object (get_parent ());
07198
07199 parent_size =
07200 obj.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
07201 }
07202
07203 pos = convert_position (pos, get_units (), "pixels", parent_size);
07204
07205 pos(0)--;
07206 pos(1)--;
07207 pos(1) = parent_size(1) - pos(1) - pos(3);
07208
07209 return pos;
07210 }
07211
07212 void
07213 uicontrol::properties::set_fontunits (const octave_value& v)
07214 {
07215 if (! error_state)
07216 {
07217 caseless_str old_fontunits = get_fontunits ();
07218 if (fontunits.set (v, true))
07219 {
07220 update_fontunits (old_fontunits);
07221 mark_modified ();
07222 }
07223 }
07224 }
07225
07226 void
07227 uicontrol::properties::update_fontunits (const caseless_str& old_units)
07228 {
07229 caseless_str new_units = get_fontunits ();
07230 double parent_height = get_boundingbox (false).elem (3);
07231 double fsz = get_fontsize ();
07232
07233 fsz = convert_font_size (fsz, old_units, new_units, parent_height);
07234
07235 fontsize.set (octave_value (fsz), true);
07236 }
07237
07238 double
07239 uicontrol::properties::get_fontsize_points (double box_pix_height) const
07240 {
07241 double fs = get_fontsize ();
07242 double parent_height = box_pix_height;
07243
07244 if (fontunits_is ("normalized") && parent_height <= 0)
07245 parent_height = get_boundingbox (false).elem(3);
07246
07247 return convert_font_size (fs, get_fontunits (), "points", parent_height);
07248 }
07249
07250
07251
07252 Matrix
07253 uipanel::properties::get_boundingbox (bool internal,
07254 const Matrix& parent_pix_size) const
07255 {
07256 Matrix pos = get_position ().matrix_value ();
07257 Matrix parent_size (parent_pix_size);
07258
07259 if (parent_size.numel () == 0)
07260 {
07261 graphics_object obj = gh_manager::get_object (get_parent ());
07262
07263 parent_size =
07264 obj.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
07265 }
07266
07267 pos = convert_position (pos, get_units (), "pixels", parent_size);
07268
07269 pos(0)--;
07270 pos(1)--;
07271 pos(1) = parent_size(1) - pos(1) - pos(3);
07272
07273 if (internal)
07274 {
07275 double outer_height = pos(3);
07276
07277 pos(0) = pos(1) = 0;
07278
07279 if (! bordertype_is ("none"))
07280 {
07281 double bw = get_borderwidth ();
07282 double mul = 1.0;
07283
07284 if (bordertype_is ("etchedin") || bordertype_is ("etchedout"))
07285 mul = 2.0;
07286
07287 pos(0) += mul * bw;
07288 pos(1) += mul * bw;
07289 pos(2) -= 2 * mul * bw;
07290 pos(3) -= 2 * mul * bw;
07291 }
07292
07293 if (! get_title ().empty ())
07294 {
07295 double fs = get_fontsize ();
07296
07297 if (! fontunits_is ("pixels"))
07298 {
07299 double res = xget (0, "screenpixelsperinch").double_value ();
07300
07301 if (fontunits_is ("points"))
07302 fs *= (res / 72.0);
07303 else if (fontunits_is ("inches"))
07304 fs *= res;
07305 else if (fontunits_is ("centimeters"))
07306 fs *= (res / 2.54);
07307 else if (fontunits_is ("normalized"))
07308 fs *= outer_height;
07309 }
07310
07311 if (titleposition_is ("lefttop") || titleposition_is ("centertop")
07312 || titleposition_is ("righttop"))
07313 pos(1) += (fs / 2);
07314 pos(3) -= (fs / 2);
07315 }
07316 }
07317
07318 return pos;
07319 }
07320
07321 void
07322 uipanel::properties::set_units (const octave_value& v)
07323 {
07324 if (! error_state)
07325 {
07326 caseless_str old_units = get_units ();
07327 if (units.set (v, true))
07328 {
07329 update_units (old_units);
07330 mark_modified ();
07331 }
07332 }
07333 }
07334
07335 void
07336 uipanel::properties::update_units (const caseless_str& old_units)
07337 {
07338 Matrix pos = get_position ().matrix_value ();
07339
07340 graphics_object parent_obj = gh_manager::get_object (get_parent ());
07341 Matrix parent_bbox = parent_obj.get_properties ().get_boundingbox (true),
07342 parent_size = parent_bbox.extract_n (0, 2, 1, 2);
07343
07344 pos = convert_position (pos, old_units, get_units (), parent_size);
07345 set_position (pos);
07346 }
07347
07348 void
07349 uipanel::properties::set_fontunits (const octave_value& v)
07350 {
07351 if (! error_state)
07352 {
07353 caseless_str old_fontunits = get_fontunits ();
07354 if (fontunits.set (v, true))
07355 {
07356 update_fontunits (old_fontunits);
07357 mark_modified ();
07358 }
07359 }
07360 }
07361
07362 void
07363 uipanel::properties::update_fontunits (const caseless_str& old_units)
07364 {
07365 caseless_str new_units = get_fontunits ();
07366 double parent_height = get_boundingbox (false).elem (3);
07367 double fsz = get_fontsize ();
07368
07369 fsz = convert_font_size (fsz, old_units, new_units, parent_height);
07370
07371 set_fontsize (octave_value (fsz));
07372 }
07373
07374 double
07375 uipanel::properties::get_fontsize_points (double box_pix_height) const
07376 {
07377 double fs = get_fontsize ();
07378 double parent_height = box_pix_height;
07379
07380 if (fontunits_is ("normalized") && parent_height <= 0)
07381 parent_height = get_boundingbox (false).elem(3);
07382
07383 return convert_font_size (fs, get_fontunits (), "points", parent_height);
07384 }
07385
07386
07387
07388 octave_value
07389 uitoolbar::get_default (const caseless_str& name) const
07390 {
07391 octave_value retval = default_properties.lookup (name);
07392
07393 if (retval.is_undefined ())
07394 {
07395 graphics_handle parent = get_parent ();
07396 graphics_object parent_obj = gh_manager::get_object (parent);
07397
07398 retval = parent_obj.get_default (name);
07399 }
07400
07401 return retval;
07402 }
07403
07404 void
07405 uitoolbar::reset_default_properties (void)
07406 {
07407 ::reset_default_properties (default_properties);
07408 }
07409
07410
07411
07412 octave_value
07413 base_graphics_object::get_default (const caseless_str& name) const
07414 {
07415 graphics_handle parent = get_parent ();
07416 graphics_object parent_obj = gh_manager::get_object (parent);
07417
07418 return parent_obj.get_default (type () + name);
07419 }
07420
07421 octave_value
07422 base_graphics_object::get_factory_default (const caseless_str& name) const
07423 {
07424 graphics_object parent_obj = gh_manager::get_object (0);
07425
07426 return parent_obj.get_factory_default (type () + name);
07427 }
07428
07429
07430
07431 gh_manager::gh_manager (void)
07432 : handle_map (), handle_free_list (),
07433 next_handle (-1.0 - (rand () + 1.0) / (RAND_MAX + 2.0)),
07434 figure_list (), graphics_lock (), event_queue (),
07435 callback_objects (), event_processing (0)
07436 {
07437 handle_map[0] = graphics_object (new root_figure ());
07438
07439
07440 gtk_manager::default_toolkit ();
07441 }
07442
07443 void
07444 gh_manager::create_instance (void)
07445 {
07446 instance = new gh_manager ();
07447
07448 if (instance)
07449 singleton_cleanup_list::add (cleanup_instance);
07450 }
07451
07452 graphics_handle
07453 gh_manager::do_make_graphics_handle (const std::string& go_name,
07454 const graphics_handle& p,
07455 bool integer_figure_handle,
07456 bool do_createfcn,
07457 bool do_notify_toolkit)
07458 {
07459 graphics_handle h = get_handle (integer_figure_handle);
07460
07461 base_graphics_object *go = 0;
07462
07463 go = make_graphics_object_from_type (go_name, h, p);
07464
07465 if (go)
07466 {
07467 graphics_object obj (go);
07468
07469 handle_map[h] = obj;
07470 if (do_createfcn)
07471 go->get_properties ().execute_createfcn ();
07472
07473
07474 if (do_notify_toolkit)
07475 obj.initialize ();
07476 }
07477 else
07478 error ("gh_manager::do_make_graphics_handle: invalid object type '%s'",
07479 go_name.c_str ());
07480
07481 return h;
07482 }
07483
07484 graphics_handle
07485 gh_manager::do_make_figure_handle (double val, bool do_notify_toolkit)
07486 {
07487 graphics_handle h = val;
07488
07489 base_graphics_object* go = new figure (h, 0);
07490 graphics_object obj (go);
07491
07492 handle_map[h] = obj;
07493
07494
07495 if (do_notify_toolkit)
07496 obj.initialize ();
07497
07498 return h;
07499 }
07500
07501 void
07502 gh_manager::do_push_figure (const graphics_handle& h)
07503 {
07504 do_pop_figure (h);
07505
07506 figure_list.push_front (h);
07507 }
07508
07509 void
07510 gh_manager::do_pop_figure (const graphics_handle& h)
07511 {
07512 for (figure_list_iterator p = figure_list.begin ();
07513 p != figure_list.end ();
07514 p++)
07515 {
07516 if (*p == h)
07517 {
07518 figure_list.erase (p);
07519 break;
07520 }
07521 }
07522 }
07523
07524 class
07525 callback_event : public base_graphics_event
07526 {
07527 public:
07528 callback_event (const graphics_handle& h, const std::string& name,
07529 const octave_value& data = Matrix ())
07530 : base_graphics_event (), handle (h), callback_name (name),
07531 callback (), callback_data (data) { }
07532
07533 callback_event (const graphics_handle& h, const octave_value& cb,
07534 const octave_value& data = Matrix ())
07535 : base_graphics_event (), handle (h), callback_name (),
07536 callback (cb), callback_data (data) { }
07537
07538 void execute (void)
07539 {
07540 if (callback.is_defined ())
07541 gh_manager::execute_callback (handle, callback, callback_data);
07542 else
07543 gh_manager::execute_callback (handle, callback_name, callback_data);
07544 }
07545
07546 private:
07547 callback_event (void)
07548 : base_graphics_event (), handle (),
07549 callback_name (), callback_data ()
07550 { }
07551
07552 private:
07553 graphics_handle handle;
07554 std::string callback_name;
07555 octave_value callback;
07556 octave_value callback_data;
07557 };
07558
07559 class
07560 function_event : public base_graphics_event
07561 {
07562 public:
07563 function_event (graphics_event::event_fcn fcn, void* data = 0)
07564 : base_graphics_event (), function (fcn),
07565 function_data (data) { }
07566
07567 void execute (void)
07568 {
07569 function (function_data);
07570 }
07571
07572 private:
07573
07574 graphics_event::event_fcn function;
07575
07576 void* function_data;
07577
07578
07579 function_event (void);
07580
07581
07582
07583 function_event (const function_event &);
07584
07585 function_event & operator = (const function_event &);
07586 };
07587
07588 class
07589 set_event : public base_graphics_event
07590 {
07591 public:
07592 set_event (const graphics_handle& h, const std::string& name,
07593 const octave_value& value, bool do_notify_toolkit = true)
07594 : base_graphics_event (), handle (h), property_name (name),
07595 property_value (value), notify_toolkit (do_notify_toolkit) { }
07596
07597 void execute (void)
07598 {
07599 gh_manager::auto_lock guard;
07600
07601 graphics_object go = gh_manager::get_object (handle);
07602
07603 if (go)
07604 {
07605 property p = go.get_properties ().get_property (property_name);
07606
07607 if (p.ok ())
07608 p.set (property_value, true, notify_toolkit);
07609 }
07610 }
07611
07612 private:
07613 set_event (void)
07614 : base_graphics_event (), handle (), property_name (), property_value ()
07615 { }
07616
07617 private:
07618 graphics_handle handle;
07619 std::string property_name;
07620 octave_value property_value;
07621 bool notify_toolkit;
07622 };
07623
07624 graphics_event
07625 graphics_event::create_callback_event (const graphics_handle& h,
07626 const std::string& name,
07627 const octave_value& data)
07628 {
07629 graphics_event e;
07630
07631 e.rep = new callback_event (h, name, data);
07632
07633 return e;
07634 }
07635
07636 graphics_event
07637 graphics_event::create_callback_event (const graphics_handle& h,
07638 const octave_value& cb,
07639 const octave_value& data)
07640 {
07641 graphics_event e;
07642
07643 e.rep = new callback_event (h, cb, data);
07644
07645 return e;
07646 }
07647
07648 graphics_event
07649 graphics_event::create_function_event (graphics_event::event_fcn fcn,
07650 void *data)
07651 {
07652 graphics_event e;
07653
07654 e.rep = new function_event (fcn, data);
07655
07656 return e;
07657 }
07658
07659 graphics_event
07660 graphics_event::create_set_event (const graphics_handle& h,
07661 const std::string& name,
07662 const octave_value& data,
07663 bool notify_toolkit)
07664 {
07665 graphics_event e;
07666
07667 e.rep = new set_event (h, name, data, notify_toolkit);
07668
07669 return e;
07670 }
07671
07672 static void
07673 xset_gcbo (const graphics_handle& h)
07674 {
07675 graphics_object go = gh_manager::get_object (0);
07676 root_figure::properties& props =
07677 dynamic_cast<root_figure::properties&> (go.get_properties ());
07678
07679 props.set_callbackobject (h.as_octave_value ());
07680 }
07681
07682 void
07683 gh_manager::do_restore_gcbo (void)
07684 {
07685 gh_manager::auto_lock guard;
07686
07687 callback_objects.pop_front ();
07688
07689 xset_gcbo (callback_objects.empty ()
07690 ? graphics_handle ()
07691 : callback_objects.front ().get_handle ());
07692 }
07693
07694 void
07695 gh_manager::do_execute_listener (const graphics_handle& h,
07696 const octave_value& l)
07697 {
07698 if (octave_thread::is_octave_thread ())
07699 gh_manager::execute_callback (h, l, octave_value ());
07700 else
07701 {
07702 gh_manager::auto_lock guard;
07703
07704 do_post_event (graphics_event::create_callback_event (h, l));
07705 }
07706 }
07707
07708 void
07709 gh_manager::do_execute_callback (const graphics_handle& h,
07710 const octave_value& cb_arg,
07711 const octave_value& data)
07712 {
07713 if (cb_arg.is_defined () && ! cb_arg.is_empty ())
07714 {
07715 octave_value_list args;
07716 octave_function *fcn = 0;
07717
07718 args(0) = h.as_octave_value ();
07719 if (data.is_defined ())
07720 args(1) = data;
07721 else
07722 args(1) = Matrix ();
07723
07724 unwind_protect_safe frame;
07725 frame.add_fcn (gh_manager::restore_gcbo);
07726
07727 if (true)
07728 {
07729 gh_manager::auto_lock guard;
07730
07731 callback_objects.push_front (get_object (h));
07732 xset_gcbo (h);
07733 }
07734
07735 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
07736
07737
07738
07739 octave_value cb = cb_arg;
07740
07741 if (cb.is_function () || cb.is_function_handle ())
07742 fcn = cb.function_value ();
07743 else if (cb.is_string ())
07744 {
07745 int status;
07746 std::string s = cb.string_value ();
07747
07748 eval_string (s, false, status, 0);
07749 }
07750 else if (cb.is_cell () && cb.length () > 0
07751 && (cb.rows () == 1 || cb.columns () == 1)
07752 && (cb.cell_value ()(0).is_function ()
07753 || cb.cell_value ()(0).is_function_handle ()))
07754 {
07755 Cell c = cb.cell_value ();
07756
07757 fcn = c(0).function_value ();
07758 if (! error_state)
07759 {
07760 for (int i = 1; i < c.length () ; i++)
07761 args(1+i) = c(i);
07762 }
07763 }
07764 else
07765 {
07766 std::string nm = cb.class_name ();
07767 error ("trying to execute non-executable object (class = %s)",
07768 nm.c_str ());
07769 }
07770
07771 if (fcn && ! error_state)
07772 feval (fcn, args);
07773
07774 END_INTERRUPT_WITH_EXCEPTIONS;
07775 }
07776 }
07777
07778 void
07779 gh_manager::do_post_event (const graphics_event& e)
07780 {
07781 event_queue.push_back (e);
07782
07783 command_editor::add_event_hook (gh_manager::process_events);
07784 }
07785
07786 void
07787 gh_manager::do_post_callback (const graphics_handle& h, const std::string name,
07788 const octave_value& data)
07789 {
07790 gh_manager::auto_lock guard;
07791
07792 graphics_object go = get_object (h);
07793
07794 if (go.valid_object ())
07795 {
07796 if (callback_objects.empty ())
07797 do_post_event (graphics_event::create_callback_event (h, name, data));
07798 else
07799 {
07800 const graphics_object& current = callback_objects.front ();
07801
07802 if (current.get_properties ().is_interruptible ())
07803 do_post_event (graphics_event::create_callback_event (h, name, data));
07804 else
07805 {
07806 caseless_str busy_action (go.get_properties ().get_busyaction ());
07807
07808 if (busy_action.compare ("queue"))
07809 do_post_event (graphics_event::create_callback_event (h, name, data));
07810 else
07811 {
07812 caseless_str cname (name);
07813
07814 if (cname.compare ("deletefcn")
07815 || cname.compare ("createfcn")
07816 || (go.isa ("figure")
07817 && (cname.compare ("closerequestfcn")
07818 || cname.compare ("resizefcn"))))
07819 do_post_event (graphics_event::create_callback_event (h, name, data));
07820 }
07821 }
07822 }
07823 }
07824 }
07825
07826 void
07827 gh_manager::do_post_function (graphics_event::event_fcn fcn, void* fcn_data)
07828 {
07829 gh_manager::auto_lock guard;
07830
07831 do_post_event (graphics_event::create_function_event (fcn, fcn_data));
07832 }
07833
07834 void
07835 gh_manager::do_post_set (const graphics_handle& h, const std::string name,
07836 const octave_value& value, bool notify_toolkit)
07837 {
07838 gh_manager::auto_lock guard;
07839
07840 do_post_event (graphics_event::create_set_event (h, name, value,
07841 notify_toolkit));
07842 }
07843
07844 int
07845 gh_manager::do_process_events (bool force)
07846 {
07847 graphics_event e;
07848 bool old_Vdrawnow_requested = Vdrawnow_requested;
07849 bool events_executed = false;
07850
07851 do
07852 {
07853 e = graphics_event ();
07854
07855 gh_manager::lock ();
07856
07857 if (! event_queue.empty ())
07858 {
07859 if (callback_objects.empty () || force)
07860 {
07861 e = event_queue.front ();
07862
07863 event_queue.pop_front ();
07864 }
07865 else
07866 {
07867 const graphics_object& go = callback_objects.front ();
07868
07869 if (go.get_properties ().is_interruptible ())
07870 {
07871 e = event_queue.front ();
07872
07873 event_queue.pop_front ();
07874 }
07875 }
07876 }
07877
07878 gh_manager::unlock ();
07879
07880 if (e.ok ())
07881 {
07882 e.execute ();
07883 events_executed = true;
07884 }
07885 }
07886 while (e.ok ());
07887
07888 gh_manager::lock ();
07889
07890 if (event_queue.empty () && event_processing == 0)
07891 command_editor::remove_event_hook (gh_manager::process_events);
07892
07893 gh_manager::unlock ();
07894
07895 if (events_executed)
07896 flush_octave_stdout ();
07897
07898 if (Vdrawnow_requested && ! old_Vdrawnow_requested)
07899 {
07900 feval ("drawnow");
07901
07902 Vdrawnow_requested = false;
07903 }
07904
07905 return 0;
07906 }
07907
07908 void
07909 gh_manager::do_enable_event_processing (bool enable)
07910 {
07911 gh_manager::auto_lock guard;
07912
07913 if (enable)
07914 {
07915 event_processing++;
07916
07917 command_editor::add_event_hook (gh_manager::process_events);
07918 }
07919 else
07920 {
07921 event_processing--;
07922
07923 if (event_queue.empty () && event_processing == 0)
07924 command_editor::remove_event_hook (gh_manager::process_events);
07925 }
07926 }
07927
07928 property_list::plist_map_type
07929 root_figure::init_factory_properties (void)
07930 {
07931 property_list::plist_map_type plist_map;
07932
07933 plist_map["figure"] = figure::properties::factory_defaults ();
07934 plist_map["axes"] = axes::properties::factory_defaults ();
07935 plist_map["line"] = line::properties::factory_defaults ();
07936 plist_map["text"] = text::properties::factory_defaults ();
07937 plist_map["image"] = image::properties::factory_defaults ();
07938 plist_map["patch"] = patch::properties::factory_defaults ();
07939 plist_map["surface"] = surface::properties::factory_defaults ();
07940 plist_map["hggroup"] = hggroup::properties::factory_defaults ();
07941 plist_map["uimenu"] = uimenu::properties::factory_defaults ();
07942 plist_map["uicontrol"] = uicontrol::properties::factory_defaults ();
07943 plist_map["uipanel"] = uipanel::properties::factory_defaults ();
07944 plist_map["uicontextmenu"] = uicontextmenu::properties::factory_defaults ();
07945 plist_map["uitoolbar"] = uitoolbar::properties::factory_defaults ();
07946 plist_map["uipushtool"] = uipushtool::properties::factory_defaults ();
07947 plist_map["uitoggletool"] = uitoggletool::properties::factory_defaults ();
07948
07949 return plist_map;
07950 }
07951
07952
07953
07954 DEFUN (ishandle, args, ,
07955 "-*- texinfo -*-\n\
07956 @deftypefn {Built-in Function} {} ishandle (@var{h})\n\
07957 Return true if @var{h} is a graphics handle and false otherwise.\n\
07958 @var{h} may also be a matrix of handles in which case a logical\n\
07959 array is returned that is true where the elements of @var{h} are\n\
07960 graphics handles and false where they are not.\n\
07961 @seealso{isfigure}\n\
07962 @end deftypefn")
07963 {
07964 gh_manager::auto_lock guard;
07965
07966 octave_value retval;
07967
07968 if (args.length () == 1)
07969 retval = is_handle (args(0));
07970 else
07971 print_usage ();
07972
07973 return retval;
07974 }
07975
07976 static bool
07977 is_handle_visible (const graphics_handle& h)
07978 {
07979 return h.ok () && gh_manager::is_handle_visible (h);
07980 }
07981
07982 static bool
07983 is_handle_visible (double val)
07984 {
07985 return is_handle_visible (gh_manager::lookup (val));
07986 }
07987
07988 static octave_value
07989 is_handle_visible (const octave_value& val)
07990 {
07991 octave_value retval = false;
07992
07993 if (val.is_real_scalar () && is_handle_visible (val.double_value ()))
07994 retval = true;
07995 else if (val.is_numeric_type () && val.is_real_type ())
07996 {
07997 const NDArray handles = val.array_value ();
07998
07999 if (! error_state)
08000 {
08001 boolNDArray result (handles.dims ());
08002
08003 for (octave_idx_type i = 0; i < handles.numel (); i++)
08004 result.xelem (i) = is_handle_visible (handles (i));
08005
08006 retval = result;
08007 }
08008 }
08009
08010 return retval;
08011 }
08012
08013 DEFUN (__is_handle_visible__, args, ,
08014 "-*- texinfo -*-\n\
08015 @deftypefn {Built-in Function} __is_handle_visible__ (@var{h})\n\
08016 Undocumented internal function.\n\
08017 @end deftypefn")
08018 {
08019 octave_value retval;
08020
08021 if (args.length () == 1)
08022 retval = is_handle_visible (args(0));
08023 else
08024 print_usage ();
08025
08026 return retval;
08027 }
08028
08029 DEFUN (reset, args, ,
08030 "-*- texinfo -*-\n\
08031 @deftypefn {Built-in Function} {} reset (@var{h}, @var{property})\n\
08032 Remove any defaults set for the handle @var{h}. The default figure\n\
08033 properties of \"position\", \"units\", \"windowstyle\" and\n\
08034 \"paperunits\" and the default axes properties of \"position\" and \"units\"\n\
08035 are not reset.\n\
08036 @end deftypefn")
08037 {
08038 int nargin = args.length ();
08039
08040 if (nargin != 1)
08041 print_usage ();
08042 else
08043 {
08044
08045 ColumnVector hcv (args(0).vector_value ());
08046
08047 if (! error_state)
08048 {
08049
08050 for (octave_idx_type n = 0; n < hcv.length (); n++)
08051 gh_manager::get_object (hcv(n)).reset_default_properties ();
08052 }
08053 }
08054
08055 return octave_value ();
08056 }
08057
08058 DEFUN (set, args, nargout,
08059 "-*- texinfo -*-\n\
08060 @deftypefn {Built-in Function} {} set (@var{h}, @var{property}, @var{value}, @dots{})\n\
08061 @deftypefnx {Built-in Function} {} set (@var{h}, @var{properties}, @var{values})\n\
08062 @deftypefnx {Built-in Function} {} set (@var{h}, @var{pv})\n\
08063 Set named property values for the graphics handle (or vector of graphics\n\
08064 handles) @var{h}.\n\
08065 There are three ways how to give the property names and values:\n\
08066 \n\
08067 @itemize\n\
08068 @item as a comma separated list of @var{property}, @var{value} pairs\n\
08069 \n\
08070 Here, each @var{property} is a string containing the property name, each\n\
08071 @var{value} is a value of the appropriate type for the property.\n\
08072 \n\
08073 @item as a cell array of strings @var{properties} containing property names\n\
08074 and a cell array @var{values} containing property values.\n\
08075 \n\
08076 In this case, the number of columns of @var{values} must match the number of\n\
08077 elements in @var{properties}. The first column of @var{values} contains\n\
08078 values for the first entry in @var{properties}, etc. The number of rows of\n\
08079 @var{values} must be 1 or match the number of elements of @var{h}. In the\n\
08080 first case, each handle in @var{h} will be assigned the same values. In the\n\
08081 latter case, the first handle in @var{h} will be assigned the values from\n\
08082 the first row of @var{values} and so on.\n\
08083 \n\
08084 @item as a structure array @var{pv}\n\
08085 \n\
08086 Here, the field names of @var{pv} represent the property names, and the field\n\
08087 values give the property values. In contrast to the previous case, all\n\
08088 elements of @var{pv} will be set in all handles in @var{h} independent of\n\
08089 the dimensions of @var{pv}.\n\
08090 @end itemize\n\
08091 @end deftypefn")
08092 {
08093 gh_manager::auto_lock guard;
08094
08095 octave_value retval;
08096
08097 int nargin = args.length ();
08098
08099 if (nargin > 0)
08100 {
08101
08102 ColumnVector hcv (args(0).vector_value ());
08103
08104 if (! error_state)
08105 {
08106 bool request_drawnow = false;
08107
08108
08109 for (octave_idx_type n = 0; n < hcv.length (); n++)
08110 {
08111 graphics_object obj = gh_manager::get_object (hcv(n));
08112
08113 if (obj)
08114 {
08115 if (nargin == 3 && args(1).is_cellstr ()
08116 && args(2).is_cell ())
08117 {
08118 if (args(2).cell_value ().rows () == 1)
08119 {
08120 obj.set (args(1).cellstr_value (),
08121 args(2).cell_value (), 0);
08122 }
08123 else if (hcv.length () == args(2).cell_value ().rows ())
08124 {
08125 obj.set (args(1).cellstr_value (),
08126 args(2).cell_value (), n);
08127 }
08128 else
08129 {
08130 error("set: number of graphics handles must match number of value rows (%d != %d)",
08131 hcv.length (), args(2).cell_value ().rows ());
08132 break;
08133
08134 }
08135 }
08136 else if (nargin == 2 && args(1).is_map ())
08137 {
08138 obj.set (args(1).map_value ());
08139 }
08140 else if (nargin == 1)
08141 {
08142 if (nargout != 0)
08143 retval = obj.values_as_struct ();
08144 else
08145 {
08146 std::string s = obj.values_as_string ();
08147 if (! error_state)
08148 octave_stdout << s;
08149 }
08150 }
08151 else
08152 {
08153 obj.set (args.splice (0, 1));
08154 request_drawnow = true;
08155 }
08156 }
08157 else
08158 {
08159 error ("set: invalid handle (= %g)", hcv(n));
08160 break;
08161 }
08162
08163 if (error_state)
08164 break;
08165
08166 request_drawnow = true;
08167 }
08168
08169 if (! error_state && request_drawnow)
08170 Vdrawnow_requested = true;
08171 }
08172 else
08173 error ("set: expecting graphics handle as first argument");
08174 }
08175 else
08176 print_usage ();
08177
08178 return retval;
08179 }
08180
08181 static std::string
08182 get_graphics_object_type (const double val)
08183 {
08184 std::string retval;
08185
08186 graphics_object obj = gh_manager::get_object (val);
08187
08188 if (obj)
08189 retval = obj.type ();
08190 else
08191 error ("get: invalid handle (= %g)", val);
08192
08193 return retval;
08194 }
08195
08196 DEFUN (get, args, ,
08197 "-*- texinfo -*-\n\
08198 @deftypefn {Built-in Function} {} get (@var{h}, @var{p})\n\
08199 Return the named property @var{p} from the graphics handle @var{h}.\n\
08200 If @var{p} is omitted, return the complete property list for @var{h}.\n\
08201 If @var{h} is a vector, return a cell array including the property\n\
08202 values or lists respectively.\n\
08203 @end deftypefn")
08204 {
08205 gh_manager::auto_lock guard;
08206
08207 octave_value retval;
08208
08209 Cell vals;
08210
08211 int nargin = args.length ();
08212
08213 bool use_cell_format = false;
08214
08215 if (nargin == 1 || nargin == 2)
08216 {
08217 if (args(0).is_empty())
08218 {
08219 retval = Matrix ();
08220 return retval;
08221 }
08222
08223 ColumnVector hcv (args(0).vector_value ());
08224
08225 if (! error_state)
08226 {
08227 octave_idx_type len = hcv.length ();
08228
08229 if (nargin == 1 && len > 1)
08230 {
08231 std::string t0 = get_graphics_object_type (hcv(0));
08232
08233 if (! error_state)
08234 {
08235 for (octave_idx_type n = 1; n < len; n++)
08236 {
08237 std::string t = get_graphics_object_type (hcv(n));
08238
08239 if (error_state)
08240 break;
08241
08242 if (t != t0)
08243 {
08244 error ("get: vector of handles must all have same type");
08245 break;
08246 }
08247 }
08248
08249 }
08250 }
08251
08252 if (! error_state)
08253 {
08254 if (nargin > 1 && args(1).is_cellstr ())
08255 {
08256 Array<std::string> plist = args(1).cellstr_value ();
08257
08258 if (! error_state)
08259 {
08260 octave_idx_type plen = plist.numel ();
08261
08262 use_cell_format = true;
08263
08264 vals.resize (dim_vector (len, plen));
08265
08266 for (octave_idx_type n = 0; ! error_state && n < len; n++)
08267 {
08268 graphics_object obj = gh_manager::get_object (hcv(n));
08269
08270 if (obj)
08271 {
08272 for (octave_idx_type m = 0; ! error_state && m < plen; m++)
08273 {
08274 caseless_str property = plist(m);
08275
08276 vals(n, m) = obj.get (property);
08277 }
08278 }
08279 else
08280 {
08281 error ("get: invalid handle (= %g)", hcv(n));
08282 break;
08283 }
08284 }
08285 }
08286 else
08287 error ("get: expecting property name or cell array of property names as second argument");
08288 }
08289 else
08290 {
08291 caseless_str property;
08292
08293 if (nargin > 1)
08294 {
08295 property = args(1).string_value ();
08296
08297 if (error_state)
08298 error ("get: expecting property name or cell array of property names as second argument");
08299 }
08300
08301 vals.resize (dim_vector (len, 1));
08302
08303 if (! error_state)
08304 {
08305 for (octave_idx_type n = 0; ! error_state && n < len; n++)
08306 {
08307 graphics_object obj = gh_manager::get_object (hcv(n));
08308
08309 if (obj)
08310 {
08311 if (nargin == 1)
08312 vals(n) = obj.get ();
08313 else
08314 vals(n) = obj.get (property);
08315 }
08316 else
08317 {
08318 error ("get: invalid handle (= %g)", hcv(n));
08319 break;
08320 }
08321 }
08322 }
08323 }
08324 }
08325 }
08326 else
08327 error ("get: expecting graphics handle as first argument");
08328 }
08329 else
08330 print_usage ();
08331
08332 if (! error_state)
08333 {
08334 if (use_cell_format)
08335 retval = vals;
08336 else
08337 {
08338 octave_idx_type len = vals.numel ();
08339
08340 if (len == 0)
08341 retval = Matrix ();
08342 else if (len == 1)
08343 retval = vals(0);
08344 else if (len > 1 && nargin == 1)
08345 {
08346 OCTAVE_LOCAL_BUFFER (octave_scalar_map, tmp, len);
08347
08348 for (octave_idx_type n = 0; n < len; n++)
08349 tmp[n] = vals(n).scalar_map_value ();
08350
08351 retval = octave_map::cat (0, len, tmp);
08352 }
08353 else
08354 retval = vals;
08355 }
08356 }
08357
08358 return retval;
08359 }
08360
08361
08362
08363
08364
08365
08366
08367
08368
08369 DEFUN (__get__, args, ,
08370 "-*- texinfo -*-\n\
08371 @deftypefn {Built-in Function} {} __get__ (@var{h})\n\
08372 Undocumented internal function.\n\
08373 @end deftypefn")
08374 {
08375 gh_manager::auto_lock guard;
08376
08377 octave_value retval;
08378
08379 Cell vals;
08380
08381 int nargin = args.length ();
08382
08383 if (nargin == 1)
08384 {
08385 ColumnVector hcv (args(0).vector_value ());
08386
08387 if (! error_state)
08388 {
08389 octave_idx_type len = hcv.length ();
08390
08391 vals.resize (dim_vector (len, 1));
08392
08393 for (octave_idx_type n = 0; n < len; n++)
08394 {
08395 graphics_object obj = gh_manager::get_object (hcv(n));
08396
08397 if (obj)
08398 vals(n) = obj.get (true);
08399 else
08400 {
08401 error ("get: invalid handle (= %g)", hcv(n));
08402 break;
08403 }
08404 }
08405 }
08406 else
08407 error ("get: expecting graphics handle as first argument");
08408 }
08409 else
08410 print_usage ();
08411
08412 if (! error_state)
08413 {
08414 octave_idx_type len = vals.numel ();
08415
08416 if (len > 1)
08417 retval = vals;
08418 else if (len == 1)
08419 retval = vals(0);
08420 }
08421
08422 return retval;
08423 }
08424
08425 static octave_value
08426 make_graphics_object (const std::string& go_name,
08427 bool integer_figure_handle,
08428 const octave_value_list& args)
08429 {
08430 octave_value retval;
08431
08432 double val = octave_NaN;
08433
08434 octave_value_list xargs = args.splice (0, 1);
08435
08436 caseless_str p ("parent");
08437
08438 for (int i = 0; i < xargs.length (); i++)
08439 if (xargs(i).is_string ()
08440 && p.compare (xargs(i).string_value ()))
08441 {
08442 if (i < (xargs.length () - 1))
08443 {
08444 val = xargs(i+1).double_value ();
08445
08446 if (! error_state)
08447 {
08448 xargs = xargs.splice (i, 2);
08449 break;
08450 }
08451 }
08452 else
08453 error ("__go_%s__: missing value for parent property",
08454 go_name.c_str ());
08455 }
08456
08457 if (! error_state && xisnan (val))
08458 val = args(0).double_value ();
08459
08460 if (! error_state)
08461 {
08462 graphics_handle parent = gh_manager::lookup (val);
08463
08464 if (parent.ok ())
08465 {
08466 graphics_handle h
08467 = gh_manager::make_graphics_handle (go_name, parent,
08468 integer_figure_handle,
08469 false, false);
08470
08471 if (! error_state)
08472 {
08473 adopt (parent, h);
08474
08475 xset (h, xargs);
08476 xcreatefcn (h);
08477 xinitialize (h);
08478
08479 retval = h.value ();
08480
08481 if (! error_state)
08482 Vdrawnow_requested = true;
08483 }
08484 else
08485 error ("__go%s__: unable to create graphics handle",
08486 go_name.c_str ());
08487 }
08488 else
08489 error ("__go_%s__: invalid parent", go_name.c_str ());
08490 }
08491 else
08492 error ("__go_%s__: invalid parent", go_name.c_str ());
08493
08494 return retval;
08495 }
08496
08497 DEFUN (__go_figure__, args, ,
08498 "-*- texinfo -*-\n\
08499 @deftypefn {Built-in Function} {} __go_figure__ (@var{fignum})\n\
08500 Undocumented internal function.\n\
08501 @end deftypefn")
08502 {
08503 gh_manager::auto_lock guard;
08504
08505 octave_value retval;
08506
08507 if (args.length () > 0)
08508 {
08509 double val = args(0).double_value ();
08510
08511 if (! error_state)
08512 {
08513 if (is_figure (val))
08514 {
08515 graphics_handle h = gh_manager::lookup (val);
08516
08517 xset (h, args.splice (0, 1));
08518
08519 retval = h.value ();
08520 }
08521 else
08522 {
08523 bool int_fig_handle = true;
08524
08525 octave_value_list xargs = args.splice (0, 1);
08526
08527 graphics_handle h = octave_NaN;
08528
08529 if (xisnan (val))
08530 {
08531 caseless_str p ("integerhandle");
08532
08533 for (int i = 0; i < xargs.length (); i++)
08534 {
08535 if (xargs(i).is_string ()
08536 && p.compare (xargs(i).string_value ()))
08537 {
08538 if (i < (xargs.length () - 1))
08539 {
08540 std::string pval = xargs(i+1).string_value ();
08541
08542 if (! error_state)
08543 {
08544 caseless_str on ("on");
08545 int_fig_handle = on.compare (pval);
08546 xargs = xargs.splice (i, 2);
08547 break;
08548 }
08549 }
08550 }
08551 }
08552
08553 h = gh_manager::make_graphics_handle ("figure", 0,
08554 int_fig_handle,
08555 false, false);
08556
08557 if (! int_fig_handle)
08558 {
08559
08560
08561
08562
08563
08564 graphics_object go = gh_manager::get_object (h);
08565 go.get_properties ().init_integerhandle ("off");
08566 }
08567 }
08568 else if (val > 0 && D_NINT (val) == val)
08569 h = gh_manager::make_figure_handle (val, false);
08570
08571 if (! error_state && h.ok ())
08572 {
08573 adopt (0, h);
08574
08575 gh_manager::push_figure (h);
08576
08577 xset (h, xargs);
08578 xcreatefcn (h);
08579 xinitialize (h);
08580
08581 retval = h.value ();
08582 }
08583 else
08584 error ("__go_figure__: failed to create figure handle");
08585 }
08586 }
08587 else
08588 error ("__go_figure__: expecting figure number to be double value");
08589 }
08590 else
08591 print_usage ();
08592
08593 return retval;
08594 }
08595
08596 #define GO_BODY(TYPE) \
08597 gh_manager::auto_lock guard; \
08598 \
08599 octave_value retval; \
08600 \
08601 if (args.length () > 0) \
08602 retval = make_graphics_object (#TYPE, false, args); \
08603 else \
08604 print_usage (); \
08605 \
08606 return retval
08607
08608 int
08609 calc_dimensions (const graphics_object& go)
08610 {
08611
08612 int nd = 2;
08613
08614 if (go.isa ("surface"))
08615 nd = 3;
08616
08617 if ((go.isa ("line") || go.isa ("patch")) && ! go.get("zdata").is_empty ())
08618 nd = 3;
08619
08620 Matrix kids = go.get_properties().get_children ();
08621
08622 for (octave_idx_type i = 0; i < kids.length (); i++)
08623 {
08624 graphics_handle hnd = gh_manager::lookup (kids(i));
08625
08626 if (hnd.ok ())
08627 {
08628 const graphics_object& kid = gh_manager::get_object(hnd);
08629
08630 if (kid.valid_object())
08631 nd = calc_dimensions (kid);
08632
08633 if (nd == 3)
08634 break;
08635 }
08636 }
08637
08638 return nd;
08639 }
08640
08641 DEFUN (__calc_dimensions__, args, ,
08642 "-*- texinfo -*-\n\
08643 @deftypefn {Built-in Function} {} __calc_dimensions__ (@var{axes})\n\
08644 Internal function. Determine the number of dimensions in a graphics\n\
08645 object, whether 2 or 3.\n\
08646 @end deftypefn")
08647 {
08648 gh_manager::auto_lock guard;
08649
08650 octave_value retval;
08651
08652 int nargin = args.length ();
08653
08654 if (nargin == 1)
08655 {
08656 double h = args(0).double_value ();
08657
08658 if (! error_state)
08659 retval = calc_dimensions (gh_manager::get_object (h));
08660 else
08661 error ("__calc_dimensions__: expecting graphics handle as only argument");
08662 }
08663 else
08664 print_usage ();
08665
08666 return retval;
08667 }
08668
08669 DEFUN (__go_axes__, args, ,
08670 "-*- texinfo -*-\n\
08671 @deftypefn {Built-in Function} {} __go_axes__ (@var{parent})\n\
08672 Undocumented internal function.\n\
08673 @end deftypefn")
08674 {
08675 GO_BODY (axes);
08676 }
08677
08678 DEFUN (__go_line__, args, ,
08679 "-*- texinfo -*-\n\
08680 @deftypefn {Built-in Function} {} __go_line__ (@var{parent})\n\
08681 Undocumented internal function.\n\
08682 @end deftypefn")
08683 {
08684 GO_BODY (line);
08685 }
08686
08687 DEFUN (__go_text__, args, ,
08688 "-*- texinfo -*-\n\
08689 @deftypefn {Built-in Function} {} __go_text__ (@var{parent})\n\
08690 Undocumented internal function.\n\
08691 @end deftypefn")
08692 {
08693 GO_BODY (text);
08694 }
08695
08696 DEFUN (__go_image__, args, ,
08697 "-*- texinfo -*-\n\
08698 @deftypefn {Built-in Function} {} __go_image__ (@var{parent})\n\
08699 Undocumented internal function.\n\
08700 @end deftypefn")
08701 {
08702 GO_BODY (image);
08703 }
08704
08705 DEFUN (__go_surface__, args, ,
08706 "-*- texinfo -*-\n\
08707 @deftypefn {Built-in Function} {} __go_surface__ (@var{parent})\n\
08708 Undocumented internal function.\n\
08709 @end deftypefn")
08710 {
08711 GO_BODY (surface);
08712 }
08713
08714 DEFUN (__go_patch__, args, ,
08715 "-*- texinfo -*-\n\
08716 @deftypefn {Built-in Function} {} __go_patch__ (@var{parent})\n\
08717 Undocumented internal function.\n\
08718 @end deftypefn")
08719 {
08720 GO_BODY (patch);
08721 }
08722
08723 DEFUN (__go_hggroup__, args, ,
08724 "-*- texinfo -*-\n\
08725 @deftypefn {Built-in Function} {} __go_hggroup__ (@var{parent})\n\
08726 Undocumented internal function.\n\
08727 @end deftypefn")
08728 {
08729 GO_BODY (hggroup);
08730 }
08731
08732 DEFUN (__go_uimenu__, args, ,
08733 "-*- texinfo -*-\n\
08734 @deftypefn {Built-in Function} {} __go_uimenu__ (@var{parent})\n\
08735 Undocumented internal function.\n\
08736 @end deftypefn")
08737 {
08738 GO_BODY (uimenu);
08739 }
08740
08741 DEFUN (__go_uicontrol__, args, ,
08742 "-*- texinfo -*-\n\
08743 @deftypefn {Built-in Function} {} __go_uicontrol__ (@var{parent})\n\
08744 Undocumented internal function.\n\
08745 @end deftypefn")
08746 {
08747 GO_BODY (uicontrol);
08748 }
08749
08750 DEFUN (__go_uipanel__, args, ,
08751 "-*- texinfo -*-\n\
08752 @deftypefn {Built-in Function} {} __go_uipanel__ (@var{parent})\n\
08753 Undocumented internal function.\n\
08754 @end deftypefn")
08755 {
08756 GO_BODY (uipanel);
08757 }
08758
08759 DEFUN (__go_uicontextmenu__, args, ,
08760 "-*- texinfo -*-\n\
08761 @deftypefn {Built-in Function} {} __go_uicontextmenu__ (@var{parent})\n\
08762 Undocumented internal function.\n\
08763 @end deftypefn")
08764 {
08765 GO_BODY (uicontextmenu);
08766 }
08767
08768 DEFUN (__go_uitoolbar__, args, ,
08769 "-*- texinfo -*-\n\
08770 @deftypefn {Built-in Function} {} __go_uitoolbar__ (@var{parent})\n\
08771 Undocumented internal function.\n\
08772 @end deftypefn")
08773 {
08774 GO_BODY (uitoolbar);
08775 }
08776
08777 DEFUN (__go_uipushtool__, args, ,
08778 "-*- texinfo -*-\n\
08779 @deftypefn {Built-in Function} {} __go_uipushtool__ (@var{parent})\n\
08780 Undocumented internal function.\n\
08781 @end deftypefn")
08782 {
08783 GO_BODY (uipushtool);
08784 }
08785
08786 DEFUN (__go_uitoggletool__, args, ,
08787 "-*- texinfo -*-\n\
08788 @deftypefn {Built-in Function} {} __go_uitoggletool__ (@var{parent})\n\
08789 Undocumented internal function.\n\
08790 @end deftypefn")
08791 {
08792 GO_BODY (uitoggletool);
08793 }
08794
08795 DEFUN (__go_delete__, args, ,
08796 "-*- texinfo -*-\n\
08797 @deftypefn {Built-in Function} {} __go_delete__ (@var{h})\n\
08798 Undocumented internal function.\n\
08799 @end deftypefn")
08800 {
08801 gh_manager::auto_lock guard;
08802
08803 octave_value_list retval;
08804
08805 if (args.length () == 1)
08806 {
08807 graphics_handle h = octave_NaN;
08808
08809 const NDArray vals = args (0).array_value ();
08810
08811 if (! error_state)
08812 {
08813
08814
08815
08816 for (octave_idx_type i = 0; i < vals.numel (); i++)
08817 {
08818 h = gh_manager::lookup (vals.elem (i));
08819
08820 if (! h.ok ())
08821 {
08822 error ("delete: invalid graphics object (= %g)",
08823 vals.elem (i));
08824 break;
08825 }
08826 }
08827
08828 if (! error_state)
08829 delete_graphics_objects (vals);
08830 }
08831 else
08832 error ("delete: invalid graphics object");
08833 }
08834 else
08835 print_usage ();
08836
08837 return retval;
08838 }
08839
08840 DEFUN (__go_axes_init__, args, ,
08841 "-*- texinfo -*-\n\
08842 @deftypefn {Built-in Function} {} __go_axes_init__ (@var{h}, @var{mode})\n\
08843 Undocumented internal function.\n\
08844 @end deftypefn")
08845 {
08846 gh_manager::auto_lock guard;
08847
08848 octave_value retval;
08849
08850 int nargin = args.length ();
08851
08852 std::string mode = "";
08853
08854 if (nargin == 2)
08855 {
08856 mode = args(1).string_value ();
08857
08858 if (error_state)
08859 return retval;
08860 }
08861
08862 if (nargin == 1 || nargin == 2)
08863 {
08864 graphics_handle h = octave_NaN;
08865
08866 double val = args(0).double_value ();
08867
08868 if (! error_state)
08869 {
08870 h = gh_manager::lookup (val);
08871
08872 if (h.ok ())
08873 {
08874 graphics_object obj = gh_manager::get_object (h);
08875
08876 obj.set_defaults (mode);
08877
08878 h = gh_manager::lookup (val);
08879 if (! h.ok ())
08880 error ("__go_axes_init__: axis deleted during initialization (= %g)", val);
08881 }
08882 else
08883 error ("__go_axes_init__: invalid graphics object (= %g)", val);
08884 }
08885 else
08886 error ("__go_axes_init__: invalid graphics object");
08887 }
08888 else
08889 print_usage ();
08890
08891 return retval;
08892 }
08893
08894 DEFUN (__go_handles__, args, ,
08895 "-*- texinfo -*-\n\
08896 @deftypefn {Built-in Function} {} __go_handles__ (@var{show_hidden})\n\
08897 Undocumented internal function.\n\
08898 @end deftypefn")
08899 {
08900 gh_manager::auto_lock guard;
08901
08902 bool show_hidden = false;
08903
08904 if (args.length () > 0)
08905 show_hidden = args(0).bool_value ();
08906
08907 return octave_value (gh_manager::handle_list (show_hidden));
08908 }
08909
08910 DEFUN (__go_figure_handles__, args, ,
08911 "-*- texinfo -*-\n\
08912 @deftypefn {Built-in Function} {} __go_figure_handles__ (@var{show_hidden})\n\
08913 Undocumented internal function.\n\
08914 @end deftypefn")
08915 {
08916 gh_manager::auto_lock guard;
08917
08918 bool show_hidden = false;
08919
08920 if (args.length () > 0)
08921 show_hidden = args(0).bool_value ();
08922
08923 return octave_value (gh_manager::figure_handle_list (show_hidden));
08924 }
08925
08926 DEFUN (__go_execute_callback__, args, ,
08927 "-*- texinfo -*-\n\
08928 @deftypefn {Built-in Function} {} __go_execute_callback__ (@var{h}, @var{name})\n\
08929 @deftypefnx {Built-in Function} {} __go_execute_callback__ (@var{h}, @var{name}, @var{param})\n\
08930 Undocumented internal function.\n\
08931 @end deftypefn")
08932 {
08933 octave_value retval;
08934
08935 int nargin = args.length ();
08936
08937 if (nargin == 2 || nargin == 3)
08938 {
08939 double val = args(0).double_value ();
08940
08941 if (! error_state)
08942 {
08943 graphics_handle h = gh_manager::lookup (val);
08944
08945 if (h.ok ())
08946 {
08947 std::string name = args(1).string_value ();
08948
08949 if (! error_state)
08950 {
08951 if (nargin == 2)
08952 gh_manager::execute_callback (h, name);
08953 else
08954 gh_manager::execute_callback (h, name, args(2));
08955 }
08956 else
08957 error ("__go_execute_callback__: invalid callback name");
08958 }
08959 else
08960 error ("__go_execute_callback__: invalid graphics object (= %g)",
08961 val);
08962 }
08963 else
08964 error ("__go_execute_callback__: invalid graphics object");
08965 }
08966 else
08967 print_usage ();
08968
08969 return retval;
08970 }
08971
08972 DEFUN (__image_pixel_size__, args, ,
08973 "-*- texinfo -*-\n\
08974 @deftypefn {Built-in Function} {@var{px}, @var{py}} __image_pixel_size__ (@var{h})\n\
08975 Internal function: returns the pixel size of the image in normalized units.\n\
08976 @end deftypefn")
08977 {
08978 octave_value retval;
08979
08980 int nargin = args.length ();
08981
08982 if (nargin == 1)
08983 {
08984 double h = args(0).double_value ();
08985
08986 if (! error_state)
08987 {
08988 graphics_object fobj = gh_manager::get_object (h);
08989 if (fobj && fobj.isa ("image"))
08990 {
08991 image::properties& ip =
08992 dynamic_cast<image::properties&> (fobj.get_properties ());
08993
08994 Matrix dp = Matrix (1, 2, 0);
08995 dp(0, 0) = ip.pixel_xsize ();
08996 dp(0, 1) = ip.pixel_ysize ();
08997 retval = dp;
08998 }
08999 else
09000 error ("__image_pixel_size__: object is not an image");
09001 }
09002 else
09003 error ("__image_pixel_size__: argument is not a handle");
09004 }
09005 else
09006 print_usage ();
09007
09008 return retval;
09009 }
09010
09011 gtk_manager *gtk_manager::instance = 0;
09012
09013 void
09014 gtk_manager::create_instance (void)
09015 {
09016 instance = new gtk_manager ();
09017
09018 if (instance)
09019 singleton_cleanup_list::add (cleanup_instance);
09020 }
09021
09022 graphics_toolkit
09023 gtk_manager::do_get_toolkit (void) const
09024 {
09025 graphics_toolkit retval;
09026
09027 const_loaded_toolkits_iterator pl = loaded_toolkits.find (dtk);
09028
09029 if (pl == loaded_toolkits.end ())
09030 {
09031 const_available_toolkits_iterator pa = available_toolkits.find (dtk);
09032
09033 if (pa != available_toolkits.end ())
09034 {
09035 octave_value_list args;
09036 args(0) = dtk;
09037 feval ("graphics_toolkit", args);
09038
09039 if (! error_state)
09040 pl = loaded_toolkits.find (dtk);
09041
09042 if (error_state || pl == loaded_toolkits.end ())
09043 error ("failed to load %s graphics toolkit", dtk.c_str ());
09044 else
09045 retval = pl->second;
09046 }
09047 else
09048 error ("default graphics toolkit '%s' is not available!",
09049 dtk.c_str ());
09050 }
09051 else
09052 retval = pl->second;
09053
09054 return retval;
09055 }
09056
09057 DEFUN (available_graphics_toolkits, , ,
09058 "-*- texinfo -*-\n\
09059 @deftypefn {Built-in Function} {} available_graphics_toolkits ()\n\
09060 Return a cell array of registered graphics toolkits.\n\
09061 @seealso{graphics_toolkit, register_graphics_toolkit}\n\
09062 @end deftypefn")
09063 {
09064 gh_manager::auto_lock guard;
09065
09066 return octave_value (gtk_manager::available_toolkits_list ());
09067 }
09068
09069 DEFUN (register_graphics_toolkit, args, ,
09070 "-*- texinfo -*-\n\
09071 @deftypefn {Built-in Function} {} register_graphics_toolkit (@var{toolkit})\n\
09072 List @var{toolkit} as an available graphics toolkit.\n\
09073 @seealso{available_graphics_toolkits}\n\
09074 @end deftypefn")
09075 {
09076 octave_value retval;
09077
09078 gh_manager::auto_lock guard;
09079
09080 if (args.length () == 1)
09081 {
09082 std::string name = args(0).string_value ();
09083
09084 if (! error_state)
09085 gtk_manager::register_toolkit (name);
09086 else
09087 error ("register_graphics_toolkit: expecting character string");
09088 }
09089 else
09090 print_usage ();
09091
09092 return retval;
09093 }
09094
09095 DEFUN (loaded_graphics_toolkits, , ,
09096 "-*- texinfo -*-\n\
09097 @deftypefn {Built-in Function} {} loaded_graphics_toolkits ()\n\
09098 Return a cell array of the currently loaded graphics toolkits.\n\
09099 @seealso{available_graphics_toolkits}\n\
09100 @end deftypefn")
09101 {
09102 gh_manager::auto_lock guard;
09103
09104 return octave_value (gtk_manager::loaded_toolkits_list ());
09105 }
09106
09107 DEFUN (drawnow, args, ,
09108 "-*- texinfo -*-\n\
09109 @deftypefn {Built-in Function} {} drawnow ()\n\
09110 @deftypefnx {Built-in Function} {} drawnow (\"expose\")\n\
09111 @deftypefnx {Built-in Function} {} drawnow (@var{term}, @var{file}, @var{mono}, @var{debug_file})\n\
09112 Update figure windows and their children. The event queue is flushed and\n\
09113 any callbacks generated are executed. With the optional argument\n\
09114 @code{\"expose\"}, only graphic objects are updated and no other events or\n\
09115 callbacks are processed.\n\
09116 The third calling form of @code{drawnow} is for debugging and is\n\
09117 undocumented.\n\
09118 @end deftypefn")
09119 {
09120 static int drawnow_executing = 0;
09121
09122 octave_value retval;
09123
09124 gh_manager::lock ();
09125
09126 unwind_protect frame;
09127 frame.protect_var (Vdrawnow_requested, false);
09128
09129 frame.protect_var (drawnow_executing);
09130
09131 if (++drawnow_executing <= 1)
09132 {
09133 if (args.length () == 0 || args.length () == 1)
09134 {
09135 Matrix hlist = gh_manager::figure_handle_list (true);
09136
09137 for (int i = 0; ! error_state && i < hlist.length (); i++)
09138 {
09139 graphics_handle h = gh_manager::lookup (hlist(i));
09140
09141 if (h.ok () && h != 0)
09142 {
09143 graphics_object go = gh_manager::get_object (h);
09144 figure::properties& fprops = dynamic_cast <figure::properties&> (go.get_properties ());
09145
09146 if (fprops.is_modified ())
09147 {
09148 if (fprops.is_visible ())
09149 {
09150 gh_manager::unlock ();
09151
09152 fprops.get_toolkit ().redraw_figure (go);
09153
09154 gh_manager::lock ();
09155 }
09156
09157 fprops.set_modified (false);
09158 }
09159 }
09160 }
09161
09162 bool do_events = true;
09163
09164 if (args.length () == 1)
09165 {
09166 caseless_str val (args(0).string_value ());
09167
09168 if (! error_state && val.compare ("expose"))
09169 do_events = false;
09170 else
09171 {
09172 error ("drawnow: invalid argument, expected 'expose' as argument");
09173 return retval;
09174 }
09175 }
09176
09177 if (do_events)
09178 {
09179 gh_manager::unlock ();
09180
09181 gh_manager::process_events ();
09182
09183 gh_manager::lock ();
09184 }
09185 }
09186 else if (args.length () >= 2 && args.length () <= 4)
09187 {
09188 std::string term, file, debug_file;
09189 bool mono;
09190
09191 term = args(0).string_value ();
09192
09193 if (! error_state)
09194 {
09195 file = args(1).string_value ();
09196
09197 if (! error_state)
09198 {
09199 size_t pos = file.find_first_not_of ("|");
09200 if (pos > 0)
09201 file = file.substr (pos);
09202 else
09203 {
09204 pos = file.find_last_of (file_ops::dir_sep_chars ());
09205
09206 if (pos != std::string::npos)
09207 {
09208 std::string dirname = file.substr (0, pos+1);
09209
09210 file_stat fs (dirname);
09211
09212 if (! (fs && fs.is_dir ()))
09213 {
09214 error ("drawnow: nonexistent directory '%s'",
09215 dirname.c_str ());
09216
09217 return retval;
09218 }
09219 }
09220 }
09221
09222 mono = (args.length () >= 3 ? args(2).bool_value () : false);
09223
09224 if (! error_state)
09225 {
09226 debug_file = (args.length () > 3 ? args(3).string_value ()
09227 : "");
09228
09229 if (! error_state)
09230 {
09231 graphics_handle h = gcf ();
09232
09233 if (h.ok ())
09234 {
09235 graphics_object go = gh_manager::get_object (h);
09236
09237 gh_manager::unlock ();
09238
09239 go.get_toolkit ()
09240 .print_figure (go, term, file, mono, debug_file);
09241
09242 gh_manager::lock ();
09243 }
09244 else
09245 error ("drawnow: nothing to draw");
09246 }
09247 else
09248 error ("drawnow: invalid DEBUG_FILE, expected a string value");
09249 }
09250 else
09251 error ("drawnow: invalid colormode MONO, expected a boolean value");
09252 }
09253 else
09254 error ("drawnow: invalid FILE, expected a string value");
09255 }
09256 else
09257 error ("drawnow: invalid terminal TERM, expected a string value");
09258 }
09259 else
09260 print_usage ();
09261 }
09262
09263 gh_manager::unlock ();
09264
09265 return retval;
09266 }
09267
09268 DEFUN (addlistener, args, ,
09269 "-*- texinfo -*-\n\
09270 @deftypefn {Built-in Function} {} addlistener (@var{h}, @var{prop}, @var{fcn})\n\
09271 Register @var{fcn} as listener for the property @var{prop} of the graphics\n\
09272 object @var{h}. Property listeners are executed (in order of registration)\n\
09273 when the property is set. The new value is already available when the\n\
09274 listeners are executed.\n\
09275 \n\
09276 @var{prop} must be a string naming a valid property in @var{h}.\n\
09277 \n\
09278 @var{fcn} can be a function handle, a string or a cell array whose first\n\
09279 element is a function handle. If @var{fcn} is a function handle, the\n\
09280 corresponding function should accept at least 2 arguments, that will be\n\
09281 set to the object handle and the empty matrix respectively. If @var{fcn}\n\
09282 is a string, it must be any valid octave expression. If @var{fcn} is a cell\n\
09283 array, the first element must be a function handle with the same signature\n\
09284 as described above. The next elements of the cell array are passed\n\
09285 as additional arguments to the function.\n\
09286 \n\
09287 Example:\n\
09288 \n\
09289 @example\n\
09290 @group\n\
09291 function my_listener (h, dummy, p1)\n\
09292 fprintf (\"my_listener called with p1=%s\\n\", p1);\n\
09293 endfunction\n\
09294 \n\
09295 addlistener (gcf, \"position\", @{@@my_listener, \"my string\"@})\n\
09296 @end group\n\
09297 @end example\n\
09298 \n\
09299 @end deftypefn")
09300 {
09301 gh_manager::auto_lock guard;
09302
09303 octave_value retval;
09304
09305 if (args.length () >= 3 && args.length () <= 4)
09306 {
09307 double h = args(0).double_value ();
09308
09309 if (! error_state)
09310 {
09311 std::string pname = args(1).string_value ();
09312
09313 if (! error_state)
09314 {
09315 graphics_handle gh = gh_manager::lookup (h);
09316
09317 if (gh.ok ())
09318 {
09319 graphics_object go = gh_manager::get_object (gh);
09320
09321 go.add_property_listener (pname, args(2), POSTSET);
09322
09323 if (args.length () == 4)
09324 {
09325 caseless_str persistent = args(3).string_value ();
09326 if (persistent.compare ("persistent"))
09327 go.add_property_listener (pname, args(2), PERSISTENT);
09328 }
09329 }
09330 else
09331 error ("addlistener: invalid graphics object (= %g)",
09332 h);
09333 }
09334 else
09335 error ("addlistener: invalid property name, expected a string value");
09336 }
09337 else
09338 error ("addlistener: invalid handle");
09339 }
09340 else
09341 print_usage ();
09342
09343 return retval;
09344 }
09345
09346 DEFUN (dellistener, args, ,
09347 "-*- texinfo -*-\n\
09348 @deftypefn {Built-in Function} {} dellistener (@var{h}, @var{prop}, @var{fcn})\n\
09349 Remove the registration of @var{fcn} as a listener for the property\n\
09350 @var{prop} of the graphics object @var{h}. The function @var{fcn} must\n\
09351 be the same variable (not just the same value), as was passed to the\n\
09352 original call to @code{addlistener}.\n\
09353 \n\
09354 If @var{fcn} is not defined then all listener functions of @var{prop}\n\
09355 are removed.\n\
09356 \n\
09357 Example:\n\
09358 \n\
09359 @example\n\
09360 @group\n\
09361 function my_listener (h, dummy, p1)\n\
09362 fprintf (\"my_listener called with p1=%s\\n\", p1);\n\
09363 endfunction\n\
09364 \n\
09365 c = @{@@my_listener, \"my string\"@};\n\
09366 addlistener (gcf, \"position\", c);\n\
09367 dellistener (gcf, \"position\", c);\n\
09368 @end group\n\
09369 @end example\n\
09370 \n\
09371 @end deftypefn")
09372 {
09373 gh_manager::auto_lock guard;
09374
09375 octave_value retval;
09376
09377 if (args.length () == 3 || args.length () == 2)
09378 {
09379 double h = args(0).double_value ();
09380
09381 if (! error_state)
09382 {
09383 std::string pname = args(1).string_value ();
09384
09385 if (! error_state)
09386 {
09387 graphics_handle gh = gh_manager::lookup (h);
09388
09389 if (gh.ok ())
09390 {
09391 graphics_object go = gh_manager::get_object (gh);
09392
09393 if (args.length () == 2)
09394 go.delete_property_listener (pname, octave_value (), POSTSET);
09395 else
09396 {
09397 caseless_str persistent = args(2).string_value ();
09398 if (persistent.compare ("persistent"))
09399 {
09400 go.delete_property_listener (pname, octave_value (), PERSISTENT);
09401 go.delete_property_listener (pname, octave_value (), POSTSET);
09402 }
09403 else
09404 go.delete_property_listener (pname, args(2), POSTSET);
09405 }
09406 }
09407 else
09408 error ("dellistener: invalid graphics object (= %g)",
09409 h);
09410 }
09411 else
09412 error ("dellistener: invalid property name, expected a string value");
09413 }
09414 else
09415 error ("dellistener: invalid handle");
09416 }
09417 else
09418 print_usage ();
09419
09420 return retval;
09421 }
09422
09423 DEFUN (addproperty, args, ,
09424 "-*- texinfo -*-\n\
09425 @deftypefn {Built-in Function} {} addproperty (@var{name}, @var{h}, @var{type})\n\
09426 @deftypefnx {Built-in Function} {} addproperty (@var{name}, @var{h}, @var{type}, @var{arg}, @dots{})\n\
09427 Create a new property named @var{name} in graphics object @var{h}.\n\
09428 @var{type} determines the type of the property to create. @var{args}\n\
09429 usually contains the default value of the property, but additional\n\
09430 arguments might be given, depending on the type of the property.\n\
09431 \n\
09432 The supported property types are:\n\
09433 \n\
09434 @table @code\n\
09435 @item string\n\
09436 A string property. @var{arg} contains the default string value.\n\
09437 \n\
09438 @item any\n\
09439 An un-typed property. This kind of property can hold any octave\n\
09440 value. @var{args} contains the default value.\n\
09441 \n\
09442 @item radio\n\
09443 A string property with a limited set of accepted values. The first\n\
09444 argument must be a string with all accepted values separated by\n\
09445 a vertical bar ('|'). The default value can be marked by enclosing\n\
09446 it with a '@{' '@}' pair. The default value may also be given as\n\
09447 an optional second string argument.\n\
09448 \n\
09449 @item boolean\n\
09450 A boolean property. This property type is equivalent to a radio\n\
09451 property with \"on|off\" as accepted values. @var{arg} contains\n\
09452 the default property value.\n\
09453 \n\
09454 @item double\n\
09455 A scalar double property. @var{arg} contains the default value.\n\
09456 \n\
09457 @item handle\n\
09458 A handle property. This kind of property holds the handle of a\n\
09459 graphics object. @var{arg} contains the default handle value.\n\
09460 When no default value is given, the property is initialized to\n\
09461 the empty matrix.\n\
09462 \n\
09463 @item data\n\
09464 A data (matrix) property. @var{arg} contains the default data\n\
09465 value. When no default value is given, the data is initialized to\n\
09466 the empty matrix.\n\
09467 \n\
09468 @item color\n\
09469 A color property. @var{arg} contains the default color value.\n\
09470 When no default color is given, the property is set to black.\n\
09471 An optional second string argument may be given to specify an\n\
09472 additional set of accepted string values (like a radio property).\n\
09473 @end table\n\
09474 \n\
09475 @var{type} may also be the concatenation of a core object type and\n\
09476 a valid property name for that object type. The property created\n\
09477 then has the same characteristics as the referenced property (type,\n\
09478 possible values, hidden state@dots{}). This allows to clone an existing\n\
09479 property into the graphics object @var{h}.\n\
09480 \n\
09481 Examples:\n\
09482 \n\
09483 @example\n\
09484 @group\n\
09485 addproperty (\"my_property\", gcf, \"string\", \"a string value\");\n\
09486 addproperty (\"my_radio\", gcf, \"radio\", \"val_1|val_2|@{val_3@}\");\n\
09487 addproperty (\"my_style\", gcf, \"linelinestyle\", \"--\");\n\
09488 @end group\n\
09489 @end example\n\
09490 \n\
09491 @end deftypefn")
09492 {
09493 gh_manager::auto_lock guard;
09494
09495 octave_value retval;
09496
09497 if (args.length () >= 3)
09498 {
09499 std::string name = args(0).string_value ();
09500
09501 if (! error_state)
09502 {
09503 double h = args(1).double_value ();
09504
09505 if (! error_state)
09506 {
09507 graphics_handle gh = gh_manager::lookup (h);
09508
09509 if (gh.ok ())
09510 {
09511 graphics_object go = gh_manager::get_object (gh);
09512
09513 std::string type = args(2).string_value ();
09514
09515 if (! error_state)
09516 {
09517 if (! go.get_properties ().has_property (name))
09518 {
09519 property p = property::create (name, gh, type,
09520 args.splice (0, 3));
09521
09522 if (! error_state)
09523 go.get_properties ().insert_property (name, p);
09524 }
09525 else
09526 error ("addproperty: a '%s' property already exists in the graphics object",
09527 name.c_str ());
09528 }
09529 else
09530 error ("addproperty: invalid property TYPE, expected a string value");
09531 }
09532 else
09533 error ("addproperty: invalid graphics object (= %g)", h);
09534 }
09535 else
09536 error ("addproperty: invalid handle value");
09537 }
09538 else
09539 error ("addproperty: invalid property NAME, expected a string value");
09540 }
09541 else
09542 print_usage ();
09543
09544 return retval;
09545 }
09546
09547 octave_value
09548 get_property_from_handle (double handle, const std::string& property,
09549 const std::string& func)
09550 {
09551 gh_manager::auto_lock guard;
09552
09553 graphics_object obj = gh_manager::get_object (handle);
09554 octave_value retval;
09555
09556 if (obj)
09557 retval = obj.get (caseless_str (property));
09558 else
09559 error ("%s: invalid handle (= %g)", func.c_str(), handle);
09560
09561 return retval;
09562 }
09563
09564 bool
09565 set_property_in_handle (double handle, const std::string& property,
09566 const octave_value& arg, const std::string& func)
09567 {
09568 gh_manager::auto_lock guard;
09569
09570 graphics_object obj = gh_manager::get_object (handle);
09571 int ret = false;
09572
09573 if (obj)
09574 {
09575 obj.set (caseless_str (property), arg);
09576
09577 if (! error_state)
09578 ret = true;
09579 }
09580 else
09581 error ("%s: invalid handle (= %g)", func.c_str(), handle);
09582
09583 return ret;
09584 }
09585
09586 static bool
09587 compare_property_values (const octave_value& o1, const octave_value& o2)
09588 {
09589 octave_value_list args (2);
09590
09591 args(0) = o1;
09592 args(1) = o2;
09593
09594 octave_value_list result = feval ("isequal", args, 1);
09595
09596 if (! error_state && result.length () > 0)
09597 return result(0).bool_value ();
09598
09599 return false;
09600 }
09601
09602 static std::map<uint32_t, bool> waitfor_results;
09603
09604 static void
09605 cleanup_waitfor_id (uint32_t id)
09606 {
09607 waitfor_results.erase (id);
09608 }
09609
09610 static void
09611 do_cleanup_waitfor_listener (const octave_value& listener,
09612 listener_mode mode = POSTSET)
09613 {
09614 Cell c = listener.cell_value ();
09615
09616 if (c.numel () >= 4)
09617 {
09618 double h = c(2).double_value ();
09619
09620 if (! error_state)
09621 {
09622 caseless_str pname = c(3).string_value ();
09623
09624 if (! error_state)
09625 {
09626 gh_manager::auto_lock guard;
09627
09628 graphics_handle handle = gh_manager::lookup (h);
09629
09630 if (handle.ok ())
09631 {
09632 graphics_object go = gh_manager::get_object (handle);
09633
09634 if (go.get_properties ().has_property (pname))
09635 {
09636 go.get_properties ()
09637 .delete_listener (pname, listener, mode);
09638 if (mode == POSTSET)
09639 go.get_properties ()
09640 .delete_listener (pname, listener, PERSISTENT);
09641 }
09642 }
09643 }
09644 }
09645 }
09646 }
09647
09648 static void
09649 cleanup_waitfor_postset_listener(const octave_value& listener)
09650 { do_cleanup_waitfor_listener (listener, POSTSET); }
09651
09652 static void
09653 cleanup_waitfor_predelete_listener(const octave_value& listener)
09654 { do_cleanup_waitfor_listener (listener, PREDELETE); }
09655
09656 static octave_value_list
09657 waitfor_listener (const octave_value_list& args, int)
09658 {
09659 if (args.length () > 3)
09660 {
09661 uint32_t id = args(2).uint32_scalar_value ().value ();
09662
09663 if (! error_state)
09664 {
09665 if (args.length () > 5)
09666 {
09667 double h = args(0).double_value ();
09668
09669 if (! error_state)
09670 {
09671 caseless_str pname = args(4).string_value ();
09672
09673 if (! error_state)
09674 {
09675 gh_manager::auto_lock guard;
09676
09677 graphics_handle handle = gh_manager::lookup (h);
09678
09679 if (handle.ok ())
09680 {
09681 graphics_object go = gh_manager::get_object (handle);
09682 octave_value pvalue = go.get (pname);
09683
09684 if (compare_property_values (pvalue, args(5)))
09685 waitfor_results[id] = true;
09686 }
09687 }
09688 }
09689 }
09690 else
09691 waitfor_results[id] = true;
09692 }
09693 }
09694
09695 return octave_value_list ();
09696 }
09697
09698 static octave_value_list
09699 waitfor_del_listener (const octave_value_list& args, int)
09700 {
09701 if (args.length () > 2)
09702 {
09703 uint32_t id = args(2).uint32_scalar_value ().value ();
09704
09705 if (! error_state)
09706 waitfor_results[id] = true;
09707 }
09708
09709 return octave_value_list ();
09710 }
09711
09712 DEFUN (waitfor, args, ,
09713 "-*- texinfo -*-\n\
09714 @deftypefn {Built-in Function} {} waitfor (@var{h})\n\
09715 @deftypefnx {Built-in Function} {} waitfor (@var{h}, @var{prop})\n\
09716 @deftypefnx {Built-in Function} {} waitfor (@var{h}, @var{prop}, @var{value})\n\
09717 @deftypefnx {Built-in Function} {} waitfor (@dots{}, \"timeout\", @var{timeout})\n\
09718 Suspend the execution of the current program until a condition is\n\
09719 satisfied on the graphics handle @var{h}. While the program is suspended\n\
09720 graphics events are still being processed normally, allowing callbacks to\n\
09721 modify the state of graphics objects. This function is reentrant and can be\n\
09722 called from a callback, while another @code{waitfor} call is pending at\n\
09723 top-level.\n\
09724 \n\
09725 In the first form, program execution is suspended until the graphics object\n\
09726 @var{h} is destroyed. If the graphics handle is invalid, the function\n\
09727 returns immediately.\n\
09728 \n\
09729 In the second form, execution is suspended until the graphics object is\n\
09730 destroyed or the property named @var{prop} is modified. If the graphics\n\
09731 handle is invalid or the property does not exist, the function returns\n\
09732 immediately.\n\
09733 \n\
09734 In the third form, execution is suspended until the graphics object is\n\
09735 destroyed or the property named @var{prop} is set to @var{value}. The\n\
09736 function @code{isequal} is used to compare property values. If the graphics\n\
09737 handle is invalid, the property does not exist or the property is already\n\
09738 set to @var{value}, the function returns immediately.\n\
09739 \n\
09740 An optional timeout can be specified using the property @code{timeout}.\n\
09741 This timeout value is the number of seconds to wait for the condition to be\n\
09742 true. @var{timeout} must be at least 1. If a smaller value is specified, a\n\
09743 warning is issued and a value of 1 is used instead. If the timeout value is\n\
09744 not an integer, it is truncated towards 0.\n\
09745 \n\
09746 To define a condition on a property named @code{timeout}, use the string\n\
09747 @code{\\timeout} instead.\n\
09748 \n\
09749 In all cases, typing CTRL-C stops program execution immediately.\n\
09750 @seealso{isequal}\n\
09751 @end deftypefn")
09752 {
09753 if (args.length () > 0)
09754 {
09755 double h = args(0).double_value ();
09756
09757 if (! error_state)
09758 {
09759 caseless_str pname;
09760
09761 unwind_protect frame;
09762
09763 static uint32_t id_counter = 0;
09764 uint32_t id = 0;
09765
09766 int max_arg_index = 0;
09767 int timeout_index = -1;
09768
09769 int timeout = 0;
09770
09771 if (args.length () > 1)
09772 {
09773 pname = args(1).string_value ();
09774 if (! error_state
09775 && ! pname.empty ()
09776 && ! pname.compare ("timeout"))
09777 {
09778 if (pname.compare ("\\timeout"))
09779 pname = "timeout";
09780
09781 static octave_value wf_listener;
09782
09783 if (! wf_listener.is_defined ())
09784 wf_listener =
09785 octave_value (new octave_builtin (waitfor_listener,
09786 "waitfor_listener"));
09787
09788 max_arg_index++;
09789 if (args.length () > 2)
09790 {
09791 if (args(2).is_string ())
09792 {
09793 caseless_str s = args(2).string_value ();
09794
09795 if (! error_state)
09796 {
09797 if (s.compare ("timeout"))
09798 timeout_index = 2;
09799 else
09800 max_arg_index++;
09801 }
09802 }
09803 else
09804 max_arg_index++;
09805 }
09806
09807 Cell listener (1, max_arg_index >= 2 ? 5 : 4);
09808
09809 id = id_counter++;
09810 frame.add_fcn (cleanup_waitfor_id, id);
09811 waitfor_results[id] = false;
09812
09813 listener(0) = wf_listener;
09814 listener(1) = octave_uint32 (id);
09815 listener(2) = h;
09816 listener(3) = pname;
09817
09818 if (max_arg_index >= 2)
09819 listener(4) = args(2);
09820
09821 octave_value ov_listener (listener);
09822
09823 gh_manager::auto_lock guard;
09824
09825 graphics_handle handle = gh_manager::lookup (h);
09826
09827 if (handle.ok ())
09828 {
09829 graphics_object go = gh_manager::get_object (handle);
09830
09831 if (max_arg_index >= 2
09832 && compare_property_values (go.get (pname),
09833 args(2)))
09834 waitfor_results[id] = true;
09835 else
09836 {
09837
09838 frame.add_fcn (cleanup_waitfor_postset_listener,
09839 ov_listener);
09840 go.add_property_listener (pname, ov_listener,
09841 POSTSET);
09842 go.add_property_listener (pname, ov_listener,
09843 PERSISTENT);
09844
09845 if (go.get_properties ()
09846 .has_dynamic_property (pname))
09847 {
09848 static octave_value wf_del_listener;
09849
09850 if (! wf_del_listener.is_defined ())
09851 wf_del_listener =
09852 octave_value (new octave_builtin
09853 (waitfor_del_listener,
09854 "waitfor_del_listener"));
09855
09856 Cell del_listener (1, 4);
09857
09858 del_listener(0) = wf_del_listener;
09859 del_listener(1) = octave_uint32 (id);
09860 del_listener(2) = h;
09861 del_listener(3) = pname;
09862
09863 octave_value ov_del_listener (del_listener);
09864
09865 frame.add_fcn (cleanup_waitfor_predelete_listener,
09866 ov_del_listener);
09867 go.add_property_listener (pname, ov_del_listener,
09868 PREDELETE);
09869 }
09870 }
09871 }
09872 }
09873 else if (error_state || pname.empty ())
09874 error ("waitfor: invalid property name, expected a non-empty string value");
09875 }
09876
09877 if (! error_state
09878 && timeout_index < 0
09879 && args.length () > (max_arg_index + 1))
09880 {
09881 caseless_str s = args(max_arg_index + 1).string_value ();
09882
09883 if (! error_state)
09884 {
09885 if (s.compare ("timeout"))
09886 timeout_index = max_arg_index + 1;
09887 else
09888 error ("waitfor: invalid parameter '%s'", s.c_str ());
09889 }
09890 else
09891 error ("waitfor: invalid parameter, expected 'timeout'");
09892 }
09893
09894 if (! error_state && timeout_index >= 0)
09895 {
09896 if (args.length () > (timeout_index + 1))
09897 {
09898 timeout = static_cast<int>
09899 (args(timeout_index + 1).scalar_value ());
09900
09901 if (! error_state)
09902 {
09903 if (timeout < 1)
09904 {
09905 warning ("waitfor: the timeout value must be >= 1, using 1 instead");
09906 timeout = 1;
09907 }
09908 }
09909 else
09910 error ("waitfor: invalid timeout value, expected a value >= 1");
09911 }
09912 else
09913 error ("waitfor: missing timeout value");
09914 }
09915
09916
09917
09918
09919
09920
09921
09922
09923
09924
09925
09926
09927
09928
09929
09930
09931 time_t start = 0;
09932
09933 if (timeout > 0)
09934 start = time (0);
09935
09936 while (! error_state)
09937 {
09938 if (true)
09939 {
09940 gh_manager::auto_lock guard;
09941
09942 graphics_handle handle = gh_manager::lookup (h);
09943
09944 if (handle.ok ())
09945 {
09946 if (! pname.empty () && waitfor_results[id])
09947 break;
09948 }
09949 else
09950 break;
09951 }
09952
09953 octave_usleep (100000);
09954
09955 OCTAVE_QUIT;
09956
09957 command_editor::run_event_hooks ();
09958
09959 if (timeout > 0)
09960 {
09961 if (start + timeout < time (0))
09962 break;
09963 }
09964 }
09965 }
09966 else
09967 error ("waitfor: invalid handle value.");
09968 }
09969 else
09970 print_usage ();
09971
09972 return octave_value ();
09973 }