Index: src/graphics.h.in =================================================================== RCS file: /cvs/octave/src/graphics.h.in,v retrieving revision 1.49 diff -c -r1.49 graphics.h.in *** src/graphics.h.in 25 Jan 2008 08:24:48 -0000 1.49 --- src/graphics.h.in 28 Jan 2008 20:52:28 -0000 *************** *** 182,187 **** --- 182,310 ---- // --------------------------------------------------------------------- + class base_scaler + { + public: + base_scaler (void) { } + + virtual Matrix scale (const Matrix& m) const + { + error ("invalid axis scale"); + return m; + } + + virtual double scale (double d) const + { + error ("invalid axis scale"); + return d; + } + + virtual double unscale (double d) const + { + error ("invalid axis scale"); + return d; + } + + virtual base_scaler* clone () const + { return new base_scaler (); } + }; + + class lin_scaler : public base_scaler + { + public: + lin_scaler (void) { } + + Matrix scale (const Matrix& m) const { return m; } + + double scale (double d) const { return d; } + + double unscale (double d) const { return d; } + + base_scaler* clone (void) const { return new lin_scaler (); } + }; + + class log_scaler : public base_scaler + { + public: + log_scaler (void) { } + + Matrix scale (const Matrix& m) const + { + Matrix retval (m.rows (), m.cols ()); + const double *d1 = m.fortran_vec (); + double *d2 = retval.fortran_vec (); + + for (int i = 0; i < m.numel (); i++) + d2[i] = log10 (d1[i]); + + return retval; + } + + double scale (double d) const + { return log10 (d); } + + double unscale (double d) const + { return pow (10.0, d); } + + base_scaler* clone (void) const + { return new log_scaler (); } + }; + + class scaler + { + public: + scaler (void) : rep (new base_scaler ()) { } + + scaler (const scaler& s) : rep (s.rep->clone()) { } + + ~scaler (void) { delete rep; } + + Matrix scale (const Matrix& m) const + { return rep->scale (m); } + + double scale (double d) const + { return rep->scale (d); } + + double unscale (double d) const + { return rep->unscale (d); } + + scaler& operator = (const scaler& s) + { + if (rep) + { + delete rep; + rep = 0; + } + + rep = s.rep->clone (); + + return *this; + } + + scaler& operator = (const std::string& s) + { + if (rep) + { + delete rep; + rep = 0; + } + + if (s == "log") + rep = new log_scaler (); + else if (s == "linear") + rep = new lin_scaler (); + else + rep = new base_scaler (); + + return *this; + } + + private: + base_scaler *rep; + }; + + // --------------------------------------------------------------------- + class property; class base_property *************** *** 989,994 **** --- 1112,1123 ---- return Matrix (1, 2, 0.0); } + virtual double get_screen_resolution (void) const + { + error ("get_screen_resolution: invalid graphics backend"); + return -1; + } + private: std::string name; int count; *************** *** 1053,1058 **** --- 1182,1190 ---- Matrix get_canvas_size (const graphics_handle& fh) const { return rep->get_canvas_size (fh); } + double get_screen_resolution (void) const + { return rep->get_screen_resolution (); } + OCTINTERP_API static graphics_backend default_backend (void); static void register_backend (const graphics_backend& b) *************** *** 2046,2056 **** void delete_children (void); // See the genprops.awk script for an explanation of the // properties declarations. BEGIN_PROPERTIES(axes) ! array_property position , Matrix () mutable handle_property title GSO , graphics_handle () bool_property box , "on" bool_property key , "off" --- 2178,2208 ---- void delete_children (void); + const scaler& get_x_scaler (void) const { return sx; } + const scaler& get_y_scaler (void) const { return sy; } + const scaler& get_z_scaler (void) const { return sz; } + + Matrix get_boundingbox (void) const; + + void update_camera (void); + void update_aspectratios (void); + void update_transform (void) + { + update_aspectratios (); + update_camera (); + } + + private: + scaler sx, sy, sz; + Matrix x_render, x_render_inv; + Matrix x_gl_mat1, x_gl_mat2; + Matrix x_zlim; + // See the genprops.awk script for an explanation of the // properties declarations. BEGIN_PROPERTIES(axes) ! array_property position , default_axes_position () mutable handle_property title GSO , graphics_handle () bool_property box , "on" bool_property key , "off" *************** *** 2099,2115 **** color_property xcolor , color_values (0, 0, 0) color_property ycolor , color_values (0, 0, 0) color_property zcolor , color_values (0, 0, 0) ! radio_property xscale al , "{linear}|log" ! radio_property yscale al , "{linear}|log" ! radio_property zscale al , "{linear}|log" ! radio_property xdir , "{normal}|reverse" ! radio_property ydir , "{normal}|reverse" ! radio_property zdir , "{normal}|reverse" radio_property yaxislocation , "{left}|right|zero" radio_property xaxislocation , "{bottom}|top|zero" ! array_property view , Matrix () radio_property nextplot , "add|replace_children|{replace}" ! array_property outerposition , Matrix () radio_property activepositionproperty , "{outerposition}|position" radio_property __colorbar__ h , "{none}|north|south|east|west|northoutside|southoutside|eastoutside|westoutside" color_property ambientlightcolor , color_values (1, 1, 1) --- 2251,2267 ---- color_property xcolor , color_values (0, 0, 0) color_property ycolor , color_values (0, 0, 0) color_property zcolor , color_values (0, 0, 0) ! radio_property xscale alu , "{linear}|log" ! radio_property yscale alu , "{linear}|log" ! radio_property zscale alu , "{linear}|log" ! radio_property xdir u , "{normal}|reverse" ! radio_property ydir u , "{normal}|reverse" ! radio_property zdir u , "{normal}|reverse" radio_property yaxislocation , "{left}|right|zero" radio_property xaxislocation , "{bottom}|top|zero" ! array_property view u , Matrix () radio_property nextplot , "add|replace_children|{replace}" ! array_property outerposition , default_axes_outerposition () radio_property activepositionproperty , "{outerposition}|position" radio_property __colorbar__ h , "{none}|north|south|east|west|northoutside|southoutside|eastoutside|westoutside" color_property ambientlightcolor , color_values (1, 1, 1) *************** *** 2179,2185 **** --- 2331,2353 ---- currentpoint.add_constraint (dim_vector (2, 3)); ticklength.add_constraint (dim_vector (1, 2)); tightinset.add_constraint (dim_vector (1, 4)); + + x_zlim.resize (1, 2); + sx = "linear"; + sy = "linear"; + sz = "linear"; } + + private: + void update_xscale (void) { sx = get_xscale (); } + void update_yscale (void) { sy = get_yscale (); } + void update_zscale (void) { sz = get_zscale (); } + + void update_view (void) { update_camera (); } + + void update_xdir (void) { update_camera (); } + void update_ydir (void) { update_camera (); } + void update_zdir (void) { update_camera (); } }; private: Index: src/graphics.cc =================================================================== RCS file: /cvs/octave/src/graphics.cc,v retrieving revision 1.79 diff -c -r1.79 graphics.cc *** src/graphics.cc 25 Jan 2008 08:24:48 -0000 1.79 --- src/graphics.cc 28 Jan 2008 20:52:30 -0000 *************** *** 142,147 **** --- 142,166 ---- return retval; } + static Matrix + default_axes_position (void) + { + Matrix m (1, 4, 0.0); + m(0) = 0.13; + m(1) = 0.11; + m(2) = 0.775; + m(3) = 0.815; + return m; + } + + static Matrix + default_axes_outerposition (void) + { + Matrix m (1, 4, 0.0); + m(2) = m(3) = 1.0; + return m; + } + // NOTE: "cb" is passed by value, because "function_value" method // is non-const; passing "cb" by const-reference is not // possible *************** *** 200,205 **** --- 219,308 ---- END_INTERRUPT_WITH_EXCEPTIONS; } + static Matrix + convert_position (const Matrix& pos, const caseless_str& from_units, + const caseless_str& to_units, + const Matrix& parent_dim = Matrix (1, 2, 0.0), + const graphics_backend& backend = graphics_backend ()) + { + Matrix retval (1, 4); + double res = 0; + + if (from_units.compare ("pixels")) + retval = pos; + else if (from_units.compare ("normalized")) + { + retval(0) = pos(0) * parent_dim(0) + 1; + retval(1) = pos(1) * parent_dim(1) + 1; + retval(2) = pos(2) * parent_dim(0); + retval(3) = pos(3) * parent_dim(1); + } + else if (from_units.compare ("characters")) + { + // FIXME: implement this + } + else + { + res = backend.get_screen_resolution (); + + double f = 0.0; + + if (from_units.compare ("points")) + f = res / 72.0; + else if (from_units.compare ("inches")) + f = res; + else if (from_units.compare ("centimeters")) + f = res / 2.54; + + if (f > 0) + { + retval(0) = pos(0) * f + 1; + retval(1) = pos(1) * f + 1; + retval(2) = pos(2) * f; + retval(3) = pos(3) * f; + } + } + + if (! to_units.compare ("pixels")) + { + if (to_units.compare ("normalized")) + { + retval(0) = (retval(0) - 1) / parent_dim(0); + retval(1) = (retval(1) - 1) / parent_dim(1); + retval(2) /= parent_dim(0); + retval(3) /= parent_dim(1); + } + else if (to_units.compare ("characters")) + { + // FIXME: implement this + } + else + { + if (res <= 0) + res = backend.get_screen_resolution (); + + double f = 0.0; + + if (to_units.compare ("points")) + f = res / 72.0; + else if (to_units.compare ("inches")) + f = res; + else if (to_units.compare ("centimeters")) + f = res / 2.54; + + if (f > 0) + { + retval(0) = (retval(0) - 1) / f; + retval(1) = (retval(1) - 1) / f; + retval(2) /= f; + retval(3) /= f; + } + } + } + + return retval; + } + // --------------------------------------------------------------------- radio_values::radio_values (const std::string& opt_string) *************** *** 1208,1214 **** } Matrix get_canvas_size (const graphics_handle&) const ! { return Matrix (1, 2, 0.0); } }; graphics_backend --- 1311,1323 ---- } Matrix get_canvas_size (const graphics_handle&) const ! { ! Matrix sz (1, 2, 0.0); ! return sz; ! } ! ! double get_screen_resolution (void) const ! { return 72.0; } }; graphics_backend *************** *** 1365,1371 **** axes::properties::set_defaults (base_graphics_object& obj, const std::string& mode) { ! position = Matrix (); title = graphics_handle (); box = "on"; key = "off"; --- 1474,1480 ---- axes::properties::set_defaults (base_graphics_object& obj, const std::string& mode) { ! position = default_axes_position (); title = graphics_handle (); box = "on"; key = "off"; *************** *** 1424,1429 **** --- 1533,1566 ---- yaxislocation = "left"; xaxislocation = "bottom"; + // Note: camera properties will be set through update_transform + camerapositionmode = "auto"; + cameratargetmode = "auto"; + cameraupvectormode = "auto"; + cameraviewanglemode = "auto"; + plotboxaspectratio = Matrix (1, 3, 1.0); + drawmode = "normal"; + fontangle = "normal"; + fontname = "Helvetica"; + fontsize = 12; + fontunits = "points"; + fontweight = "normal"; + gridlinestyle = "-"; + linestyleorder = "-"; + linewidth = 0.5; + minorgridlinestyle = "-"; + // Note: plotboxaspectratio will be set through update_aspectratiors + plotboxaspectratiomode = "auto"; + projection = "orthographic"; + tickdir = "in"; + tickdirmode = "auto"; + ticklength = Matrix (1, 2, 0.1); + tightinset = Matrix (1, 4, 0.0); + + sx = "linear"; + sy = "linear"; + sz = "linear"; + Matrix tview (1, 2, 0.0); tview(1) = 90; view = tview; *************** *** 1449,1454 **** --- 1586,1593 ---- children = Matrix (); + update_transform (); + override_defaults (obj); } *************** *** 1514,1519 **** --- 1653,2073 ---- gh_manager::free (zlabel.handle_value ()); } + inline Matrix + xform_matrix (void) + { + Matrix m (4, 4, 0.0); + for (int i = 0; i < 4; i++) + m(i,i) = 1; + return m; + } + + inline ColumnVector + xform_vector (void) + { + ColumnVector v (4, 0.0); + v(3) = 1; + return v; + } + + inline ColumnVector + xform_vector (double x, double y, double z) + { + ColumnVector v (4, 1.0); + v(0) = x; v(1) = y; v(2) = z; + return v; + } + + inline ColumnVector + transform (const Matrix& m, double x, double y, double z) + { + return (m * xform_vector (x, y, z)); + } + + inline Matrix + xform_scale (double x, double y, double z) + { + Matrix m (4, 4, 0.0); + m(0,0) = x; m(1,1) = y; m(2,2) = z; m(3,3) = 1; + return m; + } + + inline Matrix + xform_translate (double x, double y, double z) + { + Matrix m = xform_matrix (); + m(0,3) = x; m(1,3) = y; m(2,3) = z; m(3,3) = 1; + return m; + } + + inline void + scale (Matrix& m, double x, double y, double z) + { + m = m * xform_scale (x, y, z); + } + + inline void + translate (Matrix& m, double x, double y, double z) + { + m = m * xform_translate (x, y, z); + } + + inline void + xform (ColumnVector& v, const Matrix& m) + { + v = m*v; + } + + inline void + scale (ColumnVector& v, double x, double y, double z) + { + v(0) *= x; + v(1) *= y; + v(2) *= z; + } + + inline void + translate (ColumnVector& v, double x, double y, double z) + { + v(0) += x; + v(1) += y; + v(2) += z; + } + + inline void + normalize (ColumnVector& v) + { + double fact = 1.0/sqrt(v(0)*v(0)+v(1)*v(1)+v(2)*v(2)); + scale (v, fact, fact, fact); + } + + inline double + dot (const ColumnVector& v1, const ColumnVector& v2) + { + return (v1(0)*v2(0)+v1(1)*v2(1)+v1(2)*v2(2)); + } + + inline double + norm (const ColumnVector& v) + { + return sqrt (dot (v, v)); + } + + inline ColumnVector + cross (const ColumnVector& v1, const ColumnVector& v2) + { + ColumnVector r = xform_vector (); + r(0) = v1(1)*v2(2)-v1(2)*v2(1); + r(1) = v1(2)*v2(0)-v1(0)*v2(2); + r(2) = v1(0)*v2(1)-v1(1)*v2(0); + return r; + } + + inline Matrix + unit_cube (void) + { + static double data[32] = { + 0,0,0,1, + 1,0,0,1, + 0,1,0,1, + 0,0,1,1, + 1,1,0,1, + 1,0,1,1, + 0,1,1,1, + 1,1,1,1}; + Matrix m (4, 8); + memcpy (m.fortran_vec (), data, sizeof(double)*32); + return m; + } + + inline ColumnVector + cam2xform (const Array& m) + { + ColumnVector retval (4, 1.0); + memcpy (retval.fortran_vec (), m.fortran_vec (), sizeof(double)*3); + return retval; + } + + inline RowVector + xform2cam (const ColumnVector& v) + { + return v.extract_n (0, 3).transpose (); + } + + void + axes::properties::update_camera (void) + { + double xd = (xdir_is ("normal") ? 1 : -1); + double yd = (ydir_is ("normal") ? 1 : -1); + double zd = (zdir_is ("normal") ? 1 : -1); + + Matrix xlim = sx.scale (get_xlim ().matrix_value ()); + Matrix ylim = sy.scale (get_ylim ().matrix_value ()); + Matrix zlim = sz.scale (get_zlim ().matrix_value ()); + + double xo = xlim(xd > 0 ? 0 : 1); + double yo = ylim(yd > 0 ? 0 : 1); + double zo = zlim(zd > 0 ? 0 : 1); + + Matrix pb = get_plotboxaspectratio ().matrix_value (); + + bool autocam = (camerapositionmode_is ("auto") + && cameratargetmode_is ("auto") + && cameraupvectormode_is ("auto") + && cameraviewanglemode_is ("auto")); + bool dowarp = (autocam && dataaspectratiomode_is("auto") + && plotboxaspectratiomode_is ("auto")); + + ColumnVector c_eye (xform_vector ()); + ColumnVector c_center (xform_vector ()); + ColumnVector c_upv (xform_vector ()); + + if (cameratargetmode_is ("auto")) + { + c_center(0) = (xlim(0)+xlim(1))/2; + c_center(1) = (ylim(0)+ylim(1))/2; + c_center(2) = (zlim(0)+zlim(1))/2; + + cameratarget = xform2cam (c_center); + } + else + c_center = cam2xform (get_cameratarget ().matrix_value ()); + + if (camerapositionmode_is ("auto")) + { + Matrix view = get_view ().matrix_value (); + double az = view(0), el = view(1); + double d = 5*sqrt(pb(0)*pb(0)+pb(1)*pb(1)+pb(2)*pb(2)); + + if (el == 90 || el == -90) + c_eye(2) = d*signum(el); + else + { + az *= M_PI/180.0; + el *= M_PI/180.0; + c_eye(0) = d*cos(el)*sin(az); + c_eye(1) = -d*cos(el)*cos(az); + c_eye(2) = d*sin(el); + } + c_eye(0) = c_eye(0)*(xlim(1)-xlim(0))/(xd*pb(0))+c_center(0); + c_eye(1) = c_eye(1)*(ylim(1)-ylim(0))/(yd*pb(1))+c_center(1); + c_eye(2) = c_eye(2)*(zlim(1)-zlim(0))/(zd*pb(2))+c_center(2); + + cameraposition = xform2cam (c_eye); + } + else + c_eye = cam2xform (get_cameraposition ().matrix_value ()); + + if (cameraupvectormode_is ("auto")) + { + Matrix view = get_view ().matrix_value (); + double az = view(0), el = view(1); + + if (el == 90 || el == -90) + { + c_upv(0) = -sin(az*M_PI/180.0)*(xlim(1)-xlim(0))/pb(0); + c_upv(1) = cos(az*M_PI/180.0)*(ylim(1)-ylim(0))/pb(1); + } + else + c_upv(2) = 1; + + cameraupvector = xform2cam (c_upv); + } + else + c_upv = cam2xform (get_cameraupvector ().matrix_value ()); + + Matrix x_view = xform_matrix (); + Matrix x_projection = xform_matrix (); + Matrix x_viewport = xform_matrix (); + Matrix x_normrender = xform_matrix (); + Matrix x_pre = xform_matrix (); + + x_render = xform_matrix (); + x_render_inv = xform_matrix (); + + scale (x_pre, pb(0), pb(1), pb(2)); + translate (x_pre, -0.5, -0.5, -0.5); + scale (x_pre, xd/(xlim(1)-xlim(0)), yd/(ylim(1)-ylim(0)), + zd/(zlim(1)-zlim(0))); + translate (x_pre, -xo, -yo, -zo); + + xform (c_eye, x_pre); + xform (c_center, x_pre); + scale (c_upv, pb(0)/(xlim(1)-xlim(0)), pb(1)/(ylim(1)-ylim(0)), + pb(2)/(zlim(1)-zlim(0))); + translate (c_center, -c_eye(0), -c_eye(1), -c_eye(2)); + + ColumnVector F (c_center), f (F), UP (c_upv); + normalize (f); + normalize (UP); + + if (abs (dot (f, UP)) > 1e-15) + { + double fa = 1/sqrt(1-f(2)*f(2)); + scale (UP, fa, fa, fa); + } + + ColumnVector s = cross (f, UP); + ColumnVector u = cross (s, f); + + scale (x_view, 1, 1, -1); + Matrix l = xform_matrix (); + l(0,0) = s(0); l(0,1) = s(1); l(0,2) = s(2); + l(1,0) = u(0); l(1,1) = u(1); l(1,2) = u(2); + l(2,0) = -f(0); l(2,1) = -f(1); l(2,2) = -f(2); + x_view = x_view * l; + translate (x_view, -c_eye(0), -c_eye(1), -c_eye(2)); + scale (x_view, pb(0), pb(1), pb(2)); + translate (x_view, -0.5, -0.5, -0.5); + + Matrix x_cube = x_view * unit_cube (); + ColumnVector cmin = x_cube.row_min (), cmax = x_cube.row_max (); + double xM = cmax(0)-cmin(0); + double yM = cmax(1)-cmin(1); + + Matrix bb = get_boundingbox (); + Matrix cs = get_backend ().get_canvas_size (__myhandle__); + double fh = cs(1); + + double v_angle; + + if (cameraviewanglemode_is ("auto")) + { + double af; + + // FIXME: Was this really needed? When compared to Matlab, it + // does not seem to be required. Need investigation with concrete + // backend to see results visually. + if (false && dowarp) + af = 1.0 / (xM > yM ? xM : yM); + else + { + if ((bb(2)/bb(3)) > (xM/yM)) + af = 1.0 / yM; + else + af = 1.0 / xM; + } + v_angle = 2 * (180.0 / M_PI) * atan (1 / (2 * af * norm (F))); + + cameraviewangle = v_angle; + } + else + v_angle = get_cameraviewangle (); + + double pf = 1 / (2 * tan ((v_angle / 2) * M_PI / 180.0) * norm (F)); + scale (x_projection, pf, pf, 1); + + if (dowarp) + { + xM *= pf; + yM *= pf; + translate (x_viewport, bb(0)+bb(2)/2, fh-(bb(1)+bb(3)/2)+1, 0); + scale (x_viewport, bb(2)/xM, -bb(3)/yM, 1); + } + else + { + double pix = 1; + if (autocam) + { + if ((bb(2)/bb(3)) > (xM/yM)) + pix = bb(3); + else + pix = bb(2); + } + else + pix = (bb(2) < bb(3) ? bb(2) : bb(3)); + translate (x_viewport, bb(0)+bb(2)/2, fh-(bb(1)+bb(3)/2)+1, 0); + scale (x_viewport, pix, -pix, 1); + } + + x_normrender = x_viewport * x_projection * x_view; + + x_cube = x_normrender * unit_cube (); + cmin = x_cube.row_min (); + cmax = x_cube.row_max (); + x_zlim.resize (1, 2); + x_zlim(0) = cmin(2); + x_zlim(1) = cmax(2); + + x_render = x_normrender; + scale (x_render, xd/(xlim(1)-xlim(0)), yd/(ylim(1)-ylim(0)), + zd/(zlim(1)-zlim(0))); + translate (x_render, -xo, -yo, -zo); + + x_viewtransform = x_view; + x_projectiontransform = x_projection; + x_viewporttransform = x_viewport; + x_normrendertransform = x_normrender; + x_rendertransform = x_render; + + x_render_inv = x_render.inverse (); + + // Note: these matrices are a slight modified version of the regular + // matrices, more suited for OpenGL rendering (x_gl_mat1 => light + // => x_gl_mat2) + x_gl_mat1 = x_view; + scale (x_gl_mat1, xd/(xlim(1)-xlim(0)), yd/(ylim(1)-ylim(0)), + zd/(zlim(1)-zlim(0))); + translate (x_gl_mat1, -xo, -yo, -zo); + x_gl_mat2 = x_viewport * x_projection; + } + + void + axes::properties::update_aspectratios (void) + { + Matrix xlim = get_xlim ().matrix_value (); + Matrix ylim = get_ylim ().matrix_value (); + Matrix zlim = get_zlim ().matrix_value (); + + double dx = (xlim(1)-xlim(0)); + double dy = (ylim(1)-ylim(0)); + double dz = (zlim(1)-zlim(0)); + + if (dataaspectratiomode_is ("auto")) + { + double dmin = xmin (xmin (dx, dy), dz); + Matrix da (1, 3, 0.0); + + da(0) = dx/dmin; + da(1) = dy/dmin; + da(2) = dz/dmin; + + dataaspectratio = da; + } + + if (plotboxaspectratiomode_is ("auto")) + { + if (dataaspectratiomode_is ("auto")) + plotboxaspectratio = Matrix (1, 3, 1.0); + else + { + Matrix da = get_dataaspectratio ().matrix_value (); + Matrix pba (1, 3, 0.0); + + pba(0) = dx/da(0); + pba(1) = dy/da(1); + pba(2) = dz/da(2); + } + } + + // FIXME: if plotboxaspectratiomode is "manual", limits + // and/or dataaspectratio might be adapted + } + + Matrix + axes::properties::get_boundingbox (void) const + { + graphics_backend b = get_backend (); + Matrix pos; + + pos = convert_position (get_position ().matrix_value (), get_units (), + "pixels", b.get_canvas_size (__myhandle__), b); + pos(0)--; + pos(1)--; + + return pos; + } + octave_value axes::get_default (const caseless_str& name) const { *************** *** 1778,1783 **** --- 2332,2339 ---- break; } + xproperties.update_transform (); + unwind_protect::run (); } Index: src/genprops.awk =================================================================== RCS file: /cvs/octave/src/genprops.awk,v retrieving revision 1.17 diff -c -r1.17 genprops.awk *** src/genprops.awk 19 Jan 2008 07:42:15 -0000 1.17 --- src/genprops.awk 28 Jan 2008 20:52:30 -0000 *************** *** 108,113 **** --- 108,126 ---- ## ## h: Make the property hidden ## + ## r: Make the property read-only. A read-only property is not + ## settable from the global set (caseless_str, octave_value) + ## method, but still has set_X accessor. + ## + ## u: The property has an updater method. This effectively add + ## the line + ## + ## update_NAME (); + ## + ## to the type-specific set function. This line is added before + ## any other update call (like those added by the 'l' or 'm' + ## modifiers. + ## ## The 'o' and 'O' qualifiers are only useful when the the property type ## is something other than octave_value. *************** *** 275,280 **** --- 288,295 ---- { printf ("\n {\n if (! error_state)\n {\n %s = val;\n", name[i]); + if (updater[i]) + printf (" %s ();\n", updater[i]); if (limits[i]) printf (" update_axis_limits (\"%s\");\n", name[i]); if (mode[i]) *************** *** 465,470 **** --- 480,486 ---- emit_get[idx] = "definition"; emit_set[idx] = "definition"; defval[idx] = ""; + updater[idx] = ""; ## if (type[idx] == "octave_value") ## emit_ov_set[idx] = ""; ## else *************** *** 510,515 **** --- 526,536 ---- if (index (quals, "r")) readonly[idx] = 1; + ## There is an updater method that should be called + ## from the set method + if (index (quals, "u")) + updater[idx] = ("update_" name[idx]); + ## ## emmit an asignment set function ## if (index (quals, "a")) ## emit_ov_set[idx] = "assignment";