# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1575839518 -3600
#      Sun Dec 08 22:11:58 2019 +0100
# Node ID a2e308b6378989a7871b17e181e83854228357db
# Parent  7220376b4aeac5c04650d462736ddca7520b36a7
Better documentation for legend objects (bug #57254)

* genpropdoc.m: New optionnal argument "props" to indicate that only a subset
  of properties should be printed. Add "legend" to the list of supported objects
  (getstructure): Add support for legend objects and eventually limited set of
  properties.
  (getdoc): Document legend specific properties in the axes section.

* legend.m: Rework doc and include a subset of legend specific properties.

* plot.txi: include legend properties after primitive objects.

* module.mk: Generate plot-legendproperties.texi.

diff -r 7220376b4aea -r a2e308b63789 doc/interpreter/genpropdoc.m
--- a/doc/interpreter/genpropdoc.m	Sun Aug 02 15:13:26 2020 +0200
+++ b/doc/interpreter/genpropdoc.m	Sun Dec 08 22:11:58 2019 +0100
@@ -37,28 +37,27 @@
 ## @seealso{}
 ## @end deftypefn
 
-function genpropdoc (objname, fname)
+function genpropdoc (objname, fname = "", props = {})
   objnames = {"root", "figure", "axes", ...
               "image", "light", "line", "patch", "scatter", "surface", ...
               "text", "uibuttongroup", "uicontextmenu", "uicontrol", ...
               "uipanel", "uimenu", "uipushtool", "uitable", ...
-              "uitoggletool", "uitoolbar"
-             };
+              "uitoggletool", "uitoolbar", "legend"};
 
   ## Base properties
   base = getstructure ("base");
 
   ## Object properties
   if (any (strcmp (objname, objnames)))
-    obj = getstructure (objname, base);
+    obj = getstructure (objname, base, props);
   else
     error ("genpropdoc: unknown object %s", objname);
   endif
 
   ## Docstring
-  str = printdoc (objname, obj);
+  str = printdoc (objname, obj, ! isempty (props));
 
-  if (nargin == 2)
+  if (! isempty (fname))
     fid = fopen (fname,  "w+");
     if (fid < 0)
       error ("genpropdoc: couldn't open %s.", fname);
@@ -651,7 +650,7 @@
     endswitch
 
   ## Axes properties
-  elseif (strcmp (objname, "axes"))
+  elseif (strcmp (objname, "axes") || strcmp (objname, "legend"))
     switch (field)
       ## Overridden shared properties
       case "clipping"
@@ -666,7 +665,7 @@
         s.doc = doc_unused;
 
       case "box"
-        s.doc = "Control whether the axes has a surrounding box.";
+        s.doc = "Control whether the __objname__ has a surrounding box.";
 
       case "boxstyle"
         s.doc = "For 3-D axes, control whether the @qcode{\"full\"} \
@@ -699,7 +698,8 @@
         s.doc = doc_unused;
 
       case "color"
-        s.doc = "Color of the axes background.  @xref{Colors, , colorspec}.";
+        s.doc = "Color of the __objname__ background.  \
+@xref{Colors, , colorspec}.";
         s.valid = valid_color;
 
       case "colororder"
@@ -820,14 +820,20 @@
 height to be 0.4 and 0.5 respectively.  \
 @xref{XREFaxesposition, , @w{position property}}.";
         s.valid = valid_4elvec;
-
       case "plotboxaspectratio"
         s.doc = "@xref{XREFpbaspect, , pbaspect function}.  \
 __modemsg__.";
 
       case "plotboxaspectratiomode"
       case "position"
-        s.doc = "Specify the position of the plot excluding titles, \
+        if (strcmp (objname, "legend"))
+          s.doc = "Specify the position of the legend excluding title. \
+The four elements of the vector are the coordinates of the lower left corner \
+and width and height of the legend.  Changing this property also \
+switches the @qcode{\"location\"} to @qcode{\"none\"}.";
+          s.printdefault = false;          
+        else
+          s.doc = "Specify the position of the plot excluding titles, \
 axes, and legend.  The four elements of the vector are the \
 coordinates of the lower left corner and width and height of the \
 plot, in units normalized to the width and height of the plot \
@@ -835,6 +841,7 @@
 left corner of the axes at @math{(0.2, 0.3)} and the width and \
 height to be 0.4 and 0.5 respectively.  \
 @xref{XREFaxesouterposition, , @w{outerposition property}}.";
+        endif
         s.valid = valid_4elvec;
 
       case "positionconstraint"
