# HG changeset patch
# User pantxo <pantxo.diribarne@gmail.com>
# Date 1395396328 -3600
# Node ID 948a687cbcf71f6440e5a31da9ad9d8a58beb134
# Parent  5eca3080c7cdca8851c217bb0e369be1459389d8
Freset: properly reset graphics objects (bug #35511)

* graphics.in.h (base_graphics_object, graphics_object, root): add new method "get_factory_defaults_list" to retrieve factory defaults as property_list
* graphics.in.h (base_graphics_object::reset_default_properties (void)): move definition to graphics.cc

* graphics.cc (xreset_default_properties): new function to set a list of prop/val
* graphics.cc (base_graphics_object::reset_default_properties): use xreset_default_properties, override with parents' defaults
* graphics.cc (root_figure::reset_default_properties, figure::reset_default_properties, uitoolbar::reset_default_properties): same as above but first empty local defaults
* graphics.cc (axes_figure::reset_default_properties): same as above but use "propeties.set_defaults" to reset properties to their factory value.
* graphics.cc (axes_figure::properties::set_defaults): new "reset" mode, that does the same as "replace" but  x/y/zlabels and title are reset instead of being deleting/recreating.
* graphics.cc: add %!tests for Freset

diff -r 5eca3080c7cd -r 948a687cbcf7 libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Sat Jun 14 13:24:46 2014 -0700
+++ b/libinterp/corefcn/graphics.cc	Fri Mar 21 11:05:28 2014 +0100
@@ -2739,6 +2739,39 @@
   finalize (go);
 }
 
+static void
+xreset_default_properties (graphics_handle gh,
+                           property_list::pval_map_type factory_pval)
+{
+  graphics_object obj = gh_manager::get_object (gh);
+
+  property_list::pval_map_type pval;
+
+  for (property_list::pval_map_const_iterator it = factory_pval.begin ();
+       it != factory_pval.end (); it++)
+    {
+      std::string pname = it->first;
+
+      // Don't reset internal properties and handle_properties
+      if (! obj.has_readonly_property (pname) &&
+          pname.find ("__") != 0 && pname.find ("current") != 0 &&
+          pname != "uicontextmenu" && pname != "parent")
+        {
+          // Store *mode prop/val in order to set them last 
+          if (pname.find ("mode") == (pname.length () - 4))
+            pval.insert (std::pair<std::string, octave_value>
+                         (pname, it->second));
+          else
+            obj.set (it->first, it->second);
+        }
+    }
+
+  // set *mode properties
+  for (property_list::pval_map_const_iterator it = pval.begin ();
+       it != pval.end (); it++)
+    obj.set (it->first, it->second);
+}
+
 // ---------------------------------------------------------------------
 
 void
@@ -2758,7 +2791,7 @@
            q++)
         {
           std::string pname = q->first;
-
+          
           obj.set (pname, q->second);
 
           if (error_state)
@@ -3070,6 +3103,21 @@
     }
 }
 
