# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1701426643 -3600
#      Fri Dec 01 11:30:43 2023 +0100
# Branch stable
# Node ID 4a65f4d6c80494b799ed49186dfd6019c515a875
# Parent  59d0866396021e14df2e86ff780d7e5feb5466f0
legend.m: Better handling of custom position (bug #64929)

* legend.m (main): Invert order of listeners to legend "location" and "position"
                   properties.
  (update_position_cb): Store the point size of user provided position.
  (maybe_update_layout_cb): Return early when "location" property is "none".
  (update_layout_cb): Take into account the user provided size and the legend
                      item extent to decide the actual size of the box.   
* genpropdoc.m: Document that Octave adapts the box size when the item don't fit
                in the user provided box. 


diff -r 59d086639602 -r 4a65f4d6c804 doc/interpreter/genpropdoc.m
--- a/doc/interpreter/genpropdoc.m	Thu Nov 30 08:29:47 2023 -0800
+++ b/doc/interpreter/genpropdoc.m	Fri Dec 01 11:30:43 2023 +0100
@@ -830,7 +830,9 @@
           s.doc = "Specify the position of the legend excluding its 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\"}.";
+switches the @qcode{\"location\"} to @qcode{\"none\"}.\n\n\
+If legend item don't fit in the provided width or height, Octave adapts \
+the size of the box, but preserves the coordinates of the lower left corner.";
           s.printdefault = false;
         else
           s.doc = "Specify the position of the plot excluding titles, \
diff -r 59d086639602 -r 4a65f4d6c804 scripts/plot/appearance/legend.m
--- a/scripts/plot/appearance/legend.m	Thu Nov 30 08:29:47 2023 -0800
+++ b/scripts/plot/appearance/legend.m	Fri Dec 01 11:30:43 2023 +0100
@@ -342,9 +342,9 @@
 
     addlistener (hl, "edgecolor", @update_edgecolor_cb);
 
-    addlistener (hl, "location", @update_location_cb);
+    addlistener (hl, "position", @update_position_cb);
 
-    addlistener (hl, "position", @update_position_cb);
+    addlistener (hl, "location", @update_location_cb);
 
     addlistener (hl, "string", @update_string_cb);
 
@@ -419,6 +419,14 @@
 
   updating = getappdata (hl, "__updating_layout__");
   if (isempty (updating) || ! updating)
+
+    ## Store the point size of user provided position
+    units = get (hl, "units");
+    set (hl, "units", "points");
+    pos = get (hl, "position");
+    setappdata (hl, "__user_bouding_box__", pos(3:4));
+    set (hl, "units", units);
+
     if (! strcmp (get (hl, "location"), "none"))
       set (hl, "location", "none");
     else
@@ -555,6 +563,11 @@
 
   persistent updating = false;
 
+  ## Leave legends with user-prescribed position unchanged
+  if (strcmp (get (hl, "location"), "none"))
+    return;
+  endif
+
   if (! updating)
 
     unwind_protect
@@ -935,26 +948,24 @@
     if (! strcmp (get (hl, "location"), "none"))
       update_legend_position (hl, sz);
     else
-      ## Custom location: Adapt width and height if necessary.
-      [x0, y0, x1, y1] = deal (0, 0, sz(1), sz(2));
+      ## Custom location: Eventually adapt width and height, honor prescribed
+      ## anchor.
+      bb = getappdata (hl, "__user_bouding_box__");
 
-      if (sz(1) > pos(3))
-        pos(3) = sz(1);
-      else
-        dx = pos(3)-sz(1);
-        x0 -= dx/2;
-        x1 += dx/2;
+      x0 = 0;
+      if (bb(1) > sz(1))
+        x0 = sz(1)/2 - bb(1)/2;
+        sz(1) = bb(1);
       endif
 
-      if (sz(2) > pos(4))
-        pos(4) = sz(2);
-      else
-        dy = pos(4)-sz(2);
-        y0 -= dy/2;
-        y1 += dy/2;
+      y0 = 0;
+      if (bb(2) > sz(2))
+        y0 = sz(2)/2 - bb(2)/2;
+        sz(2) = bb(2);
       endif
 
-      set (hl, "position",  pos, "xlim", [x0 x1], "ylim", [y0 y1]);
+      set (hl, "position",  [pos(1:2) sz], ...
+               "xlim", [x0 x0+sz(1)], "ylim", [y0 y0+sz(2)]);
     endif
 
   unwind_protect_cleanup
