changeset 9442:2d73b19c5507

improve behavior of builtin
author John W. Eaton <jwe@octave.org>
date Tue, 21 Jul 2009 12:43:33 -0400
parents 160c564d5d25
children 8f9d8776d11c
files src/ChangeLog src/DLD-FUNCTIONS/dispatch.cc src/DLD-FUNCTIONS/fltk_backend.cc src/graphics.cc src/graphics.h.in src/symtab.cc src/symtab.h
diffstat 7 files changed, 359 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/ChangeLog	Tue Jul 21 12:43:33 2009 -0400
@@ -1,3 +1,14 @@
+2009-07-21  John W. Eaton  <jwe@octave.org>
+
+	* symtab.cc (symbol_table::builtin_find,
+	symbol_table::do_builtin_find,
+	symbol_table::fcn_info::builtin_find,
+	symbol_table::fcn_info::fcn_info_rep::builtin_find,
+	symbol_table::fcn_info::fcn_info_rep::x_builtin_find): New functions.
+	* symtab.h: Provide decls.
+	* DLD-FUNCTIONS/dispatch.cc (Fbuiltin): Call
+	symbol_table::builtin_find instead of symbol_table::find_function.
+
 2009-07-20  Aleksej Saushev  <asau@inbox.ru>
 
 	* sysdep.cc: Also define BSD_init if __NetBSD__ is defined.
--- a/src/DLD-FUNCTIONS/dispatch.cc	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/DLD-FUNCTIONS/dispatch.cc	Tue Jul 21 12:43:33 2009 -0400
@@ -58,7 +58,7 @@
  
       if (! error_state)
 	{
-	  octave_value fcn = symbol_table::find_function (name);
+	  octave_value fcn = symbol_table::builtin_find (name);
 
 	  if (fcn.is_defined ())
 	    retval = feval (fcn.function_value (), args.splice (0, 1),
--- a/src/DLD-FUNCTIONS/fltk_backend.cc	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/DLD-FUNCTIONS/fltk_backend.cc	Tue Jul 21 12:43:33 2009 -0400
@@ -334,30 +334,34 @@
       }
   }
 
-  graphics_handle pixel2axes (int /* px */, int /* py */)
+  graphics_handle pixel2axes (int px, int py )
   {
     Matrix kids = fp.get_children ();
+    int len = kids.length ();
 
-    for (octave_idx_type n = 0; n < kids.numel (); n++)
+    for (int k = 0; k < len; k++)
       {
-	graphics_object ax = gh_manager::get_object (kids (n));
-	if (ax && ax.isa ("axes"))
+	graphics_handle hnd = gh_manager::lookup (kids(k));
+
+	if (hnd.ok ())
 	  {
-#if 0
-	     axes::properties& ap =
-	       dynamic_cast<axes::properties&> (ax.get_properties ());
+	    graphics_object child = gh_manager::get_object (hnd);
+
+	    if (child.valid_object () && child.isa ("axes"))
+	      {
+		Matrix bb = child.get_properties ().get_boundingbox (true);
 
-	     // std::cout << "\npixpos="<<pixpos<<"(px,py)=("<<px<<","<<py<<")\n";
-	     if (px >= pixpos(0) && px <= pixpos(2)
-		 && py >= pixpos(1) && py <= pixpos(3))
-	       return ap.get___myhandle__ ();
-#endif
+		if (bb(0) <= px && px < (bb(0)+bb(2))
+		    && bb(1) <= py && py < (bb(1)+bb(3)))
+		  {
+		    return hnd;
+		  }
+	      }
 	  }
       }
-
-    return graphics_handle ();
+    return graphics_handle();
   }
