1########################################################################
2##
3## Copyright (C) 2017-2021 The Octave Project Developers
4##
5## See the file COPYRIGHT.md in the top-level directory of this
6## distribution or <https://octave.org/copyright/>.
7##
8## This file is part of Octave.
9##
10## Octave is free software: you can redistribute it and/or modify it
11## under the terms of the GNU General Public License as published by
12## the Free Software Foundation, either version 3 of the License, or
13## (at your option) any later version.
14##
15## Octave is distributed in the hope that it will be useful, but
16## WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with Octave; see the file COPYING.  If not, see
22## <https://www.gnu.org/licenses/>.
23##
24########################################################################
25
26## -*- texinfo -*-
27## @deftypefn  {} {@var{tickval} =} xticklabels
28## @deftypefnx {} {@var{mode} =} xticklabels ("mode")
29## @deftypefnx {} {} xticklabels (@var{tickval})
30## @deftypefnx {} {} xticklabels ("auto")
31## @deftypefnx {} {} xticklabels ("manual")
32## @deftypefnx {} {@dots{} =} xticklabels (@var{hax}, @dots{})
33## Query or set the tick labels on the x-axis of the current axis.
34##
35## When called without an argument, return a cell array of strings of the
36## current tick labels as specified in the @qcode{"xticklabel"} axes property.
37## These labels can be changed by calling @code{xticklabels} with a cell array
38## of strings.  Note: a vector of numbers will be mapped to a cell array of
39## strings.  If fewer labels are specified than the current number of ticks,
40## blank labels will be appended to the array.
41##
42## When called with argument @qcode{"mode"}, @code{xticklabels} returns the
43## current value of the axes property @qcode{"xticklabelmode"}.  This property
44## can be changed by calling @code{xticklabels} with either @qcode{"auto"}
45## (algorithm determines tick labels) or @qcode{"manual"} (tick labels remain
46## fixed).  Note: Specifying xticklabel values will also set the
47## @qcode{"xticklabelmode"} and @qcode{"xticks"} properties to
48## @qcode{"manual"}.
49##
50## If the first argument @var{hax} is an axes handle, then operate on
51## this axis rather than the current axes returned by @code{gca}.
52##
53## Requesting a return value when calling @code{xticklabels} to set a property
54## value will result in an error.
55##
56## @seealso{xticks, yticklabels, zticklabels, get, set}
57## @end deftypefn
58
59function retval = xticklabels (varargin)
60
61  hax = [];
62  switch (nargin)
63    case 0
64      retval = get (gca , "xticklabel");  # will error if no xticklabel exists.
65      return;
66
67    case 1
68      if (isaxes (varargin{1}))
69        retval = get (varargin{1}, "xticklabel");
70        return;
71      else
72        arg = varargin{1};
73      endif
74
75    case 2
76      if (! isaxes (varargin{1}))
77        error ("xticklabels: HAX must be a handle to an axes object");
78      endif
79      hax = varargin{1};
80      arg = varargin{2};
81
82    otherwise
83      print_usage ();
84
85  endswitch
86
87  if (isempty (hax))
88    hax = gca ();
89  endif
90
91  if (iscell (arg) || isnumeric (arg))
92    if (nargout > 0)
93      error ("xticklabels: too many output arguments requested");
94    endif
95
96    if (isnumeric (arg))
97      ## NOTE: Matlab accepts a cell array, but a non-vector numeric array will
98      ## simply produce a black set of labels without error or warning.
99      ## This implementation allows for a numeric array, which is handled in
100      ## the same order as Matlab handles a cell array
101      arg = num2cell (arg(:));
102
103    endif
104
105    ## Convert any numeric elements to characters, make it a 1D cell array.
106    arg = cellfun (@num2str, arg, "UniformOutput", false)(:);
107
108    ## Pad with blank cell entries if needed.
109    arg((numel (arg) + 1):(numel (get (hax, "xtick")))) = {""};
110
111    ## Setting labels sets both ticklabel and tick mode to manual.
112    set (hax, "xticklabel", arg,
113              "xticklabelmode", "manual",
114              "xtickmode", "manual");
115
116  elseif (ischar (arg))
117    arg = tolower (arg);
118    switch (arg)
119      case "mode"
120        retval = get (hax, "xticklabelmode");
121
122      case {"auto", "manual"}
123        if (nargout > 0)
124          error (["xticklabels: " ...
125                  "too many output arguments requested for arg: ", arg]);
126        endif
127        set (hax, "xticklabelmode", arg);
128
129      otherwise
130        error ("xticklabels: invalid option: %s", arg);
131
132    endswitch
133
134  else
135    print_usage ();
136  endif
137
138endfunction
139
140
141%!test
142%! hf = figure ("visible", "off");
143%! unwind_protect
144%!   set (gca, "xticklabelmode", "auto");
145%!   hax = gca;
146%!   vals1 = xticklabels;
147%!   assert (xticklabels (hax), vals1);
148%!   mode1 = xticklabels ("mode");
149%!   assert (xticklabels (hax, "mode"), mode1);
150%!   xticklabels (hax, "manual");
151%!   assert (xticklabels (hax, "mode"), "manual");
152%!   xticklabels (hax, "auto");
153%!   assert (xticks (hax, "mode"), "auto");
154%!   xticklabels (hax, {"1", "2", "3", "4", "5", "6"});
155%!   assert (xticklabels (hax), {"1"; "2"; "3"; "4"; "5"; "6"});
156%!   assert (xticklabels (hax, "mode"), "manual");
157%!   assert (xticks (hax, "mode"), "manual");
158%! unwind_protect_cleanup
159%!   close (hf);
160%! end_unwind_protect
161
162## Test input validation
163%!error xticklabels (1,2,3)
164%!test
165%! hf = figure ("visible", "off");
166%! unwind_protect
167%!   hax = gca;
168%!   fail ("xticklabels (-1, {})", "HAX must be a handle to an axes");
169%!   fail ("tmp = xticklabels (hax, {'A','B'})", "too many output arguments");
170%!   fail ("tmp = xticklabels (hax, [0, 1])", "too many output arguments");
171%!   fail ("tmp = xticklabels (hax, 'auto')", "too many .* for arg: auto");
172%!   fail ("tmp = xticklabels (hax, 'foo')", "invalid option: foo");
173%! unwind_protect_cleanup
174%!   close (hf);
175%! end_unwind_protect
176