Mercurial > hg > octave-lojdl
changeset 7849:3249f64f69b2
Initial low-level support for property listeners.
* * *
Make listeners work for all properties.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Fri, 29 Feb 2008 17:38:32 +0100 |
parents | 6bb2bbc2bf45 |
children | 56254a8d4d59 |
files | src/ChangeLog src/genprops.awk src/graphics.cc src/graphics.h.in |
diffstat | 4 files changed, 343 insertions(+), 103 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -27,6 +27,36 @@ 2008-06-04 Michael Goffioul <michael.goffioul@gmail.com> + * graphics.h.in (base_properties::get_property): Make virtual and + remove const modifier. + * graphics.cc (base_properties::get_property): Can return built-in + properties. Generate an error if the property does not exist. + (base_properties::add_listener): Use get_property. + (Fadd_listener): Add documentation. + * genprops.awk (emit_common_declarations, emit_source): Emit code for + overloaded get_property method. + + * genprops.awk (emit_declarations): Run listeners in the property + setter methods. + * graphics.h.in (enum listener_mode): New enum type for listeners. + (base_property::set): Make non-virtual and handle listeners execution. + (base_property::listeners): New field holding a map of listeners. + (base_property::add_listener, base_property::run_listeners, + base_property::do_set): New methods to handle listeners. + (property::add_listener, property::run_listeners): Likewise. + (base_properties::add_listener): Likewise. + (base_graphics_object::add_property_listener, + graphics_object::add_property_listener): Likewise. + (all property classes): Rename set to do_set and make it protected. + * graphics.cc (base_property::run_listeners): New method to execute + listeners. + (color_property::set, double_radio_property::set, + handle_property::set): Rename to do_set. + (base_properties::add_listener): New method to handle listener + additio. Only handle dynamic properties. + (Fadd_listener): New octave interface to add property listeners to + graphics object. + * genprops.awk (emit_get_data): Remove. (emit_declarations): Treat row_vector_property as array_property and remove data_property references.
--- a/src/genprops.awk +++ b/src/genprops.awk @@ -244,6 +244,7 @@ printf (" void set (const caseless_str& pname, const octave_value& val);\n\n"); printf (" octave_value get (bool all = false) const;\n\n"); printf (" octave_value get (const caseless_str& pname) const;\n\n"); + printf (" property get_property (const caseless_str& pname);\n\n"); printf (" std::string graphics_object_name (void) const { return go_name; }\n\n"); printf (" static property_list::pval_map_type factory_defaults (void);\n\n"); printf ("private:\n static std::string go_name;\n\n"); @@ -312,14 +313,21 @@ if (emit_set[i] == "definition") { - printf ("\n {\n if (! error_state)\n {\n %s = val;\n", - name[i]); + if (updaters[i] || limits[i] || mode[i]) + has_builtin_listeners = 1; + else + has_builtin_listeners = 0; + + printf ("\n {\n if (! error_state)\n {\n %s.set (val, %s);\n", + name[i], (has_builtin_listeners ? "false" : "true")); if (updater[i]) printf (" update_%s ();\n", name[i]); if (limits[i]) printf (" update_axis_limits (\"%s\");\n", name[i]); if (mode[i]) printf (" set_%smode (\"manual\");\n", name[i]); + if (has_builtin_listeners) + printf (" %s.run_listeners (POSTSET);\n", name[i]); printf (" mark_modified ();\n }\n }\n\n"); } else @@ -429,6 +437,22 @@ printf (" else\n retval = base_properties::get (pname);\n\n") >> filename; printf (" return retval;\n}\n\n") >> filename; + ## get_property method + + printf ("property\n%s::properties::get_property (const caseless_str& pname)\n{\n", + class_name) >> filename; + + for (i = 1; i<= idx; i++) + { + printf (" %sif (pname.compare (\"%s\"))\n", + (i > 1 ? "else " : ""), name[i]) >> filename; + printf (" return property (&%s, true);\n", name[i]) >> filename; + } + + printf (" else\n return base_properties::get_property (pname);\n") >> filename; + printf ("}\n\n") >> filename; + + ## factory defaults method printf ("property_list::pval_map_type\n%s::properties::factory_defaults (void)\n{\n",
--- a/src/graphics.cc +++ b/src/graphics.cc @@ -456,6 +456,20 @@ // --------------------------------------------------------------------- +void +base_property::run_listeners (listener_mode mode) +{ + const octave_value_list& l = listeners[mode]; + + for (int i = 0; i < l.length (); i++) + { + execute_callback (l(i), parent, octave_value ()); + + if (error_state) + break; + } +} + radio_values::radio_values (const std::string& opt_string) { size_t beg = 0; @@ -529,7 +543,7 @@ } void -color_property::set (const octave_value& val) +color_property::do_set (const octave_value& val) { if (val.is_string ()) { @@ -582,7 +596,7 @@ } void -double_radio_property::set (const octave_value& val) +double_radio_property::do_set (const octave_value& val) { if (val.is_string ()) { @@ -690,7 +704,7 @@ } void -handle_property::set (const octave_value& v) +handle_property::do_set (const octave_value& v) { double dv = v.double_value (); @@ -1367,14 +1381,54 @@ } property -base_properties::get_property (const caseless_str& name) const +base_properties::get_property (const caseless_str& name) { - std::map<caseless_str, property>::const_iterator it = all_props.find (name); - - if (it == all_props.end ()) - return property (); + if (name.compare ("beingdeleted")) + return property (&beingdeleted, true); + else if (name.compare ("busyaction")) + return property (&busyaction, true); + else if (name.compare ("buttondownfcn")) + return property (&buttondownfcn, true); + else if (name.compare ("clipping")) + return property (&clipping, true); + else if (name.compare ("createfcn")) + return property (&createfcn, true); + else if (name.compare ("deletefcn")) + return property (&deletefcn, true); + else if (name.compare ("handlevisibility")) + return property (&handlevisibility, true); + else if (name.compare ("hittest")) + return property (&hittest, true); + else if (name.compare ("interruptible")) + return property (&interruptible, true); + else if (name.compare ("parent")) + return property (&parent, true); + else if (name.compare ("selected")) + return property (&selected, true); + else if (name.compare ("selectionhighlight")) + return property (&selectionhighlight, true); + else if (name.compare ("tag")) + return property (&tag, true); + else if (name.compare ("type")) + return property (&userdata, true); + else if (name.compare ("userdata")) + return property (&visible, true); + else if (name.compare ("visible")) + return property (&visible, true); + else if (name.compare ("__modified__")) + return property (&__modified__, true); else - return it->second; + { + std::map<caseless_str, property>::const_iterator it = all_props.find (name); + + if (it == all_props.end ()) + { + error ("get_property: unknown property \"%s\"", name.c_str ()); + return property (); + } + else + return it->second; + } } void @@ -1494,6 +1548,16 @@ } } +void +base_properties::add_listener (const caseless_str& nm, const octave_value& v, + listener_mode mode) +{ + property p = get_property (nm); + + if (! error_state && p.ok ()) + p.add_listener (v, mode); +} + // --------------------------------------------------------------------- class gnuplot_backend : public base_graphics_backend @@ -3652,6 +3716,71 @@ return retval; } +DEFUN (add_listener, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} add_listener (@var{h}, @var{prop}, @var{fcn})\n\ +Register @var{fcn} as listener for the property @var{prop} of the graphics\n\ +object @var{h}. Property listeners are executed (in order of registration)\n\ +when the property is set. The new value is already available when the\n\ +listeners are executed.\n\ +\n\ +@var{prop} must be a string naming a valid property in @var{h}.\n\ +\n\ +@var{fcn} can be a function handle, a string or a cell array whose first\n\ +element is a function handle. If @var{fcn} is a function handle, the\n\ +corresponding function should accept at least 2 arguments, that will be\n\ +set to the object handle and the empty matrix respectively. If @var{fcn}\n\ +is a string, it must be any valid octave expression. If @var{fcn} is a cell\n\ +array, the first element must be a function handle with the same signature\n\ +as described above. The next elements of the cell array are passed\n\ +as additional arguments to the function.\n\ +\n\ +@example\n\ +function my_listener (h, dummy, p1)\n\ + fprintf (\"my_listener called with p1=%s\\n\", p1);\n\ +endfunction\n\ +\n\ +add_listener (gcf, \"position\", @{@@my_listener, \"my string\"@})\n\ +@end example\n\ +\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 3) + { + double h = args(0).double_value (); + + if (! error_state) + { + std::string pname = args(1).string_value (); + + if (! error_state) + { + graphics_handle gh = gh_manager::lookup (h); + + if (gh.ok ()) + { + graphics_object go = gh_manager::get_object (gh); + + go.add_property_listener (pname, args(2), POSTSET); + } + else + error ("add_listener: invalid graphics object (= %g)", + h); + } + else + error ("add_listener: invalid property name, expected a string value"); + } + else + error ("add_listener: invalid handle"); + } + else + print_usage (); + + return retval; +} + octave_value get_property_from_handle (double handle, const std::string& property, const std::string& func)
--- a/src/graphics.h.in +++ b/src/graphics.h.in @@ -339,6 +339,8 @@ class property; +enum listener_mode { POSTSET }; + class base_property { public: @@ -369,8 +371,13 @@ void set_hidden (bool flag) { hidden = flag; } - virtual void set (const octave_value&) - { error ("set: invalid property \"%s\"", name.c_str ()); } + void set (const octave_value& v, bool do_run = true) + { + do_set (v); + + if (do_run && ! error_state) + run_listeners (POSTSET); + } virtual octave_value get (void) const { @@ -384,11 +391,29 @@ return *this; } + void add_listener (const octave_value& v, listener_mode mode = POSTSET) + { + octave_value_list& l = listeners[mode]; + l.resize (l.length () + 1, v); + } + + OCTINTERP_API void run_listeners (listener_mode mode = POSTSET); + +protected: + virtual void do_set (const octave_value&) + { error ("set: invalid property \"%s\"", name.c_str ()); } + +private: + typedef std::map<listener_mode, octave_value_list> listener_map; + typedef std::map<listener_mode, octave_value_list>::iterator listener_map_iterator; + typedef std::map<listener_mode, octave_value_list>::const_iterator listener_map_const_iterator; + private: int count; std::string name; graphics_handle parent; bool hidden; + listener_map listeners; }; // --------------------------------------------------------------------- @@ -403,15 +428,6 @@ string_property (const string_property& p) : base_property (p), str (p.str) { } - void set (const octave_value& val) - { - if (val.is_string ()) - str = val.string_value (); - else - error ("set: invalid string property value for \"%s\"", - get_name ().c_str ()); - } - octave_value get (void) const { return octave_value (str); } @@ -423,6 +439,16 @@ return *this; } +protected: + void do_set (const octave_value& val) + { + if (val.is_string ()) + str = val.string_value (); + else + error ("set: invalid string property value for \"%s\"", + get_name ().c_str ()); + } + private: std::string str; }; @@ -495,7 +521,21 @@ radio_property (const radio_property& p) : base_property (p), vals (p.vals), current_val (p.current_val) { } - void set (const octave_value& newval) + octave_value get (void) const { return octave_value (current_val); } + + const std::string& current_value (void) const { return current_val; } + + bool is (const caseless_str& v) const + { return v.compare (current_val); } + + radio_property& operator = (const octave_value& val) + { + set (val); + return *this; + } + +protected: + void do_set (const octave_value& newval) { if (newval.is_string ()) { @@ -511,19 +551,6 @@ get_name ().c_str ()); } - octave_value get (void) const { return octave_value (current_val); } - - const std::string& current_value (void) const { return current_val; } - - bool is (const caseless_str& v) const - { return v.compare (current_val); } - - radio_property& operator = (const octave_value& val) - { - set (val); - return *this; - } - private: radio_values vals; std::string current_val; @@ -636,8 +663,6 @@ return current_val; } - OCTINTERP_API void set (const octave_value& newval); - bool is_rgb (void) const { return (current_type == color_t); } bool is_radio (void) const { return (current_type == radio_t); } @@ -669,6 +694,9 @@ operator octave_value (void) const { return get (); } +protected: + OCTINTERP_API void do_set (const octave_value& newval); + private: enum current_enum { color_t, radio_t } current_type; color_values color_val; @@ -689,15 +717,6 @@ double_property (const double_property& p) : base_property (p), current_val (p.current_val) { } - void set (const octave_value& v) - { - if (v.is_scalar_type () && v.is_real_type ()) - current_val = v.double_value (); - else - error ("set: invalid value for double property \"%s\"", - get_name ().c_str ()); - } - octave_value get (void) const { return octave_value (current_val); } double double_value (void) const { return current_val; } @@ -708,6 +727,16 @@ return *this; } +protected: + void do_set (const octave_value& v) + { + if (v.is_scalar_type () && v.is_real_type ()) + current_val = v.double_value (); + else + error ("set: invalid value for double property \"%s\"", + get_name ().c_str ()); + } + private: double current_val; }; @@ -745,8 +774,6 @@ return current_val; } - OCTINTERP_API void set (const octave_value& v); - bool is_double (void) const { return (current_type == double_t); } bool is_radio (void) const { return (current_type == radio_t); } @@ -778,6 +805,9 @@ operator octave_value (void) const { return get (); } +protected: + OCTINTERP_API void do_set (const octave_value& v); + private: enum current_enum { double_t, radio_t } current_type; double dval; @@ -812,19 +842,6 @@ octave_value get (void) const { return data; } - void set (const octave_value& v) - { - if (validate (v)) - { - data = v; - - get_data_limits (); - } - else - error ("invalid value for array property \"%s\"", - get_name ().c_str ()); - } - void add_constraint (const std::string& type) { type_constraints.push_back (type); } @@ -841,6 +858,20 @@ return *this; } +protected: + void do_set (const octave_value& v) + { + if (validate (v)) + { + data = v; + + get_data_limits (); + } + else + error ("invalid value for array property \"%s\"", + get_name ().c_str ()); + } + private: OCTINTERP_API bool validate (const octave_value& v); @@ -866,25 +897,6 @@ add_constraint (dim_vector (1, -1)); } - void set (const octave_value& v) - { - array_property::set (v); - - if (! error_state) - { - dim_vector dv = data.dims (); - - if (dv(0) > 1 && dv(1) == 1) - { - int tmp = dv(0); - dv(0) = dv(1); - dv(1) = tmp; - - data = data.reshape (dv); - } - } - } - void add_constraint (const std::string& type) { array_property::add_constraint (type); @@ -910,6 +922,26 @@ return *this; } +protected: + void do_set (const octave_value& v) + { + array_property::do_set (v); + + if (! error_state) + { + dim_vector dv = data.dims (); + + if (dv(0) > 1 && dv(1) == 1) + { + int tmp = dv(0); + dv(0) = dv(1); + dv(1) = tmp; + + data = data.reshape (dv); + } + } + } + private: OCTINTERP_API bool validate (const octave_value& v); }; @@ -932,14 +964,6 @@ bool_property (const bool_property& p) : radio_property (p) { } - void set (const octave_value& val) - { - if (val.is_bool_scalar ()) - radio_property::set (val.bool_value () ? "on" : "off"); - else - radio_property::set (val); - } - bool is_on (void) const { return is ("on"); } bool_property& operator = (const octave_value& val) @@ -947,6 +971,15 @@ set (val); return *this; } + +protected: + void do_set (const octave_value& val) + { + if (val.is_bool_scalar ()) + radio_property::do_set (val.bool_value () ? "on" : "off"); + else + radio_property::do_set (val); + } }; // --------------------------------------------------------------------- @@ -962,8 +995,6 @@ handle_property (const handle_property& p) : base_property (p), current_val (p.current_val) { } - OCTINTERP_API void set (const octave_value& v); - octave_value get (void) const { return current_val.as_octave_value (); } graphics_handle handle_value (void) const { return current_val; } @@ -980,6 +1011,9 @@ return *this; } +protected: + OCTINTERP_API void do_set (const octave_value& v); + private: graphics_handle current_val; }; @@ -995,14 +1029,15 @@ octave_value get (void) const { return data; } - void set (const octave_value& v) { data = v; } - any_property& operator = (const octave_value& val) { set (val); return *this; } +protected: + void do_set (const octave_value& v) { data = v; } + private: octave_value data; }; @@ -1018,15 +1053,6 @@ octave_value get (void) const { return callback; } - void set (const octave_value& v) - { - if (validate (v)) - callback = v; - else - error ("invalid value for callback property \"%s\"", - get_name ().c_str ()); - } - OCTINTERP_API void execute (const octave_value& data = octave_value ()) const; OCTINTERP_API static @@ -1040,6 +1066,16 @@ return *this; } +protected: + void do_set (const octave_value& v) + { + if (validate (v)) + callback = v; + else + error ("invalid value for callback property \"%s\"", + get_name ().c_str ()); + } + private: OCTINTERP_API bool validate (const octave_value& v) const; @@ -1114,6 +1150,12 @@ return *this; } + void add_listener (const octave_value& v, listener_mode mode = POSTSET) + { rep->add_listener (v, mode); } + + void run_listeners (listener_mode mode = POSTSET) + { rep->run_listeners (mode); } + /* const string_property& as_string_property (void) const { return *(dynamic_cast<string_property*> (rep)); } @@ -1412,7 +1454,7 @@ virtual octave_value get (bool all = false) const; - property get_property (const caseless_str&) const; + virtual property get_property (const caseless_str&); std::string get_tag (void) const { return tag.string_value (); } @@ -1477,6 +1519,9 @@ virtual void update_boundingbox (void); + virtual void add_listener (const caseless_str&, const octave_value&, + listener_mode = POSTSET); + void set_tag (const octave_value& val) { tag = val; } void set_parent (const octave_value& val); @@ -1885,6 +1930,14 @@ } } + virtual void add_property_listener (const std::string& nm, + const octave_value& v, + listener_mode mode = POSTSET) + { + if (valid_object ()) + get_properties ().add_listener (nm, v, mode); + } + protected: // A reference count. int count; @@ -2051,6 +2104,10 @@ graphics_backend get_backend (void) const { return rep->get_backend (); } + void add_property_listener (const std::string& nm, const octave_value& v, + listener_mode mode = POSTSET) + { rep->add_property_listener (nm, v, mode); } + private: base_graphics_object *rep; };