## Copyright (C) 2013 Ben Abbott
## 
##   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 Octave; see the file COPYING.  If not, see
##   <http://www.gnu.org/licenses/>.  

## -*- texinfo -*- 
## @deftypefn {Function File}{@var{h} =}draw_axes_prop (@var{hax}, @var{property})
## @deftypefns {Function File}{@var{h} =}draw_axes_prop (@var{property})
## Draws a representation of the axes @var{property} in the axes with handle
## @var{hax}, or in the current axes, if the axes handle is not specified.
##
## Valid @var{property} values are;
## @itemize @bullet
## @item @code{position}: Draws a dashed box around the axes @code{position}
## property.
## @item @code{outerposition}: Draws a dashed box around the axes
## @code{outerposition} property.
## @item @code{tightinset}: Draws a dashed patch between the axes @code{position}
## and the combination of the axes @code{postion} and @code{tightinset} properties.
## @item @code{tightboundingbox}: Draws a dashed line around the tight bounding
## box for the specified axes.
## @item @code{looseinset}: Draws a dashed patch between the axes @code{position}
## and the combination of the axes @code{postion} and @code{looseinset} properties.
## The @code{looseinset} is bordered between the @code{outerpostion} and
## @code{position}.
## @item @code{unmodified_axes_position}: The axes @code{position} property,
## before the @code{legend} was added.
## @item @code{unmodified_axes_outerposition}: The axes @code{outerposition} before
## the @code{legend} was added.
## @end itemize
##
## @var{h} is the handle for the rendered object.
## @seealso{set, get}
## @end deftypefn

## Author: Ben Abbott <bpabbott@mac.com>
## Created: 2013-06-23

function [h, x, y] = draw_axes_prop (h1, pos)

  linewidth = 1.5;
  if (nargin == 0)
    h1 = gca ();
    if (isempty (findall (h1, "type", "line")))
      [x, y, z] = peaks ();
      contour (x, y, z);
      axis ([-3, 3, -3, 3])
      xlabel xlabel
      ylabel ylabel
      zlabel zlabel
      title title
    endif
  endif
  units = get (h1, "units");
  set (h1, "units", "normalized", "color", "none")
  if (nargin < 2)
    delete (findobj (h1, "tag", "draw_axes_prop"))
    props = {"position", "outerposition", "tightinset", "tightboundingbox"};
    h = multiple_props (h1, props);
    set (h, "tag", "draw_axes_prop")
  elseif (iscellstr (pos))
    h = multiple_props (h1, pos);
    set (h, "tag", "draw_axes_prop")
  elseif (iscell (pos))
    print_usage ()
  else
    dots_per_inch = get (0, "screenpixelsperinch");
    points_per_inch = 72;
    hfig = ancestor (h1, "figure");
    figure (hfig);
    fpos = get (hfig, "position");
    ## FIXME - Toggle figure position to clean up FLTK rendering on MacOS X
    set (hfig, "position", fpos+1)
    drawnow
    set (hfig, "position", fpos)
    figure_size = fpos(3:4);
    dw = min (linewidth ./ figure_size * dots_per_inch / points_per_inch);
    switch (lower (pos))
    case "position"
      position = get (h1, "position");
      clr = [0 0 1];
      type = "line";
    case "outerposition"
      position = get (h1, "outerposition") + 0.002 * [1 1 -2 -2];
      clr = [0 0.5 0];
      type = "line";
    case "tightboundingbox"
      inset = get (h1, "tightinset");
      position = get (h1, "position");
      position(3:4) = position(3:4) + inset(3:4) + inset(1:2);
      position(1:2) = position(1:2) - inset(1:2);
      clr = [1 0 0];
      type = "line";
    case "tightinset"
      inset = get (h1, "tightinset");
      position = get (h1, "position");
      position(3:4) = position(3:4) + inset(3:4) + inset(1:2);
      position(1:2) = position(1:2) - inset(1:2);
      clr = [0.9 0.95 1];
      type = "patch";
    case "looseinset"
      inset = get (h1, "looseinset");
      position = get (h1, "position");
      position(3:4) = position(3:4) + inset(3:4) + inset(1:2);
      position(1:2) = position(1:2) - inset(1:2);
      position = position + [+1, +1, -2, -2] * dw;
      clr = [0.9 1 1];
      type = "patch";
    case "unmodified_axes_position"
      h = findall (gcf (), "type", "axes", "tag", "legend", ...
                   "userdata", struct ("handle", h1));
      if (isempty (h))
        return
      end
      position = get (h, "unmodified_axes_position") * dots_per_inch ...
               / points_per_inch ./ figure_size([3,4,3,4]);
      clr = [0.5 0 0.5];
      type = "line";
    case "unmodified_axes_outerposition"
      h = findall (gcf (), "type", "axes", "tag", "legend",
                   "userdata", struct ("handle", h1));
      if (isempty (h))
        return
      end
      position = get (h, "unmodified_axes_outerposition") * dots_per_inch ...
               / points_per_inch ./ figure_size([3,4,3,4]);
      clr = [0.5 0.5 0];
      type = "line";
    otherwise
      error ("Invalid property: '%s'", pos)
    end
    h2 = axes ();
    x = [position(1), sum(position([1,3]))];
    x = [x, fliplr(x), x(1)];
    y = [position(2)*[1,1], sum(position([2,4]))*[1,1], position(2)];
    switch type
    case "line"
      h = plot (h2, x, y, '--');
      set (h , "linewidth", linewidth, 'color', clr)
    case "patch"
      xo = x;
      yo = y;
      position = get (h1, "position");
      xi = [position(1), sum(position([1,3]))];
      xi = [xi, fliplr(xi), xi(1)];
      yi = [position(2)*[1,1], sum(position([2,4]))*[1,1], position(2)];
      x = [xo, fliplr(xi)];
      y = [yo, fliplr(yi)];
      h = patch (h2, x(:), y(:), clr);
      set (h, "edgecolor", "none");
      hax = get (hfig, "children");
      hax = shift (hax, -1);
      set (hfig, "children", hax)
    otherwise
      error ("type '%s' not supported", type)
    endswitch
    axis (h2, "off")
    set (h2, "units", "normalized",
             "position", [0 0 1 1],
             "xlim", [0 1],
             "ylim", [0 1],
             "color", "none")
    axes (h1)
    set (h1, "units", units)
  endif