@@ -884,8 +891,13 @@
         s.doc = "Control variant of base font used for the axes title.";
 
       case "units"
-        s.doc = "Units used to interpret the @qcode{\"position\"}, \
+        if (strcmp (objname, "legend"))
+          s.doc = "Units used to interpret the @qcode{\"position\"}, \
+ property.";
+        else
+          s.doc = "Units used to interpret the @qcode{\"position\"}, \
 @qcode{\"outerposition\"}, and @qcode{\"tightinset\"} properties.";
+        endif
 
       case "view"
         s.doc = "Two-element vector @code{[azimuth elevation]} specifying \
@@ -1021,6 +1033,82 @@
         s.doc = doc_unused;
 
       case "ztickmode"
+
+      ## Legend specific properties
+      case "autoupdate"
+        s.doc = "Control wether the number of legend item is updated \
+automatically when objects are added to (or deleted from) the peer axes.\n\
+For example:\n\
+@example\n\
+@group\n\
+## Create a single plot with its legend.\n\
+figure ();\n\
+plot (1:10);\n\
+legend (\"Slope 1\");\n\
+## Add another plot and specify its displayname so that\n\
+## the legend is correctly updated.\n\
+hold on;\n\
+plot ((1:10) * 2, \"displayname\", \"Slope 2\");\n\
+## Stop automatic updates for further plots.\n\
+legend (\"autoupdate\", \"off\");\n\
+plot ((1:10) * 3);\n\
+@end group\n\
+@end example";
+
+      case "edgecolor"
+        s.doc = "Control the color of the legend outline.";
+        s.valid = valid_color;
+
+      case "interpreter"
+        s.doc = "Control if and eventually how labels strings are interpreted \
+before rendering.\n\
+@xref{XREFinterpreterusage, , @w{Use of the interpreter property}}.";
+
+      case "location"
+        s.doc = "Control the location of the legend.";
+
+      case "numcolumns"
+        s.doc = "Control the the number of columns used to layout legend item. \
+ For example:\n\
+@example\n\
+@group\n\
+figure ();\n\
+plot (rand (30));\n\
+legend (\"numcolumns\", 3);\n\
+@end group\n\
+@end example\n\
+__modemsg__.";
+        s.valid = "scalar interger";
+
+      case "orientation"
+        s.doc = "Control wether the legend item are arranged vertically \
+(column-wise) or horizontally (row-wise).";
+
+      case "string"
+        s.doc = "List of labels for the legend item.  For example:\n\
+@example\n\
+@group\n\
+figure ();\n\
+plot (rand (20));\n\
+## Let legend choose names automatically\n\
+hl = legend ();\n\
+## Selectively change some names\n\
+str = get (hl, \"string\");\n\
+str(1:5:end) = \"Garbage\";\n\
+set (hl, \"string\", str);\n\
+@end group\n\
+@end example";
+        s.valid = valid_cellstring;
+        s.printdefault = false;
+
+      case "textcolor"
+        s.doc = "Control the color of the text strings for legend item.";
+        s.valid = valid_color;
+
+      case "textposition"
+        s.doc = "Control wether text strings are displayed on the left or \
+right of their corresponding icon.";
+
     endswitch
 
   ## Line properties
@@ -1967,7 +2055,7 @@
   strout = strrep (strout, "__fcnmsg__", fcnmsg);
 endfunction
 
-function s = getstructure (objname, base = [])
+function s = getstructure (objname, base = [], props = {})
   hf = [];
   if (! strcmp (objname, "root"))
     ## Use an improbable number to avoid ishghandle to return true for 1
@@ -1987,6 +2075,15 @@
     ## Make sure to get a scatter object independent of graphics toolkit
     hax = axes (hf);
     h = __go_scatter__ (hax);
+  elseif (strcmp (objname, "legend"))
+    line ();
+    h = legend ();
+    if (isempty (props))
+        props = {"autoupdate", "box", "color", "edgecolor", "fontangle", ...
+                 "fontname", "fontsize", "fontunits", "fontweight", ...
+                 "location", "numcolumns", "orientation", "position", ...
+                 "string", "textcolor", "title", "units"};
+    endif
   else
     eval (["h = " objname " ();"]);
   endif
@@ -1994,6 +2091,15 @@
   gprop = get (h);
   sprop = set (h);
 
