# HG changeset patch
# User Nicholas R. Jankowski <jankowskin@asme.org>
# Date 1588195679 14400
#      Wed Apr 29 17:27:59 2020 -0400
# Node ID 1508efb543f98824b5d044db538f62af44629ebe
# Parent  014e80a92d4fd2051e93f42dd56f10f509ce14b2
add datacursor function based on v3 file submission (patch #9280)

* adds to /draw/: /private/__datacursor__.m, /private/__datacursor_menu__.m
* edits in /draw/: /stairs.m, /private/__stem__.m, /private/__plt__.m

diff -r 014e80a92d4f -r 1508efb543f9 scripts/plot/draw/private/__datacursor__.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/private/__datacursor__.m	Wed Apr 29 17:27:59 2020 -0400
@@ -0,0 +1,119 @@
+## Copyright (C) 2017 Pantxo Diribarne
+## 
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn {} {@var{h} =} __datacursor__ ()
+## @deftypefnx {} {@var{h} =} __datacursor__ (@var{hax})
+## Undocumented internal function.
+## @end deftypefn
+
+## Author: Pantxo Diribarne <pantxo@gre046552>
+## Created: 2017-02-10
+## Modified by R. Baudin, 2017-05-10
+
+function [htmp] = __datacursor__ (hf = [])
+  if (isempty (hf))
+    hf = get (0, "currentfigure")
+    if (isempty (hf))
+      error ("__datacursor__: no current figure")
+    endif
+  elseif (! ishandle (hf))
+    error ("__datacursor__: not a valid figure handle")
+  endif
+  
+  htmp = install_all_listeners (hf);
+endfunction
+
+function htmp = install_all_listeners (hf)
+    htmp = annotation (hf, "textarrow", [0 0], [eps eps], ...
+                       "headlength", 8, "headwidth", 8, "headstyle", "vback1", "fontsize", 14, ...
+                       "visible", "off");
+  install_listeners (hf, htmp);
+  cursors = getappdata (hf, "__datacursor__");
+  setappdata (hf, "__datacursor__", [cursors htmp]);
+endfunction
+
+function install_listeners (hf, htmp)
+  haxes = get (hf, "children");
+  haxes(! isaxes (haxes)) = [];
+  tag = get (haxes, "tag");
+  idx = strcmp (tag, "legend") | strcmp (tag, "colorbar") | ...
+        strcmp (tag, "scribeoverlay");
+  haxes(idx) = [];
+  for hax = haxes
+    dellistener (hax, "currentpoint")
+    
+    lsn = {@update_nearest, htmp};
+    addlistener (hax, "currentpoint", lsn)
+    addlistener (htmp, "beingdeleted", {@cleanlistener, hax, lsn})
+  endfor
+endfunction
+
+function cleanlistener (h, e, h2, lsn)
+  if (ishandle (h2))
+    dellistener (h2, "currentpoint", lsn);
+  endif
+endfunction
+
+function update_nearest (hax, e, ht)
+  hf = ancestor (hax, "figure");
+  if (getappdata (hf, "__datacursor__")(end) != ht)
+    return;
+  endif
+  hax = get (hf, "currentaxes");
+ 
+  set(0, "currentfigure", hf);
+  htype = get(gco(hf), "type");
+  
+  if (strcmp(htype, "line"))
+    xd = get (gco(hf), "xdata");
+    yd = get (gco(hf), "ydata");
+    if (iscell (xd))
+      xd = [xd{:}];
+      yd = [yd{:}];
+    endif
+    cp = get (hax, "currentpoint")(1,1:2);
+    if (! isempty (xd))
+      [~, idx] = min ((cp(1)-xd).^2 + (cp(2)-yd).^2);
+      [x, y] = axes2normalized (hax, xd(idx), yd(idx));
+      set (ht, "string", sprintf ("(%g, %g)", xd(idx), yd(idx)), ...
+           "x", [x+0.02 x], "y", [y+0.02 y],
+           "visible", "on", "userdata", [xd(idx) yd(idx)])
+    endif
+  endif
+endfunction
+
+function [x0, y0] = axes2normalized (hax, x, y)
+  xl = xlim (hax);
+  yl = ylim (hax);
+  
+  if (strcmp (get (hax, "xscale"), "log"))
+    xl = log10 (xl);
+    x0 = (log10(x) - xl(1)) / diff(xl);
+  else
+    x0 = (x - xl(1)) / diff(xl);
+  endif
+    
+  if (strcmp (get (hax, "yscale"), "log"))
+    yl = log10 (yl);
+    y0 = (log10(y) - yl(1)) / diff(yl);
+  else
+    y0 = (y - yl(1)) / diff(yl);
+  endif
+  
+  pos = get (hax, "position");
+  x0 = x0*pos(3) + pos(1);
+  y0 = y0*pos(4) + pos(2);
+endfunction
diff -r 014e80a92d4f -r 1508efb543f9 scripts/plot/draw/private/__datacursor_menu__.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/private/__datacursor_menu__.m	Wed Apr 29 17:27:59 2020 -0400
@@ -0,0 +1,72 @@
+## Copyright (C) 2017 Pantxo Diribarne
+## 
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn {} {@var{retval} =} __datacursor_menu__ ()
+## Undocumented internal function.
+## @end deftypefn
+
+## Author: Pantxo Diribarne <pantxo@gre046552>
+## Created: 2017-02-10
+## Modified by R. Baudin, 2017-05-10
+
+function hm = __datacursor_menu__ ()
+  
+  hf = get (0, "currentfigure");
+  
+  if (isempty (hf))
+    error ("__datacursor_menu__: no current figure");
+  endif
+  
+  # Don't add menu if custom property 'datamenu' already exist
+  if (isprop(hf, "datamenu") == 0)
+    addproperty("datamenu", hf, "boolean",true); # Add custom property 'datamenu'
+    hm = uimenu ("label", "&Data");
+    htmp = hm;  
+    htmp = uimenu (hm, "label", "New data cursor", "callback", {@update_new, htmp});
+    htmp = uimenu (hm, "label", "Show/hide data cursor(s)", "callback", @update_show);
+    htmp = uimenu (hm, "label", "Get cursor(s) data", "callback", @data_dlg);
+  endif
+
+endfunction
+
+function update_new (hmenu, e, hshow)
+  __datacursor__ (gcbf);
+  update_show (hshow, [], true);
+endfunction
+      
+function update_show (hmenu, e, on = [])
+  hc = getappdata (gcbf, "__datacursor__");
+  if (! isempty (hc))
+    if (isempty (on))
+      on = ifelse (all (strcmp (get (hc, "visible"), "on")), "off", "on");
+    endif
+    set (hc, "visible", on)
+    set (hmenu, "checked", on)
+  endif
+endfunction
+
+function data_dlg (hm, e)
+  pos = get (gcbf, "position");
+  hc = getappdata (gcbf, "__datacursor__");
+  nm = inputdlg ({"Name of the variable:"}, "Export data", 1, {"cursor_data"});
+  if (! isempty (nm))
+    for ii = 1:numel (hc)
+      xy = get (hc(ii), "userdata");
+      evalin ("base", sprintf ("%s.('%s') = [%16.16f; %16.16f];", ...
+                               nm{1}, ["cursor" num2str(ii)], xy(1), xy(2)));
+    endfor
+  endif
+endfunction
diff -r 014e80a92d4f -r 1508efb543f9 scripts/plot/draw/private/__plt__.m
--- a/scripts/plot/draw/private/__plt__.m	Tue Apr 28 16:24:10 2020 -0700
+++ b/scripts/plot/draw/private/__plt__.m	Wed Apr 29 17:27:59 2020 -0400
@@ -154,11 +155,13 @@
     error ("__plt__: invalid number of arguments");
   endif
 
+  __datacursor_menu__;
+  
 endfunction
 
 function [hlgnd, tlgnd, setlgnd] = __plt_key__ (hp, options,
diff -r 014e80a92d4f -r 1508efb543f9 scripts/plot/draw/private/__stem__.m
--- a/scripts/plot/draw/private/__stem__.m	Tue Apr 28 16:24:10 2020 -0700
+++ b/scripts/plot/draw/private/__stem__.m	Wed Apr 29 17:27:59 2020 -0400
@@ -196,6 +183,8 @@
     endif
   end_unwind_protect
 
+  __datacursor_menu__;
+
 endfunction
 
 function [x, y, z, dofill, lc, ls, mc, ms, args] = check_stem_arg (have_z, varargin)
diff -r 014e80a92d4f -r 1508efb543f9 scripts/plot/draw/stairs.m
--- a/scripts/plot/draw/stairs.m	Tue Apr 28 16:24:10 2020 -0700
+++ b/scripts/plot/draw/stairs.m	Wed Apr 29 17:27:59 2020 -0400
@@ -245,6 +239,8 @@
     h = 0;
   endif
 
+  __datacursor_menu__;
+
 endfunction
 
 function update_props (h, ~)