endfunction

function h = multiple_props (hax, props)
  if (nargin < 2)
    props = {"position", "outerposition", "tightinset", "tightboundingbox"};
  endif
  align = cell (1, numel (props));
  funx = align;
  dx = zeros (1, numel (props));
  rot = dx;
  yaxislocation = get (hax, "yaxislocation");
  for n = numel(props):-1:1
    switch props{n}
    case {"position", "unmodified_axes_position"}
      if (strcmp (yaxislocation, "left"))
        align{n} = "left";
        funx{n} = @min;
        rot(n) = 270;
        dx(n) = 0.02;
      else
        align{n} = "right";
        funx{n} = @max;
        rot(n) = 90;
        dx(n) = -0.02;
      endif
    case {"outerposition", "unmodified_axes_position"}
      if (strcmp (yaxislocation, "left"))
        align{n} = "right";
        funx{n} = @max;
        rot(n) = 90;
        dx(n) = -0.02;
      else
        align{n} = "left";
        funx{n} = @min;
        rot(n) = 270;
        dx(n) = 0.02;
      endif
    case {"tightboundingbox"}
      align{n} = "right";
      funx{n} = @min;
      rot(n) = 90;
      dx(n) = -0.02;
    case {"tightinset", "loosinset"}
      align{n} = "left";
      funx{n} = @min;
      rot(n) = 270;
    otherwise
      error ("Unsupported property, '%s'", props{n})
    endswitch
  endfor
  m = 1;
  h = zeros (numel (props), 1);
  if (strcmp (get (hax, "xaxislocation"), "bottom"))
    yt = 0.9;
  else
    yt = 0.85;
  endif
  for n = 1:numel(props)
    [h(n), x, y] = draw_axes_prop (hax, props{n});
    switch get (h(n), "type")
    case "line"
      xt = funx{n}(x) + dx(n);
      clr = get (h(n), "color");
      hsav = gca ();
      axes (get (h(n), "parent"))
      ht(m++) = text (xt, yt, props{n},
                      "fontsize", get (hax, "fontsize"),
                      "rotation", rot(n),
                      "units", "normalized",
                      "horizontalalignment", align{n},
                      "color", clr);
                      get (ht(m-1), "position");
      axes (hsav)
    endswitch
  endfor
endfunction

%!demo
%! clf
%! h1 = gca ();
%! [x, y, z] = peaks ();
%! contour (x, y, z)
%! axis ([-3 3 -3 3])
%! set (h1, "xtick", (-3):3)
%! set (h1, "xticklabel", {"-three", "-two", "-one", "zero", "one", "two", "three"})
%! set (h1, "ytick", (-3):3)
%! set (h1, "yticklabel", {"-three", "-two", "-one", "zero", "one", "two", "three"})
%! set (findall (gcf (), "-property", "fontsize"), "fontsize", 14)
%! str = {"position", "outerposition", "tightinset", "tightboundingbox"};
%! draw_axes_prop (h1, str);

%!demo
%! clf
%! h1 = gca ();
%! [x, y, z] = peaks ();
%! contour (x, y, z)
%! xlabel xlabel
%! ylabel ylabel
%! title title
%! axis ([-3 3 -3 3])
%! set (h1, "xaxislocation", "top")
%! set (h1, "yaxislocation", "right")
%! set (findall (gcf (), "-property", "fontsize"), "fontsize", 14)
%! str = {"position", "outerposition", "tightinset", "tightboundingbox"};
%! draw_axes_prop (h1, str);

%!demo
%! clf
%! h1 = gca ();
%! [x, y, z] = peaks ();
%! contour (x, y, z)
%! axis ([-3 3 -3 3])
%! xlabel xlabel
%! ylabel ylabel
%! title title
%! set (findall (gcf (), "-property", "fontsize"), "fontsize", 14)
%! str = {"position", "outerposition", "tightinset", "tightboundingbox"};
%! draw_axes_prop (h1, str);

%!demo
%! clf
%! h1 = gca ();
%! peaks ()
%! xlabel xlabel
%! ylabel ylabel
%! zlabel zlabel
%! title title
%! set (findall (gcf (), "-property", "fontsize"), "fontsize", 14)
%! str = {"position", "outerposition", "tightinset", "tightboundingbox"};
%! draw_axes_prop (h1, str);

