# HG changeset patch # User David Bateman # Date 1284671602 -7200 # Node ID 6ea65c5de87a7347bf77eefb01fb2f5a7be05b1f # Parent f1c4527b40249a185c0c97e36099f2d106add862 Respect the units and paperunits figure properties and the units and fontunits axes properties diff -r f1c4527b4024 -r 6ea65c5de87a scripts/plot/__go_draw_axes__.m --- a/scripts/plot/__go_draw_axes__.m Thu Sep 16 14:07:21 2010 -0400 +++ b/scripts/plot/__go_draw_axes__.m Thu Sep 16 23:13:22 2010 +0200 @@ -1342,7 +1342,7 @@ else if (nd == 3) fputs (plot_stream, "set border 895;\n"); - else + elseif (! isempty (axis_obj.ytick)) if (strcmpi (axis_obj.yaxislocation, "right")) fprintf (plot_stream, "unset ytics; set y2tics %s nomirror\n", axis_obj.tickdir); diff -r f1c4527b4024 -r 6ea65c5de87a scripts/plot/__plt_get_axis_arg__.m --- a/scripts/plot/__plt_get_axis_arg__.m Thu Sep 16 14:07:21 2010 -0400 +++ b/scripts/plot/__plt_get_axis_arg__.m Thu Sep 16 23:13:22 2010 +0200 @@ -40,7 +40,8 @@ && varargin{1}(1) != 0 && ! isfigure (varargin{1}(1))) tmp = varargin{1}; obj = get (tmp); - if (strcmp (obj.type, "axes") || strcmp (obj.type, "hggroup")) + if ((strcmp (obj.type, "axes") && ! strcmp (obj.tag, "legend")) + || strcmp (obj.type, "hggroup")) h = ancestor (tmp, "axes"); varargin(1) = []; if (isempty (varargin)) diff -r f1c4527b4024 -r 6ea65c5de87a scripts/plot/legend.m --- a/scripts/plot/legend.m Thu Sep 16 14:07:21 2010 -0400 +++ b/scripts/plot/legend.m Thu Sep 16 23:13:22 2010 +0200 @@ -1,5 +1,4 @@ -## Copyright (C) 2001, 2006, 2007, 2008, 2009 Laurent Mazet -## Copyright (C) 2006 John W. Eaton +## Copyright (C) 2010 David Bateman ## ## This file is part of Octave. ## @@ -22,6 +21,7 @@ ## @deftypefnx {Function File} {} legend (@var{matstr}) ## @deftypefnx {Function File} {} legend (@var{cell}) ## @deftypefnx {Function File} {} legend (@dots{}, "location", @var{pos}) +## @deftypefnx {Function File} {} legend (@dots{}, "orientation", @var{orient}) ## @deftypefnx {Function File} {} legend (@var{hax}, @dots{}) ## @deftypefnx {Function File} {} legend (@var{hobjs}, @dots{}) ## @deftypefnx {Function File} {} legend (@var{hax}, @var{hobjs}, @dots{}) @@ -70,6 +70,10 @@ ## can be appended to any location string ## @end multitable ## +## The optional parameter @var{orient} determines if the key elements +## are placed vertically or horizontally. The allowed values are "vertical" +## or "horizontal" with the default being "vertical". +## ## The following customizations are available using @var{option}: ## ## @table @asis @@ -94,25 +98,53 @@ ## @end table ## @end deftypefn -function legend (varargin) +function [hlegend2, hobjects2, hplot2, text_strings2] = legend (varargin) - [ca, varargin, nargin] = __plt_get_axis_arg__ ("legend", varargin{:}); - nargs = nargin; + [ca, varargin, nargs] = __plt_get_axis_arg__ (true, "legend", varargin{:}); + if (isnan (ca)) + fig = get (0, "currentfigure"); + if (isempty (fig)) + ca = gca (); + fig = get (ca, "parent"); + else + ca = get (fig, "children"); + ca ( ! strcmp (get (get (fig, "children"), "type"), "axes")) = []; + ca_pos = get (get (fig, "currentaxes"), "position"); + ca_outpos = get (get (fig, "currentaxes"), "outerposition"); + for i = numel (ca) : -1 : 1 + if (! all (ca_pos, get (ca(i), "position") ) + || ! all (ca_outpos, get (ca(i), "outerposition"))) + ca(i) = []; + endif + endfor + endif + else + fig = get (ca, "parent"); + endif if (all (ishandle (varargin{1}))) kids = flipud (varargin{1}(:)); varargin(1) = []; nargs = numel (varargin); else - kids = get (ca, "children"); + kids = get (fig, "children"); + kids (strcmp (get (kids, "tag"), "legend")) = []; + if (isscalar (kids)) + kids = get(kids, "children")(:); + else + kids = [get(kids, "children"){:}](:); + endif endif nkids = numel (kids); + position = "northeast"; + orientation = "vertical"; if (nargs > 0) pos = varargin{nargs}; if (isnumeric (pos) && isscalar (pos) && round (pos) == pos) if (pos >= -1 && pos <= 4) - set (ca, "keypos", pos); + position = {"northeastoutside", "best", "northeast", + "northwest", "southwest", "southeast"} (pos + 2); nargs--; else error ("legend: invalid position specified"); @@ -120,17 +152,64 @@ endif endif - if (nargs > 1) + while (nargs > 1) pos = varargin{nargs-1}; str = varargin{nargs}; if (strcmpi (pos, "location") && ischar (str)) - set (ca, "keypos", str); + position = lower (str); + nargs -= 2; + elseif (strcmpi (pos, "orientation") && ischar (str)) + orientation = lower (str); nargs -= 2; + else + break; endif + endwhile + + ## Validate the orientation + switch (orientation) + case {"vertical", "horizontal"} + otherwise + error ("legend: unrecognized legend orientation"); + endswitch + + ## Validate the position type is valid + outside = false; + inout = findstr (position, "outside"); + if (! isempty (inout)) + outside = true; + position = position(1:inout-1); + else + outside = false; endif - k = 1; - turn_on_legend = false; + switch (position) + case {"north", "south", "east", "west", "northeast", "northwest", ... + "southeast", "southwest"} + case "best" + warning ("legend: 'Best' not yet implemented for location specifier\n"); + position = "northeast"; + otherwise + error ("legend: unrecognized legend position"); + endswitch + + show = "create"; + textpos = "default"; + reverse = false; + box = "default"; + + hlegend = []; + fkids = get (fig, "children"); + for i = 1 : numel(fkids) + if (ishandle (fkids (i)) && strcmp (get (fkids (i), "type"), "axes") + && (strcmp (get (fkids (i), "tag"), "legend"))) + udata = get (fkids (i), "userdata"); + if (! isempty (intersect (udata.handle, ca))) + hlegend = fkids (i); + break; + endif + endif + endfor if (nargs == 1) arg = varargin{1}; @@ -139,30 +218,31 @@ str = tolower (deblank (arg)); switch (str) case {"off", "hide"} - set (ca, "key", "off"); + show = "off"; nargs--; case "show" - set (ca, "key", "on"); + show = "on"; nargs--; case "toggle" - val = get (ca, "key"); - if (strcmpi (val, "on")) - set (ca, "key", "off"); + if (isempty (hlegend) || strcmp (get (hlegend, "visible"), "off")) + show = "on"; else - set (ca, "key", "on"); + show = "off"; endif nargs--; case "boxon" - set (ca, "key", "on", "keybox", "on"); + box = "on"; nargs--; case "boxoff" - set (ca, "keybox", "off"); + box = "off"; nargs--; case "left" - set (ca, "keyreverse", "off") + textpos = "left"; + reverse = false; nargs--; case "right" - set (ca, "keyreverse", "on") + textpos = "right"; + reverse = true; nargs--; otherwise endswitch @@ -178,62 +258,507 @@ endif endif - if (nargs > 0) - have_data = false; - for k = 1:nkids - typ = get (kids(k), "type"); - if (strcmp (typ, "line") || strcmp (typ, "surface") - || strcmp (typ, "patch") || strcmp (typ, "hggroup")) - have_data = true; - break; + if (strcmp (show, "off")) + if (! isempty (hlegend)) + set (hlegend, "visible", "off"); + set (get (hlegend, "children"), "visible", "off"); + hlegend = []; + endif + hobjects = []; + hplots = []; + text_strings = {}; + elseif (strcmp (show, "on")) + if (! isempty (hlegend)) + set (hlegend, "visible", "on"); + set (get (hlegend, "children"), "visible", "on"); + else + hobjects = []; + hplots = []; + text_strings = {}; + endif + elseif (strcmp (box, "on")) + if (! isempty (hlegend)) + set (hlegend, "visible", "on", "box", "on"); + endif + elseif (strcmp (box, "off")) + if (! isempty (hlegend)) + set (hlegend, "box", "off", "visible", "off"); + endif + else + hobjects = []; + hplots = []; + text_strings = {}; + + if (nargs > 0) + have_data = false; + for k = 1:nkids + typ = get (kids(k), "type"); + if (strcmp (typ, "line") || strcmp (typ, "surface") + || strcmp (typ, "patch") || strcmp (typ, "hggroup")) + have_data = true; + break; + endif + endfor + + if (! have_data) + warning ("legend: plot data is empty; setting key labels has no effect"); + endif + endif + + if (strcmp (textpos, "default")) + warned = false; + k = nkids; + for i = 1 : nargs + arg = varargin{i}; + if (ischar (arg)) + typ = get (kids(k), "type"); + while (k > 0 + && ! (strcmp (typ, "line") || strcmp (typ, "surface") + || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) + typ = get (kids(--k), "type"); + endwhile + if (k > 0) + if (strcmp (get (kids(k), "type"), "hggroup")) + hgkids = get (kids(k), "children"); + for j = 1 : length (hgkids) + hgobj = get (hgkids (j)); + if (isfield (hgobj, "displayname")) + set (hgkids(j), "displayname", arg); + hplots = [hplots, hgkids(j)]; + text_strings = {text_strings{:}, arg}; + break; + endif + endfor + else + set (kids(k), "displayname", arg); + hplots = [hplots, kids(k)]; + text_strings = {text_strings{:}, arg}; + endif + + if (--k == 0) + break; + endif + elseif (! warned) + warned = true; + warning ("legend: ignoring extra labels"); + endif + else + error ("legend: expecting argument to be a character string"); + endif + endfor + else + k = nkids; + while (k > 0) + typ = get (kids(k), "type"); + while (k > 0 + && ! (strcmp (typ, "line") || strcmp (typ, "surface") + || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) + typ = get (kids(--k), "type"); + endwhile + if (k > 0) + if (strcmp (get (kids(k), "type"), "hggroup")) + hgkids = get (kids(k), "children"); + for j = 1 : length (hgkids) + hgobj = get (hgkids (j)); + if (isfield (hgobj, "displayname") + && ! isempty (hgobj.displayname)) + hplots = [hplots, hgkids(j)]; + text_strings = {text_strings{:}, hbobj.displayname}; + break; + endif + endfor + else + if (! isempty (get (kids (k), "displayname"))) + hplots = [hplots, kids(k)]; + text_strings = {text_strings{:}, get(kids (k), "displayname")}; + endif + endif + if (--k == 0) + break; + endif + endif + endwhile + endif + + if (isempty (hplots)) + if (! isempty (hlegend)) + fkids = get (fig, "children"); + delete (fkids (fkids == hlegend)); + hlegend = []; + hobjects = []; + hplots = []; + text_strings = {}; + endif + else + ## Delete the old legend if it exists + if (! isempty (hlegend)) + fkids = get (fig, "children"); + delete (fkids (fkids == hlegend)); endif - endfor - if (! have_data) - warning ("legend: plot data is empty; setting key labels has no effect"); + + ## Force the figure to be drawn here, so that the figure position + ## is updated correctly before reading it + drawnow (); + + ## Get axis size and fontsize in points. + ## Rely on listener to handle coversion. + units = get (ca(1), "units"); + fontunits = get (ca(1), "fontunits"); + unwind_protect + set (ca(1), "units", "points"); + set (ca(1), "fontunits", "points"); + ca_pos = get (ca(1), "position"); + ca_outpos = get (ca(1), "outerposition"); + ca_fontsize = get (ca(1), "fontsize"); + unwind_protect_cleanup + set (ca(1), "units", units); + set (ca(1), "fontunits", fontunits); + end_unwind_protect + + ## Padding between legend entries horizontally and vertically + xpad = 2; + ypad = 2; + + ## Length of line segments in the legend in points + linelength = 15; + + ## Create the axis first + ## FIXME hlegend should inherit properties from "ca" + curaxes = get (fig, "currentaxes"); + unwind_protect + hlegend = axes ("tag", "legend", "userdata", struct ("handle", ca), + "box", "off", "outerposition", [0, 0, 0, 0], + "xtick", [], "ytick", [], "xticklabel", "", + "yticklabel", "", "zticklabel", "", + "xlim", [0, 1], "ylim", [0, 1], "visible", "off", + "activepositionproperty", "position"); + + ## Add text label to the axis first, checking their extents + nentries = numel (hplots); + texthandle = []; + maxwidth = 0; + maxheight = 0; + for k = 1 : nentries + if (reverse) + texthandle = [texthandle, text(0, 0, text_strings {k}, + "horizontalalignment", "left")]; + else + texthandle = [texthandle, text(0, 0, text_strings {k}, + "horizontalalignment", "right")]; + endif + units = get (texthandle (end), "units"); + unwind_protect + set (texthandle (end), "units", "points"); + extents = get (texthandle (end), "extent"); + ## FIXME fudge for gnuplot as the text extents are calculated from + ## the FreeType text render rather than from gnuplot itself. Your + ## luck will vary depending on the terminals that are used. + if (strcmp (get (fig, "__backend__"), "gnuplot")) + extents = [0,0,1,0] + [1,1,1.22,1] .* extents; + linelength = 20; + endif + maxwidth = max (maxwidth, extents (3)); + maxheight = max (maxheight, extents (4)); + unwind_protect_cleanup + set (texthandle (end), "units", units); + end_unwind_protect + endfor + + num1 = nentries; + if (strcmp (orientation, "vertical")) + height = nentries * (ypad + maxheight); + if (outside) + if (height > ca_pos (4)) + ## Avoid shrinking the height of the axis to zero if outside + num1 = ca_pos(4) / (maxheight + ypad) / 2; + endif + else + if (height > 0.9 * ca_pos (4)) + num1 = 0.9 * ca_pos(4) / (maxheight + ypad); + endif + endif + else + width = nentries * (ypad + maxwidth); + if (outside) + if (width > ca_pos (3)) + ## Avoid shrinking the width of the axis to zero if outside + num1 = ca_pos(3) / (maxwidth + ypad) / 2; + endif + else + if (width > 0.9 * ca_pos (3)) + num1 = 0.9 * ca_pos(3) / (maxwidth + ypad); + endif + endif + endif + num2 = ceil (nentries / num1); + + xstep = 3 * xpad + (maxwidth + linelength); + if (reverse) + xoffset = xpad; + txoffset = 2 * xpad + linelength; + else + xoffset = 2 * xpad + maxwidth; + txoffset = xpad + maxwidth; + endif + ystep = (ypad + maxheight); + yoffset = ystep / 2; + + ## Place the legend in the desired position + if (strcmp (orientation, "vertical")) + lpos = [0, 0, num2 * xstep, num1 * ystep]; + else + lpos = [0, 0, num1 * xstep, num2 * ystep]; + endif + switch(position) + case "north" + if (outside) + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ... + ca_outpos(2) + ca_outpos(4) - lpos(4), lpos(3), lpos(4)]; + + new_pos = [ca_pos(1), ca_pos(2), ca_pos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2), ca_outpos(3), ... + ca_outpos(4) - lpos(4)]; + else + ca_pos + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ... + ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)]; + endif + case "south" + if (outside) + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ca_outpos(2), ... + lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2) + lpos(4), ca_pos(3), ... + ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2) + lpos(4), ... + ca_outpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ... + ca_pos(2) + ypad, lpos(3), lpos(4)]; + endif + case "east" + if (outside) + lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ... + ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ca_pos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4)]; + else + lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ... + ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)]; + endif + case "west" + if (outside) + lpos = [ca_outpos(1), ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, ... + lpos(3), lpos(4)]; + new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ... + ca_pos(3) - lpos(3), ca_pos(4)]; + new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4)]; + else + lpos = [ca_pos(1) + ypad, ... + ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)]; + endif + case "northeast" + if (outside) + lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ... + ca_outpos(2) + ca_outpos(4) - lpos(4), lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ... + ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ... + ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)]; + endif + case "northwest" + if (outside) + lpos = [ca_outpos(1), ca_outpos(2) + ca_outpos(4) - lpos(4), ... + lpos(3), lpos(4)]; + new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ... + ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ypad, ... + ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)]; + endif + case "southeast" + if (outside) + lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ca_outpos(2), + lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2) + lpos(4), ... + ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2) + lpos(4), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ... + ca_pos(2) + ypad, lpos(3), lpos(4)]; + endif + case "southwest" + if (outside) + lpos = [ca_outpos(1), ca_outpos(2), 0, lpos(3), lpos(4)]; + new_pos = [ca_pos(1) +lpos(3), ca_pos(2) + lpos(4), ... + ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2) + lpos(4), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ypad, ca_pos(2) + ypad, lpos(3), lpos(4)]; + endif + endswitch + + units = get (hlegend, "units"); + unwind_protect + set (hlegend, "units", "points"); + set (hlegend, "position", lpos, "outerposition", lpos); + unwind_protect_cleanup + set (hlegend, "units", units); + end_unwind_protect + + ## Now write the line segments and place the text objects correctly + xk = 0; + yk = 0; + for k = 1 : numel (hplots) + hobjects = [hobjects, texthandle (k)]; + color = get (hplots (k), "color"); + style = get (hplots (k), "linestyle"); + if (! strcmp (style, "none")) + l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3), + "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4), + "color", color, "linestyle", style); + hobjects = [hobjects, l1]; + endif + marker = get (hplots (k), "marker"); + if (! strcmp (marker, "none")) + l1 = line ("xdata", (xoffset + 0.5 * linelength + xk * xstep) / lpos(3), + "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4), + "color", color, "marker", marker, + "markeredgecolor", get (hplots (k), "markeredgecolor"), + "markerfacecolor", get (hplots (k), "markerfacecolor"), + "markersize", get (hplots (k), "markersize")); + hobjects = [hobjects, l1]; + endif + set (texthandle (k), "position", [(txoffset + xk * xstep) / lpos(3), ... + (lpos(4) - yoffset - yk * ystep) / lpos(4)]); + + if (strcmp (orientation, "vertical")) + yk++; + if (yk > num1) + yk = 0; + xk++; + endif + else + xk++; + if (xk > num1) + xk = 0; + yk++; + endif + endif + endfor + + ## Add an invisible text object to original axis + ## that when it is destroyed will remove the legend + t1 = text (0, 0, "", "parent", ca(1), "tag", "legend", + "handlevisibility", "off", "visible", "off", + "xliminclude", "off", "yliminclude", "off"); + set (t1, "deletefcn", {@deletelegend1, hlegend}); + + ## Resize the axis the legend is attached to if the + ## legend is "outside" the plot and create listener to + ## resize axis to original size if the legend is deleted, + ## hidden or shown + if (outside) + for i = 1 : numel (ca) + units = get (ca(i), "units"); + unwind_protect + set (ca(i), "units", "points"); + set (ca (i), "position", new_pos, "outerposition", new_outpos); + unwind_protect_cleanup + set (ca(i), "units", units); + end_unwind_protect + endfor + + set (hlegend, "deletefcn", {@deletelegend2, ca, ... + ca_pos, ca_outpos, t1}); + addlistener (hlegend, "visible", {@hideshowlegend, ca, ... + ca_pos, new_pos, ... + ca_outpos, new_outpos}); + else + set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1}); + endif + unwind_protect_cleanup + set (fig, "currentaxes", curaxes); + end_unwind_protect endif endif - warned = false; - k = nkids; - for i = 1:nargs - arg = varargin{i}; - if (ischar (arg)) - typ = get (kids(k), "type"); - while (k > 1 - && ! (strcmp (typ, "line") || strcmp (typ, "surface") - || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) - typ = get (kids(--k), "type"); - endwhile - if (k > 0) - if (strcmp (get (kids(k), "type"), "hggroup")) - hgkids = get (kids(k), "children"); - for j = 1 : length (hgkids) - hgobj = get (hgkids (j)); - if (isfield (hgobj, "keylabel")) - set (hgkids(j), "keylabel", arg); - break; - endif - endfor + if (nargout > 0) + hlegend2 = hlegend2; + hobjects2 = hobjects; + hplot2 = hplots; + text_strings2 = text_strings; + endif + +endfunction + +function hideshowlegend (h, d, ca, pos1, pos2, outpos1, outpos2) + isvisible = strcmp (get (h, "visible"), "off"); + if (! isvisible) + kids = get (h, "children"); + for i = 1 : numel (kids) + if (! strcmp (get (kids(i), "visible"), "off")) + isvisible = true; + break; + endif + endfor + endif + + for i = 1 : numel (ca) + if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ca(i), "beingdeleted"), "off")) + units = get (ca(i), "units"); + unwind_protect + set (ca(i), "units", "points"); + if (isvisible) + set (ca(i), "position", pos2, "outerposition", outpos2); else - set (kids(k), "keylabel", arg); - endif - turn_on_legend = true; - if (--k == 0) - break; + set (ca(i), "position", pos1, "outerposition", outpos1); endif - elseif (! warned) - warned = true; - warning ("legend: ignoring extra labels"); - endif - else - error ("legend: expecting argument to be a character string"); + unwind_protect_cleanup + set (ca(i), "units", units); + end_unwind_protect endif endfor +endfunction - if (turn_on_legend) - set (ca, "key", "on"); +function deletelegend1 (h, d, ca) + if (ishandle (ca) && strcmp (get (ca, "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ca, "beingdeleted"), "off")) + delete (ca); endif +endfunction +function deletelegend2 (h, d, ca, pos, outpos, t1) + for i = 1 : numel (ca) + if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ca(i), "beingdeleted"), "off")) + if (!isempty (pos) && !isempty(outpos)) + units = get (ca(i), "units"); + unwind_protect + set (ca(i), "units", "points"); + set (ca(i), "position", pos, "outerposition", outpos, "deletefcn", ""); + unwind_protect_cleanup + set (ca(i), "units", units); + end_unwind_protect + endif + if (i == 1) + set (t1, "deletefcn", ""); + delete (t1); + endif + endif + endfor endfunction %!demo diff -r f1c4527b4024 -r 6ea65c5de87a src/ChangeLog --- a/src/ChangeLog Thu Sep 16 14:07:21 2010 -0400 +++ b/src/ChangeLog Thu Sep 16 23:13:22 2010 +0200 @@ -1,3 +1,27 @@ +2010-09-16 David Bateman + + * graphics.cc (static Matrix screen_size_pixels (void), static Matrix + papersize_from_type (const caseless_str, const caseless_str))): New + functions. + (void figure::properties::set_paperunits (const octave_value&), + void figure::properties::set_papertype (const octave_value&), + void figure::properties::update_paperunits (const caseless_str&)) + void figure::properties::update_papertype (void), + void figure::properties::update_papersize (void), + void figure::properties::update_units (const caseless_str&)): New + methods of the figure class. + (void axes::properties::set_units (const octave_value&), + void axes::properties::update_units (const caseless_str&), + void axes::properties::set_fontunits (const octave_value&), + void axes::properties::update_fontunits (const caseless_str&)): + New methods of the axes class. + * graphics.h.in (void figure::properties::update_paperunits + (const caseless_str&), void figure::properties::update_units + (const caseless_str&)): Declaration of new figure methods. + (void figure::properties::update_paperunits (const caseless_str&), + void figure::properties::update_units (const caseless_str&)): + Declaration of new axes methods. + 2010-09-16 John P. Swensen * DLD-FUNCTIONS/))magick_read__.cc (write_image): Remove diff -r f1c4527b4024 -r 6ea65c5de87a src/graphics.cc --- a/src/graphics.cc Thu Sep 16 14:07:21 2010 -0400 +++ b/src/graphics.cc Thu Sep 16 23:13:22 2010 +0200 @@ -532,6 +532,15 @@ return retval; } +// This function always returns the screensize in pixels +static Matrix +screen_size_pixels (void) +{ + graphics_object obj = gh_manager::get_object (0); + Matrix sz = obj.get ("screensize").matrix_value (); + return convert_position (sz, obj.get ("units").string_value (), "pixels", sz.extract_n (0, 2, 1, 2)).extract_n (0, 2, 1, 2); +} + static graphics_object xget_ancestor (const graphics_object& go_arg, const std::string& type) { @@ -2600,6 +2609,9 @@ gripe_set_invalid ("callbackobject"); } +// FIXME This should update monitorpositions and pointerlocation, but +// as these properties are yet used, and so it doesn't matter that they +// aren't set yet. void root_figure::properties::update_units (void) { @@ -2747,7 +2759,7 @@ Matrix figure::properties::get_boundingbox (bool) const { - Matrix screen_size = xget (0, "screensize").matrix_value ().extract_n (0, 2, 1, 2); + Matrix screen_size = screen_size_pixels (); Matrix pos; pos = convert_position (get_position ().matrix_value (), get_units (), @@ -2763,7 +2775,7 @@ void figure::properties::set_boundingbox (const Matrix& bb) { - Matrix screen_size = xget (0, "screensize").matrix_value ().extract_n (0, 2, 1, 2); + Matrix screen_size = screen_size_pixels (); Matrix pos = bb; pos(1) = screen_size(1) - pos(1) - pos(3); @@ -2798,6 +2810,297 @@ } } +void +figure::properties::set_paperunits (const octave_value& v) +{ + if (! error_state) + { + caseless_str typ = get_papertype (); + caseless_str punits = v.string_value (); + if (! error_state) + { + if (punits.compare ("normalized") && typ.compare ("custom")) + error ("set: can't set the paperunits to normalized when the papertype is custom"); + else + { + caseless_str old_paperunits = get_paperunits (); + if (paperunits.set (v, true)) + { + update_paperunits (old_paperunits); + mark_modified (); + } + } + } + } +} + +void +figure::properties::set_papertype (const octave_value& v) +{ + if (! error_state) + { + caseless_str typ = v.string_value (); + caseless_str punits = get_paperunits (); + if (! error_state) + { + if (punits.compare ("normalized") && typ.compare ("custom")) + error ("set: can't set the paperunits to normalized when the papertype is custom"); + else + { + if (papertype.set (v, true)) + { + update_papertype (); + mark_modified (); + } + } + } + } +} + +static Matrix +papersize_from_type (const caseless_str punits, const caseless_str typ) +{ + Matrix ret (1, 2, 1.0); + + if (! punits.compare ("normalized")) + { + double in2units; + double mm2units; + + if (punits.compare ("inches")) + { + in2units = 1.0; + mm2units = 1 / 25.4 ; + } + else if (punits.compare ("centimeters")) + { + in2units = 2.54; + mm2units = 1 / 10.0; + } + else // points + { + in2units = 72.0; + mm2units = 72.0 / 25.4; + } + + if (typ.compare ("usletter")) + { + ret (0) = 8.5 * in2units; + ret (1) = 11.0 * in2units; + } + else if (typ.compare ("uslegal")) + { + ret (0) = 8.5 * in2units; + ret (1) = 14.0 * in2units; + } + else if (typ.compare ("tabloid")) + { + ret (0) = 11.0 * in2units; + ret (1) = 17.0 * in2units; + } + else if (typ.compare ("a0")) + { + ret (0) = 841.0 * mm2units; + ret (1) = 1189.0 * mm2units; + } + else if (typ.compare ("a1")) + { + ret (0) = 594.0 * mm2units; + ret (1) = 841.0 * mm2units; + } + else if (typ.compare ("a2")) + { + ret (0) = 420.0 * mm2units; + ret (1) = 594.0 * mm2units; + } + else if (typ.compare ("a3")) + { + ret (0) = 297.0 * mm2units; + ret (1) = 420.0 * mm2units; + } + else if (typ.compare ("a4")) + { + ret (0) = 210.0 * mm2units; + ret (1) = 297.0 * mm2units; + } + else if (typ.compare ("a5")) + { + ret (0) = 148.0 * mm2units; + ret (1) = 210.0 * mm2units; + } + else if (typ.compare ("b0")) + { + ret (0) = 1029.0 * mm2units; + ret (1) = 1456.0 * mm2units; + } + else if (typ.compare ("b1")) + { + ret (0) = 728.0 * mm2units; + ret (1) = 1028.0 * mm2units; + } + else if (typ.compare ("b2")) + { + ret (0) = 514.0 * mm2units; + ret (1) = 728.0 * mm2units; + } + else if (typ.compare ("b3")) + { + ret (0) = 364.0 * mm2units; + ret (1) = 514.0 * mm2units; + } + else if (typ.compare ("b4")) + { + ret (0) = 257.0 * mm2units; + ret (1) = 364.0 * mm2units; + } + else if (typ.compare ("b5")) + { + ret (0) = 182.0 * mm2units; + ret (1) = 257.0 * mm2units; + } + else if (typ.compare ("arch-a")) + { + ret (0) = 9.0 * in2units; + ret (1) = 12.0 * in2units; + } + else if (typ.compare ("arch-b")) + { + ret (0) = 12.0 * in2units; + ret (1) = 18.0 * in2units; + } + else if (typ.compare ("arch-c")) + { + ret (0) = 18.0 * in2units; + ret (1) = 24.0 * in2units; + } + else if (typ.compare ("arch-d")) + { + ret (0) = 24.0 * in2units; + ret (1) = 36.0 * in2units; + } + else if (typ.compare ("arch-e")) + { + ret (0) = 36.0 * in2units; + ret (1) = 48.0 * in2units; + } + else if (typ.compare ("a")) + { + ret (0) = 8.5 * in2units; + ret (1) = 11.0 * in2units; + } + else if (typ.compare ("b")) + { + ret (0) = 11.0 * in2units; + ret (1) = 17.0 * in2units; + } + else if (typ.compare ("c")) + { + ret (0) = 17.0 * in2units; + ret (1) = 22.0 * in2units; + } + else if (typ.compare ("d")) + { + ret (0) = 22.0 * in2units; + ret (1) = 34.0 * in2units; + } + else if (typ.compare ("e")) + { + ret (0) = 34.0 * in2units; + ret (1) = 43.0 * in2units; + } + } + + return ret; +} + +void +figure::properties::update_paperunits (const caseless_str& old_paperunits) +{ + Matrix pos = get_paperposition ().matrix_value (); + Matrix sz = get_papersize ().matrix_value (); + + pos (0) = pos (0) / sz(0); + pos (1) = pos (1) / sz(1); + pos (2) = pos (2) / sz(0); + pos (3) = pos (3) / sz(1); + + caseless_str punits = get_paperunits (); + caseless_str typ = get_papertype (); + + if (typ.compare ("custom")) + { + if (old_paperunits.compare ("centimeters")) + { + sz (0) = sz (0) / 2.54; + sz (1) = sz (1) / 2.54; + } + else if (old_paperunits.compare ("points")) + { + sz (0) = sz (0) / 72.0; + sz (1) = sz (1) / 72.0; + } + + if (punits.compare ("centimeters")) + { + sz(0) = sz(0) * 2.54; + sz(1) = sz(1) * 2.54; + } + else if (old_paperunits.compare ("points")) + { + sz (0) = sz (0) * 72.0; + sz (1) = sz (1) * 72.0; + } + } + else + sz = papersize_from_type (punits, typ); + + pos (0) = pos (0) * sz(0); + pos (1) = pos (1) * sz(1); + pos (2) = pos (2) * sz(0); + pos (3) = pos (3) * sz(1); + + papersize.set (octave_value (sz)); + paperposition.set (octave_value (pos)); +} + +void +figure::properties::update_papertype (void) +{ + caseless_str typ = get_papertype (); + + if (! typ.compare ("custom")) + // Call papersize.set rather than set_papersize to avoid loops between + // update_papersize and update_papertype + papersize.set (octave_value (papersize_from_type (get_paperunits (), typ))); +} + +void +figure::properties::update_papersize (void) +{ + papertype.set ("custom"); +} + +void +figure::properties::set_units (const octave_value& v) +{ + if (! error_state) + { + caseless_str old_units = get_units (); + if (units.set (v, true)) + { + update_units (old_units); + mark_modified (); + } + } +} + +void +figure::properties::update_units (const caseless_str& old_units) +{ + set_position (convert_position (get_position ().matrix_value (), old_units, + get_units (), screen_size_pixels ())); +} + std::string figure::properties::get_title (void) const { @@ -3673,6 +3976,74 @@ return pos; } +void +axes::properties::set_units (const octave_value& v) +{ + if (! error_state) + { + caseless_str old_units = get_units (); + if (units.set (v, true)) + { + update_units (old_units); + mark_modified (); + } + } +} + +void +axes::properties::update_units (const caseless_str& old_units) +{ + graphics_object obj = gh_manager::get_object (get_parent ()); + Matrix parent_bb = obj.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2); + caseless_str new_units = get_units (); + set_position (octave_value (convert_position (get_position().matrix_value(), old_units, new_units, parent_bb))); + set_outerposition (octave_value (convert_position (get_outerposition().matrix_value(), old_units, new_units, parent_bb))); + set_tightinset (octave_value (convert_position (get_tightinset().matrix_value(), old_units, new_units, parent_bb))); +} + +void +axes::properties::set_fontunits (const octave_value& v) +{ + if (! error_state) + { + caseless_str old_fontunits = get_fontunits (); + if (fontunits.set (v, true)) + { + update_fontunits (old_fontunits); + mark_modified (); + } + } +} + +void +axes::properties::update_fontunits (const caseless_str& old_units) +{ + caseless_str new_units = get_fontunits (); + double fsz = get_fontsize (); + double pixelsperinch = xget (0, "screenpixelsperinch").double_value(); + double parent_height = get_boundingbox (true).elem (3); + + if (old_units.compare ("normalized")) + fsz = fsz * parent_height * 72 / pixelsperinch; + else if (old_units.compare ("pixels")) + fsz = fsz * 72 / pixelsperinch; + else if (old_units.compare ("inches")) + fsz = fsz * 72; + else if (old_units.compare ("centimeters")) + fsz = fsz * 72 / 2.54; + + if (new_units.compare ("normalized")) + fsz = fsz * pixelsperinch / parent_height / 72; + else if (new_units.compare ("pixels")) + fsz = fsz * pixelsperinch / 72; + else if (new_units.compare ("inches")) + fsz = fsz / 72; + else if (new_units.compare ("centimeters")) + fsz = fsz * 2.54 / 72; + + set_fontsize (octave_value (fsz)); +} + ColumnVector graphics_xform::xform_vector (double x, double y, double z) { diff -r f1c4527b4024 -r 6ea65c5de87a src/graphics.h.in --- a/src/graphics.h.in Thu Sep 16 14:07:21 2010 -0400 +++ b/src/graphics.h.in Thu Sep 16 23:13:22 2010 +0200 @@ -2639,6 +2639,10 @@ void set_boundingbox (const Matrix& bb); + void update_units (const caseless_str& old_units); + + void update_paperunits (const caseless_str& old_paperunits); + std::string get_title (void) const; // See the genprops.awk script for an explanation of the @@ -2668,11 +2672,11 @@ double_property mincolormap , 64 string_property name , "" bool_property numbertitle , "on" - radio_property paperunits , "{inches}|centimeters|normalized|points" + radio_property paperunits Su , "{inches}|centimeters|normalized|points" array_property paperposition , default_figure_paperposition () radio_property paperpositionmode , "auto|{manual}" - array_property papersize , default_figure_papersize () - radio_property papertype , "{usletter}|uslegal|a0|a1|a2|a3|a4|a5|b0|b1|b2|b3|b4|b5|arch-a|arch-b|arch-c|arch-d|arch-e|a|b|c|d|e|tabloid|" + array_property papersize U , default_figure_papersize () + radio_property papertype SU , "{usletter}|uslegal|a0|a1|a2|a3|a4|a5|b0|b1|b2|b3|b4|b5|arch-a|arch-b|arch-c|arch-d|arch-e|a|b|c|d|e|tabloid|" radio_property pointer , "crosshair|fullcrosshair|{arrow}|ibeam|watch|topl|topr|botl|botr|left|top|right|bottom|circle|cross|fleur|custom|hand" array_property pointershapecdata , Matrix (16, 16, 0) array_property pointershapehotspot , Matrix (1, 2, 0) @@ -2683,7 +2687,7 @@ callback_property resizefcn , Matrix () radio_property selectiontype , "{normal}|open|alt|extend" radio_property toolbar , "none|{auto}|figure" - radio_property units , "inches|centimeters|normalized|points|{pixels}|characters" + radio_property units Su , "inches|centimeters|normalized|points|{pixels}|characters" callback_property windowbuttondownfcn , Matrix () callback_property windowbuttonmotionfcn , Matrix () callback_property windowbuttonupfcn , Matrix () @@ -2922,6 +2926,10 @@ void unzoom (void); void clear_zoom_stack (void); + void update_units (const caseless_str& old_units); + + void update_fontunits (const caseless_str& old_fontunits); + private: scaler sx, sy, sz; Matrix x_render, x_render_inv; @@ -3018,7 +3026,7 @@ radio_property fontangle , "{normal}|italic|oblique" string_property fontname , OCTAVE_DEFAULT_FONTNAME double_property fontsize , 12 - radio_property fontunits , "{points}|normalized|inches|centimeters|pixels" + radio_property fontunits SU , "{points}|normalized|inches|centimeters|pixels" radio_property fontweight , "{normal}|light|demi|bold" radio_property gridlinestyle , "-|--|{:}|-.|none" string_array_property linestyleorder , "-" @@ -3032,7 +3040,7 @@ array_property ticklength , default_axes_ticklength () array_property tightinset r , Matrix (1, 4, 0.0) // FIXME -- uicontextmenu should be moved here. - radio_property units , "{normalized}|inches|centimeters|points|pixels|characters" + radio_property units SU , "{normalized}|inches|centimeters|points|pixels|characters" // hidden properties for transformation computation array_property x_viewtransform h , Matrix (4, 4, 0.0) array_property x_projectiontransform h , Matrix (4, 4, 0.0)