diff src/graphics.cc @ 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 f317f14516cb
line wrap: on
line diff
--- a/src/graphics.cc	Wed Feb 27 21:45:12 2008 +0100
+++ b/src/graphics.cc	Fri Feb 29 17:38:32 2008 +0100
@@ -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)