+void 
+base_graphics_object::reset_default_properties (void)
+  {
+    if (valid_object ())
+      {
+        property_list::pval_map_type factory_pval = 
+          gh_manager::get_object (0).get_factory_defaults_list ()
+          .find (type ())->second;
+        
+        xreset_default_properties (get_handle (), factory_pval);
+
+        override_defaults (*this);
+      }
+  }
+
 std::string
 base_graphics_object::values_as_string (void)
 {
@@ -3554,39 +3602,14 @@
 property_list
 root_figure::factory_properties = root_figure::init_factory_properties ();
 
-static void
-reset_default_properties (property_list& default_properties)
-{
-  property_list new_defaults;
-
-  for (property_list::plist_map_const_iterator p = default_properties.begin ();
-       p != default_properties.end (); p++)
-    {
-      const property_list::pval_map_type pval_map = p->second;
-      std::string prefix = p->first;
-
-      for (property_list::pval_map_const_iterator q = pval_map.begin ();
-           q != pval_map.end ();
-           q++)
-        {
-          std::string s = q->first;
-
-          if (prefix == "axes" && (s == "position" || s == "units"))
-            new_defaults.set (prefix + s, q->second);
-          else if (prefix == "figure" && (s == "position" || s == "units"
-                                          || s == "windowstyle"
-                                          || s == "paperunits"))
-            new_defaults.set (prefix + s, q->second);
-        }
-    }
-
-  default_properties = new_defaults;
-}
-
 void
 root_figure::reset_default_properties (void)
 {
-  ::reset_default_properties (default_properties);
+  // empty list of local defaults
+  default_properties = property_list ();
+
+  xreset_default_properties (get_handle (), 
+                             xproperties.factory_defaults ());
 }
 
 // ---------------------------------------------------------------------
@@ -4407,7 +4430,19 @@
 void
 figure::reset_default_properties (void)
 {
-  ::reset_default_properties (default_properties);
+  // empty list of local defaults
+  default_properties = property_list ();
+
+  property_list::pval_map_type plist = xproperties.factory_defaults ();
+  plist.erase ("units");
+  plist.erase ("position");
+  plist.erase ("paperunits");
+  plist.erase ("paperposition");
+  plist.erase ("windowstyle");
+  xreset_default_properties (get_handle (), plist);
+
+  // override with parents' defaults
+  override_defaults (*this);
 }
 
 // ---------------------------------------------------------------------
@@ -4828,27 +4863,42 @@
 
   visible = "on";
 
-  // Replace preserves Position and Units properties
-  if (mode != "replace")
+  // Replace/Reset preserves Position and Units properties
+  if (mode != "replace" && mode != "reset")
     {
       outerposition = default_axes_outerposition ();
       position = default_axes_position ();
       activepositionproperty = "outerposition";
     }
-
-  delete_children (true);
-
-  xlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
-                                             false, false);
-
-  ylabel = gh_manager::make_graphics_handle ("text", __myhandle__,
-                                             false, false);
-
-  zlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
-                                             false, false);
-
-  title = gh_manager::make_graphics_handle ("text", __myhandle__,
-                                            false, false);
+  
+  if (mode != "reset")
+    {
+      delete_children (true);
+
+      xlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
+                                                 false, false);
+      ylabel = gh_manager::make_graphics_handle ("text", __myhandle__,
+                                                 false, false);
+      zlabel = gh_manager::make_graphics_handle ("text", __myhandle__,
+                                                 false, false);
+      title = gh_manager::make_graphics_handle ("text", __myhandle__,
+                                                false, false);
+      adopt (xlabel.handle_value ());
+      adopt (ylabel.handle_value ());
+      adopt (zlabel.handle_value ());
+      adopt (title.handle_value ());
+    }
+  else
+    {
+      graphics_object go = gh_manager::get_object (xlabel.handle_value ());
+      go.reset_default_properties ();
+      go = gh_manager::get_object (ylabel.handle_value ());
+      go.reset_default_properties ();
+      go = gh_manager::get_object (zlabel.handle_value ());
+      go.reset_default_properties ();
+      go = gh_manager::get_object (title.handle_value ());
+      go.reset_default_properties ();
+    }
 
   xset (xlabel.handle_value (), "handlevisibility", "off");
   xset (ylabel.handle_value (), "handlevisibility", "off");
@@ -4886,11 +4936,6 @@
   xset (zlabel.handle_value (), "autopos_tag", "zlabel");
   xset (title.handle_value (), "autopos_tag", "title");
 
-  adopt (xlabel.handle_value ());
-  adopt (ylabel.handle_value ());
-  adopt (zlabel.handle_value ());
-  adopt (title.handle_value ());
-
   update_transform ();
   sync_positions ();
   override_defaults (obj);
@@ -7562,7 +7607,11 @@
 void
 axes::reset_default_properties (void)
 {
-  ::reset_default_properties (default_properties);
+  // empty list of local defaults
+  default_properties = property_list ();
+
+  // reset factory defaults
+  set_defaults ("reset");
 }
 
 void