-
+  
   void pixel2status (int px0, int py0, int px1 = -1, int py1 = -1)
   {
     double x0, y0, x1, y1;
@@ -442,63 +446,60 @@
 	pixel2status (px0, py0, Fl::event_x (), Fl::event_y ());
 	if (Fl::event_button () == 1)
 	  {
-	    canvas->zoom (true);
-	    Matrix zoom_box (1,4,0);
-	    zoom_box (0) = px0;
-	    zoom_box (1) = py0;
-	    zoom_box (2) =  Fl::event_x ();
-	    zoom_box (3) =  Fl::event_y ();
-	    canvas->set_zoom_box (zoom_box);
-	    canvas->redraw_overlay ();
+	    graphics_handle hnd = pixel2axes (px0, py0);
+	    graphics_object ax = gh_manager::get_object (fp.get_currentaxes ());
+	    if (hnd.ok ()) 
+	      ax = gh_manager::get_object (hnd);
+
+            if (ax && ax.isa ("axes"))
+              {
+                axes::properties& ap = dynamic_cast<axes::properties&> (ax.get_properties ());
+              
+                double x0, y0, x1, y1;
+                pixel2pos (px0, py0, x0, y0);
+                pixel2pos (Fl::event_x (), Fl::event_y (), x1, y1);
+                px0 = Fl::event_x ();
+                py0 = Fl::event_y ();
+
+                ap.translate_view (x0 - x1, y0 - y1);
+                mark_modified ();
+              }
 	    return 1;
 	  }
 	break;
 
+      case FL_MOUSEWHEEL:
+        {
+          // Parameter controlling how fast we zoom. FIXME: Should this be user tweakable?
+          const double zoom_speed = 0.05;
+
+	  graphics_object ax = gh_manager::get_object (fp.get_currentaxes ());
+	  graphics_handle hnd = pixel2axes (Fl::event_x (), Fl::event_y ());
+	  if (hnd.ok ()) 
+	    ax = gh_manager::get_object (hnd);
+
+          if (ax && ax.isa ("axes"))
+            {
+              axes::properties& ap = dynamic_cast<axes::properties&> (ax.get_properties ());
+              
+              // Determine if we're zooming in or out
+              const double factor = (Fl::event_dy () > 0) ? 1.0 + zoom_speed : 1.0 - zoom_speed;
+              
+              // Get the point we're zooming about
+              double x1, y1;
+              pixel2pos (Fl::event_x (), Fl::event_y (), x1, y1);
+              
+              ap.zoom_about_point (x1, y1, factor, false);
+              mark_modified ();
+            }
+	}
+      return 1;
+
       case FL_RELEASE:
 	if (Fl::event_button () == 1)
 	  {
-	    // end of drag -- zoom
-	    if (canvas->zoom ())
-	      {
-		canvas->zoom (false);
-		double x0,y0,x1,y1;
-		graphics_object ax =
-		  gh_manager::get_object (fp.get_currentaxes ());
-		if (ax && ax.isa ("axes"))
-		  {
-		    axes::properties& ap =
-		      dynamic_cast<axes::properties&> (ax.get_properties ());
-		    pixel2pos (px0, py0, x0, y0);
-		    pixel2pos (Fl::event_x (), Fl::event_y (), x1, y1);
-		    Matrix xl (1,2,0);
-		    Matrix yl (1,2,0);
-		    if (x0 < x1)
-		      {
-			xl(0) = x0;
-			xl(1) = x1;
-		      }
-		    else
-		      {
-			xl(0) = x1;
-			xl(1) = x0;
-		      }
-
-		    if (y0 < y1)
-		      {
-			yl(0) = y0;
-			yl(1) = y1;
-		      }
-		    else
-		      {
-			yl(0) = y1;
-			yl(1) = y0;
-		      }
-		    ap.zoom (xl, yl);
-		    mark_modified ();
-		  }
-	      }
 	    // one click -- select axes
-	    else if ( Fl::event_clicks () == 0)
+	    if ( Fl::event_clicks () == 0)
 	      {
 		std::cout << "ca="<< h0.value ()<<"\n";
 		if (h0.ok ())
--- a/src/graphics.cc	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/graphics.cc	Tue Jul 21 12:43:33 2009 -0400
@@ -3466,7 +3466,7 @@
   labels = c;
 }
 
-static void
+void
 get_children_limits (double& min_val, double& max_val, double& min_pos,
 		     const Matrix& kids, char limit_type)
 {
@@ -3704,14 +3704,63 @@
   unwind_protect::run ();
 }
 
+inline
+double force_in_range (const double x, const double lower, const double upper)
+{
+  if (x < lower)
+    { return lower; }
+  else if (x > upper)
+    { return upper; }
+  else
+    { return x; }  
+}
+
 void
-axes::properties::zoom (const Matrix& xl, const Matrix& yl)
-{
-  zoom_stack.push_front (xlimmode.get ());
-  zoom_stack.push_front (xlim.get ());
-  zoom_stack.push_front (ylimmode.get ());
-  zoom_stack.push_front (ylim.get ());
-
+axes::properties::zoom_about_point (double x, double y, double factor,
+                                    bool push_to_zoom_stack)
+{
+  // FIXME: Do we need error checking here?
+  Matrix xlims = get_xlim ().matrix_value ();
+  Matrix ylims = get_ylim ().matrix_value ();
+              
+  // Get children axes limits
+  Matrix kids = get_children ();
+  double minx = octave_Inf;
+  double maxx = -octave_Inf;
+  double min_pos_x = octave_Inf;
+  get_children_limits (minx, maxx, min_pos_x, kids, 'x');
+
+  double miny = octave_Inf;
+  double maxy = -octave_Inf;
+  double min_pos_y = octave_Inf;
+  get_children_limits (miny, maxy, min_pos_y, kids, 'y');
+              
+  // Perform the zooming
+  xlims (0) = x + factor * (xlims (0) - x);
+  xlims (1) = x + factor * (xlims (1) - x);
+  ylims (0) = y + factor * (ylims (0) - y);
+  ylims (1) = y + factor * (ylims (1) - y);
+              
+  // Make sure we stay within the range og the plot
+  xlims (0) = force_in_range (xlims (0), minx, maxx);
+  xlims (1) = force_in_range (xlims (1), minx, maxx);
+  ylims (0) = force_in_range (ylims (0), miny, maxy);
+  ylims (1) = force_in_range (ylims (1), miny, maxy);
+
+  zoom (xlims, ylims, push_to_zoom_stack);
+}
+
+void
+axes::properties::zoom (const Matrix& xl, const Matrix& yl, bool push_to_zoom_stack)
+{
+  if (push_to_zoom_stack)
+    {
+      zoom_stack.push_front (xlimmode.get ());
+      zoom_stack.push_front (xlim.get ());
+      zoom_stack.push_front (ylimmode.get ());
+      zoom_stack.push_front (ylim.get ());
+    }
+  
   xlim = xl;
   xlimmode = "manual";
   ylim = yl;
@@ -3723,6 +3772,43 @@
 }
 
 void
+axes::properties::translate_view (double delta_x, double delta_y)
+{
+  // FIXME: Do we need error checking here?
+  Matrix xlims = get_xlim ().matrix_value ();
+  Matrix ylims = get_ylim ().matrix_value ();
+              
+  // Get children axes limits
+  Matrix kids = get_children ();
+  double minx = octave_Inf;
+  double maxx = -octave_Inf;
+  double min_pos_x = octave_Inf;
+  get_children_limits (minx, maxx, min_pos_x, kids, 'x');
+        
+  double miny = octave_Inf;
+  double maxy = -octave_Inf;
+  double min_pos_y = octave_Inf;
+  get_children_limits (miny, maxy, min_pos_y, kids, 'y');
+  
+  // Make sure we don't exceed the borders
+  if (delta_x > 0)
+    delta_x = std::min (xlims (1) + delta_x, maxx) - xlims (1);
+  else
+    delta_x = std::max (xlims (0) + delta_x, minx) - xlims (0);
+  xlims (0) = xlims (0) + delta_x;
+  xlims (1) = xlims (1) + delta_x;
+                
+  if (delta_y > 0)
+    delta_y = std::min (ylims (1) + delta_y, maxy) - ylims (1);
+  else
+    delta_y = std::max (ylims (0) + delta_y, miny) - ylims (0);
+  ylims (0) = ylims (0) + delta_y;
+  ylims (1) = ylims (1) + delta_y;
+                
+  zoom (xlims, ylims, false);
+}
+
+void
 axes::properties::unzoom (void)
 {
   if (zoom_stack.size () >= 4)
--- a/src/graphics.h.in	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/graphics.h.in	Tue Jul 21 12:43:33 2009 -0400
@@ -2610,7 +2610,10 @@
     ColumnVector coord2pixel (double x, double y, double z) const
     { return get_transform ().transform (x, y, z); }
 
-    void zoom (const Matrix& xl, const Matrix& yl);
+    void zoom_about_point (double x, double y, double factor,
+                           bool push_to_zoom_stack = true);
+    void zoom (const Matrix& xl, const Matrix& yl, bool push_to_zoom_stack = true);
+    void translate_view (double delta_x, double delta_y);
     void unzoom (void);
     void clear_zoom_stack (void);
 
@@ -3907,6 +3910,8 @@
   void do_post_event (const graphics_event& e);
 };
 
+void get_children_limits (double& min_val, double& max_val, double& min_pos,
+                          const Matrix& kids, char limit_type);
 
 // This function is NOT equivalent to the scripting language function gcf.
 OCTINTERP_API graphics_handle gcf (void);
--- a/src/symtab.cc	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/symtab.cc	Tue Jul 21 12:43:33 2009 -0400
@@ -724,6 +724,141 @@
   return built_in_function;
 }
 
+// Find the definition of NAME according to the following precedence
+// list:
+//
+//   built-in function
+//   function on the path
+//   autoload function
+//   command-line function
+//   private function
+//   subfunction
+
+// This function is used to implement the "builtin" function, which
+// searches for "built-in" functions.  In Matlab, "builtin" only
+// returns functions that are actually built-in to the interpreter.
+// But since the list of built-in functions is different in Octave and
+// Matlab, we also search up the precedence list until we find
+// something that matches.  Note that we are only searching by name,
+// so class methods, constructors, and legacy dispatch functions are
+// skipped.
+
+octave_value
+symbol_table::fcn_info::fcn_info_rep::builtin_find (void)
+{
+  octave_value retval = x_builtin_find ();
+
+  if (! retval.is_defined ())
+    {
+      // It is possible that the user created a file on the fly since
+      // the last prompt or chdir, so try updating the load path and
+      // searching again.
+
+      load_path::update ();
+
+      retval = x_builtin_find ();
+    }
+
+  return retval;
+}
+
+octave_value
+symbol_table::fcn_info::fcn_info_rep::x_builtin_find (void)
+{
+  // Built-in function.
+  if (built_in_function.is_defined ())
+    return built_in_function;
+
+  // Function on the path.
+
+  octave_value fcn = find_user_function ();
+
+  if (fcn.is_defined ())
+    return fcn;
+
+  // Autoload?
+
+  fcn = find_autoload ();
+
+  if (fcn.is_defined ())
+    return fcn;
+
+  // Command-line function.
+
+  if (cmdline_function.is_defined ())
+    return cmdline_function;
+
+  // Private function.
+
+  octave_function *curr_fcn = octave_call_stack::current ();
+
+  if (curr_fcn)
+    {
+      std::string dir_name = curr_fcn->dir_name ();
+
+      if (! dir_name.empty ())
+	{
+	  str_val_iterator q = private_functions.find (dir_name);
+
+	  if (q == private_functions.end ())
+	    {
+	      octave_value val = load_private_function (dir_name);
+
+	      if (val.is_defined ())
+		return val;
+	    }
+	  else
+	    {
+	      octave_value& fval = q->second;
+
+	      if (fval.is_defined ())
+		out_of_date_check_internal (fval);
+
+	      if (fval.is_defined ())
+		return fval;
+	      else
+		{
+		  octave_value val = load_private_function (dir_name);
+
+		  if (val.is_defined ())
+		    return val;
+		}
+	    }
+	}
+    }
+
+  // Subfunction.  I think it only makes sense to check for
+  // subfunctions if we are currently executing a function defined
+  // from a .m file.
+
+  scope_val_iterator r = subfunctions.find (xcurrent_scope);
+
+  if (r != subfunctions.end ())
+    {
+      // FIXME -- out-of-date check here.
+
+      return r->second;
+    }
+  else if (curr_fcn)
+    {
+      scope_id pscope = curr_fcn->parent_fcn_scope ();
+
+      if (pscope > 0)
+	{
+	  r = subfunctions.find (pscope);
+
+	  if (r != subfunctions.end ())
+	    {
+	      // FIXME -- out-of-date check here.
+
+	      return r->second;
+	    }
+	}
+    }
+
+  return octave_value ();
+}
+
 octave_value
 symbol_table::fcn_info::fcn_info_rep::find_method (const std::string& dispatch_type)
 {
@@ -968,6 +1103,14 @@
 }
 
 octave_value
+symbol_table::builtin_find (const std::string& name)
+{
+  symbol_table *inst = get_instance (xcurrent_scope);
+
+  return inst ? inst->do_builtin_find (name) : octave_value ();
+}
+
+octave_value
 symbol_table::find_function (const std::string& name, tree_argument_list *args,
 			     const string_vector& arg_names,
 			     octave_value_list& evaluated_args,
@@ -1172,6 +1315,30 @@
   return retval;
 }
 
+octave_value
+symbol_table::do_builtin_find (const std::string& name)
+{
+  octave_value retval;
+
+  fcn_table_iterator p = fcn_table.find (name);
+
+  if (p != fcn_table.end ())
+    return p->second.builtin_find ();
+  else
+    {
+      fcn_info finfo (name);
+
+      octave_value fcn = finfo.builtin_find ();
+
+      if (fcn.is_defined ())
+	fcn_table[name] = finfo;
+
+      return fcn;
+    }
+
+  return retval;
+}
+
 void
 symbol_table::do_dump (std::ostream& os)
 {
--- a/src/symtab.h	Mon Jul 20 15:55:33 2009 -0400
+++ b/src/symtab.h	Tue Jul 21 12:43:33 2009 -0400
@@ -428,6 +428,8 @@
     find (tree_argument_list *args, const string_vector& arg_names,
 	  octave_value_list& evaluated_args, bool& args_evaluated) const;
 
+    octave_value builtin_find (void) const;
+
     void force_variable (context_id context = xcurrent_context)
     {
       rep->force_variable (context);
@@ -544,6 +546,8 @@
       find (tree_argument_list *args, const string_vector& arg_names,
 	    octave_value_list& evaluated_args, bool& args_evaluated);
 
+      octave_value builtin_find (void);
+
       octave_value find_method (const std::string& dispatch_type);
 
       octave_value find_autoload (void);
@@ -735,6 +739,8 @@
       xfind (tree_argument_list *args, const string_vector& arg_names,
 	     octave_value_list& evaluated_args, bool& args_evaluated);
 
+      octave_value x_builtin_find (void);
+
       // No copying!
 
       fcn_info_rep (const fcn_info_rep&);
@@ -776,6 +782,11 @@
     find (tree_argument_list *args, const string_vector& arg_names,
 	  octave_value_list& evaluated_args, bool& args_evaluated);
 
+    octave_value builtin_find (void)
+    {
+      return rep->builtin_find ();
+    }
+
     octave_value find_method (const std::string& dispatch_type) const
     {
       return rep->find_method (dispatch_type);
@@ -1046,6 +1057,8 @@
 	octave_value_list& evaluated_args, bool& args_evaluated,
 	bool skip_variables = false);
 
+  static octave_value builtin_find (const std::string& name);
+
   // Insert a new name in the table.
   static symbol_record& insert (const std::string& name)
   {
@@ -2004,6 +2017,8 @@
 	   octave_value_list& evaluated_args, bool& args_evaluated,
 	   bool skip_variables);
 
+  octave_value do_builtin_find (const std::string& name);
+
   symbol_record& do_insert (const std::string& name)
   {
     table_iterator p = table.find (name);