+  if (! isempty (props))
+    flds = fieldnames (gprop);
+    idx = cellfun (@(s) ! any (strcmp (props, s)), flds);
+    gprop = rmfield (gprop, flds(idx));
+    flds = fieldnames (sprop);
+    idx = cellfun (@(s) ! any (strcmp (props, s)), flds);
+    sprop = rmfield (sprop, flds(idx));
+  endif
+
   fields = fieldnames (gprop);
   nf = numel (fields);
   args = cell (2*nf, 1);
@@ -2081,7 +2187,7 @@
 
 endfunction
 
-function str = printdoc (objname, obj)
+function str = printdoc (objname, obj, is_prop_subset)
   ## Sort fields so that they appear in alphabetic order in the manual
   fields = sort (fieldnames (obj));
   nf = numel (fields);
@@ -2090,6 +2196,8 @@
   str = warn_autogen ();
   if (strcmp (objname, "root"))
     str = sprintf ("%s\n\nProperties of the root graphics object:", str);
+  elseif (is_prop_subset)
+    ## Do nothing
   else
     str = sprintf ("%s\n\nProperties of @code{%s} objects (@pxref{XREF%s,,%s}):",
                    str, objname, objname, objname);
@@ -2100,10 +2208,12 @@
     field = fields{ii};
     str = sprintf ("%s\n\n", str);
 
-    ## @anchor: cross reference using XREFobjnamefield label
-    ## Concept index: call info from octave with 'doc ("objname field")'
-    str = sprintf ("%s@anchor{XREF%s%s}\n@prindex %s %s\n",
-                   str, objname, field, objname, field);
+    if (! is_prop_subset)
+      ## @anchor: cross reference using XREFobjnamefield label
+      ## Concept index: call info from octave with 'doc ("objname field")'
+      str = sprintf ("%s@anchor{XREF%s%s}\n@prindex %s %s\n",
+                     str, objname, field, objname, field);
+    endif
 
     ## Item
     str = sprintf ("%s@item @code{%s}", str, field);
diff -r 7220376b4aea -r a2e308b63789 doc/interpreter/module.mk
--- a/doc/interpreter/module.mk	Sun Aug 02 15:13:26 2020 +0200
+++ b/doc/interpreter/module.mk	Sun Dec 08 22:11:58 2019 +0100
@@ -4,6 +4,7 @@
   %reldir%/plot-axesproperties.texi \
   %reldir%/plot-figureproperties.texi \
   %reldir%/plot-imageproperties.texi \
+  %reldir%/plot-legendproperties.texi \
   %reldir%/plot-lightproperties.texi \
   %reldir%/plot-lineproperties.texi \
   %reldir%/plot-patchproperties.texi \
@@ -40,6 +41,9 @@
 %reldir%/plot-imageproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,image)
 
+%reldir%/plot-legendproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
+	$(AM_V_GEN)$(call gen-propdoc-texi,legend)
+
 %reldir%/plot-lightproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,light)
 
diff -r 7220376b4aea -r a2e308b63789 doc/interpreter/plot.txi
--- a/doc/interpreter/plot.txi	Sun Aug 02 15:13:26 2020 +0200
+++ b/doc/interpreter/plot.txi	Sun Dec 08 22:11:58 2019 +0100
@@ -1513,6 +1513,7 @@
 * Uitoolbar Properties::
 * Uipushtool Properties::
 * Uitoggletool Properties::
+* Legend Properties::
 @end menu
 
 In this section the graphics object properties are discussed in detail,
@@ -1650,6 +1651,12 @@
 
 @include plot-uitoggletoolproperties.texi
 
+@node Legend Properties
+@subsubsection Legend Properties
+@prindex @sortas{@ Legend Properties} Legend Properties
+
+@include plot-legendproperties.texi
+
 @node Searching Properties
 @subsection Searching Properties
 
diff -r 7220376b4aea -r a2e308b63789 scripts/plot/appearance/legend.m
--- a/scripts/plot/appearance/legend.m	Sun Aug 02 15:13:26 2020 +0200
+++ b/scripts/plot/appearance/legend.m	Sun Dec 08 22:11:58 2019 +0100
@@ -56,24 +56,6 @@
 ## labeling all objects, provide their graphic handles in the input
 ## @var{hobjs}.
 ##