@@ -8407,7 +8456,14 @@
 void
 uitoolbar::reset_default_properties (void)
 {
-  ::reset_default_properties (default_properties);
+  // empty list of local defaults
+  default_properties = property_list ();
+
+  xreset_default_properties (get_handle (), 
+                             xproperties.factory_defaults ());
+
+  // override with parents' defaults
+  override_defaults (*this);
 }
 
 // ---------------------------------------------------------------------
@@ -9033,12 +9089,13 @@
 
 DEFUN (reset, args, ,
        "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} reset (@var{h}, @var{property})\n\
-Remove any defaults set for the handle @var{h}.  The default figure\n\
-properties of @qcode{\"position\"}, @qcode{\"units\"},\n\
-@qcode{\"windowstyle\"} and @qcode{\"paperunits\"} and the default axes\n\
-properties of @qcode{\"position\"} and @qcode{\"units\"} are not reset.\n\
-@seealso{cla, clf}\n\
+@deftypefn {Built-in Function} {} reset (@var{h})\n\
+Resets the properites of object(s) @var{h} to their default values.\n\
+For figures, the properties @qcode{\"position\"}, @qcode{\"units\"},\n\
+@qcode{\"windowstyle\"}, and @qcode{\"paperunits\"} are not affected.\n\
+For axes, the properties @qcode{\"position\"} and @qcode{\"units\"} are\n\
+not affected.\n\
+@seealso{cla, clf, newplot}\n\
 @end deftypefn")
 {
   int nargin = args.length ();
@@ -9055,12 +9112,135 @@
           // loop over graphics objects
           for (octave_idx_type n = 0; n < hcv.length (); n++)
             gh_manager::get_object (hcv(n)).reset_default_properties ();
+
+          if (! error_state)
+            Fdrawnow ();
         }
     }
 
   return octave_value ();
 }
 