-## The optional parameter @nospell{@var{loc}} specifies the location of the
-## legend as follows:
-##
-## @multitable @columnfractions 0.06 0.14 0.80
-## @headitem @tab @nospell{loc} @tab location of the legend
-## @item @tab north @tab center top
-## @item @tab south @tab center bottom
-## @item @tab east @tab right center
-## @item @tab west @tab left center
-## @item @tab northeast @tab right top (default)
-## @item @tab northwest @tab left top
-## @item @tab southeast @tab right bottom
-## @item @tab southwest @tab left bottom
-## @sp 1
-## @item @tab outside @tab can be appended to any location string @*
-## @item @tab         @tab which will place the legend outside the axes
-## @end multitable
-##
 ## The following customizations are available using @var{command}:
 ##
 ## @table @asis
@@ -108,6 +90,83 @@
 ## including @var{property}/@var{value} pairs.  If using this calling form, the
 ## labels must be specified as a cell array of strings.
 ##
+## Following is a subset of supported legend properties:
+## @c The following table is obtained by copying the output of
+## @c genpropdoc ("legend", "", {"autoupdate", "box", "location", "numcolumns", "orientation", "string", "textcolor"})
+## @table @asis
+## 
+## @item @code{autoupdate}: @qcode{"off"} | @{@qcode{"on"}@}
+## Control wether the number of legend item is updated automatically when objects are added to (or deleted from) the peer axes.
+## For example:
+## @example
+## @group
+## ## Create a single plot with its legend.
+## figure ();
+## plot (1:10);
+## legend ("Slope 1");
+## ## Add another plot and specify its displayname so that
+## ## the legend is correctly updated.
+## hold on;
+## plot ((1:10) * 2, "displayname", "Slope 2");
+## ## Stop automatic updates for further plots.
+## legend ("autoupdate", "off");
+## plot ((1:10) * 3);
+## @end group
+## @end example
+## 
+## 
+## @item @code{box}: @qcode{"off"} | @{@qcode{"on"}@}
+## Control whether the legend has a surrounding box.
+## 
+## 
+## @item @code{location}: @qcode{"best"} | @qcode{"bestoutside"} | @qcode{"east"} | @qcode{"eastoutside"} | @qcode{"none"} | @qcode{"north"} | @{@qcode{"northeast"}@} | @qcode{"northeastoutside"} | @qcode{"northoutside"} | @qcode{"northwest"}| @qcode{"northwestoutside"} | @qcode{"south"} | @qcode{"southeast"} | @qcode{"southeastoutside"} | @qcode{"southoutside"} | @qcode{"southwest"} | @qcode{"southwestoutside"} | @qcode{"west"} | @qcode{"westoutside"}
+## Control the location of the legend.
+## 
+## 
+## @item @code{numcolumns}: scalar interger, def. @code{1}
+## Control the the number of columns used to layout legend item.  For example:
+## @example
+## @group
+## figure ();
+## plot (rand (30));
+## legend ("numcolumns", 3);
+## @end group
+## @end example
+## Setting @code{numcolumns} also forces the @code{numcolumnsmode} property to be set to @qcode{"manual"}.
+## 
+## 
+## @item @code{orientation}: @qcode{"horizontal"} | @{@qcode{"vertical"}@}
+## Control wether the legend item are arranged vertically (column-wise) or horizontally (row-wise).
+## 
+## 
+## @item @code{string}: string | cell array of strings
+## List of labels for the legend item.  For example:
+## @example
+## @group
+## figure ();
+## plot (rand (20));
+## ## Let legend choose names automatically
+## hl = legend ();
+## ## Selectively change some names
+## str = get (hl, "string");
+## str(1:5:end) = "Garbage";
+## set (hl, "string", str);
+## @end group
+## @end example
+## 
+## 
+## @item @code{textcolor}: colorspec, def. @code{[0   0   0]}
+## Control the color of the text strings for legend item.
+## 
+## @end table
+##
+## The full list of supported legend specific properties can be found at
+## @ref{Legend Properties, , Legend Properties}.
+##
+## A legend is implemented as an additional axes object with the @code{tag}
+## property set to @qcode{"legend"}.  Properties of the legend object may be
+## manipulated directly by using @code{set}.
+##
 ## The optional output value @var{hleg} is a handle to the legend object.
 ##
 ## Implementation Note: The legend label text is either provided in the call to
@@ -121,10 +180,6 @@
 ## The legend @code{FontSize} property is initially set to 90% of the axes
 ## @code{FontSize} to which it is attached.  Use @code{set} to override this
 ## if necessary.
-##
-## A legend is implemented as an additional axes object with the @code{tag}
-## property set to @qcode{"legend"}.  Properties of the legend object may be
-## manipulated directly by using @code{set}.
 ## @end deftypefn
 
 function [hleg, hleg_obj, hplot, labels] = legend (varargin)