+/*
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   tol = 20 * eps;
+%!   hax = axes ("defaultlinelinewidth", 3);
+%!   
+%!   hli = line (1:10, 1:10, 1:10, "marker", "o",
+%!               "markerfacecolor", "b", "linestyle", ":");
+%!   
+%!   reset (hli);
+%!   assert (get (hli, "marker"), get (0, "defaultlinemarker"))
+%!   assert (get (hli, "markerfacecolor"), ...
+%!           get (0, "defaultlinemarkerfacecolor"))
+%!   assert (get (hli, "linestyle"), ...
+%!           get (0, "defaultlinelinestyle"))
+%!   assert (get (hli, "linewidth"), 3, tol) # parent axes defaults  
+%!   
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   tol = 20 * eps;
+%!   t1 = (1/16:1/8:1)' * 2*pi;
+%!   t2 = ((1/16:1/16:1)' + 1/32) * 2*pi;
+%!   x1 = sin (t1) - 0.8;
+%!   y1 = cos (t1);
+%!   x2 = sin (t2) + 0.8;
+%!   y2 = cos (t2);
+%!   vert = [x1, y1; x2, y2];
+%!   fac = [1:8,NaN(1,8);9:24];
+%!   hpa = patch ('Faces',fac, 'Vertices',vert, 'FaceColor','r');
+%!
+%!   reset (hpa);
+%!   assert (get (hpa, "faces"), get (0, "defaultpatchfaces"), tol)
+%!   assert (get (hpa, "vertices"), get (0, "defaultpatchvertices"), tol)
+%!   assert (get (hpa, "facevertexcdata"), ...
+%!           get (0, "defaultpatchfacevertexcdata"), tol)
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   tol = 20 * eps;
+%!   hsu = surface (peaks, "edgecolor", "none");
+%!
+%!   reset (hsu);
+%!   assert (get (hsu, "xdata"), get (0, "defaultsurfacexdata"), tol)
+%!   assert (get (hsu, "ydata"), get (0, "defaultsurfaceydata"), tol)
+%!   assert (get (hsu, "zdata"), get (0, "defaultsurfacezdata"), tol)
+%!   assert (get (hsu, "edgecolor"), ...
+%!           get (0, "defaultsurfaceedgecolor"), tol)
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   tol = 20 * eps;   
+%!   him =image (rand (10,10), "cdatamapping", "scaled");
+%!
+%!   reset (him);
+%!   assert (get (him, "cdata"), get (0, "defaultimagecdata"), tol)
+%!   assert (get (him, "cdatamapping"), ...
+%!           get (0, "defaultimagecdatamapping"), tol)
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   tol = 20 * eps;   
+%!   hte = text (5, 5, "Hi!", "fontsize", 20 ,"color", "r");
+%!
+%!   reset (hte);
+%!   assert (get (hte, "position"), get (0, "defaulttextposition"), tol)
+%!   assert (get (hte, "fontsize"), get (0, "defaulttextfontsize"), tol)
+%!   assert (get (hte, "color"), get (0, "defaulttextcolor"), tol)
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   tol = 20 * eps;
+%!   pos = get (0, "defaultaxesposition") * .5;
+%!   hax = axes ("linewidth", 2, "position", pos);
+%!   title ("Reset me, please!")
+%! 
+%!   reset (hax);
+%!   assert (get (hax, "linewidth"), get (0, "defaultaxeslinewidth"), tol)
+%!   assert (get (hax, "position"), pos, tol) # axes position is unchanged
+%!   assert (get (hax, "default"), struct ()) # no more axes' defaults
+%!   assert (get (get (hax, "title"), "string"), "")
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+
+// FIXME: the following test crashes octave when run using qt graphics_toolkit
+// %! hf = figure ("visible", "off", "paperunits", "centimeters", ...
+// %!              "papertype", "a4");
+// %! unwind_protect
+// %!   reset (hf)
+// %!   assert (get (hf, "papertype"), get (0, "defaultfigurepapertype"))
+// %!   assert (get (hf, "paperunits"), "centimeters") # paperunits is unchanged
+// %!   
+// %! unwind_protect_cleanup
+// %!   close (hf)
+// %! end_unwind_protect
+ */
+
 DEFUN (set, args, nargout,
        "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {} set (@var{h}, @var{property}, @var{value}, @dots{})\n\
diff -r 5eca3080c7cd -r 948a687cbcf7 libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Sat Jun 14 13:24:46 2014 -0700
+++ b/libinterp/corefcn/graphics.in.h	Fri Mar 21 11:05:28 2014 +0100
@@ -2698,6 +2698,12 @@
     return octave_value ();
   }
 
+  virtual property_list get_factory_defaults_list (void) const
+  {
+    error ("base_graphics_object::get_factory_defaults_list: invalid graphics object");
+    return property_list ();
+  }
+
   virtual bool has_readonly_property (const caseless_str& pname) const
   {
     return base_properties::has_readonly_property (pname);
@@ -2829,16 +2835,7 @@
 
   virtual void remove_all_listeners (void);
 
-  virtual void reset_default_properties (void)
-  {
-    if (valid_object ())
-      {
-        std::string msg = (type () + "::reset_default_properties");
-        gripe_not_implemented (msg.c_str ());
-      }
-    else
-      error ("base_graphics_object::default: invalid graphics object");
-  }
+  virtual void reset_default_properties (void);
 
 protected:
   virtual void initialize (const graphics_object& go)
@@ -2976,6 +2973,11 @@
     return rep->get_factory_defaults ();
   }
 
+  property_list get_factory_defaults_list (void) const
+  {
+    return rep->get_factory_defaults_list ();
+  }
+
   bool has_readonly_property (const caseless_str& pname) const
   {
     return rep->has_readonly_property (pname);
@@ -3225,6 +3227,11 @@
     return factory_properties.as_struct ("factory");
   }
 
+  property_list get_factory_defaults_list (void) const
+  {
+    return factory_properties;
+  }
+
   base_properties& get_properties (void) { return xproperties; }
 
   const base_properties& get_properties (void) const { return xproperties; }
