function pdezoom(m)
%PDEZOOM PDEZOOM in and out on a 2-D plot.
%	Note: special version of PDEZOOM for the PDE Toolbox
%	preserves the WindowButtonMotion-callback.
%
%	PDEZOOM ON turns PDEZOOM on for the current figure.  Click
%	the left mouse button to PDEZOOM in on the point under the
%	mouse.	Click the right mouse button to PDEZOOM out
%	(shift-click on the Macintosh).	 Each time you click,
%	the axes limits will be changed by a factor of 2 (in or out).
%	You can also click and drag to PDEZOOM into an area.
%
%	PDEZOOM OFF turns PDEZOOM off. PDEZOOM with no arguments
%	toggles the PDEZOOM status.  PDEZOOM OUT returns the plot
%	to its initial (full) PDEZOOM.

%	ZOOM.M:Clay M. Thompson 1-25-93
%	Revised 11 Jan 94 by Steven L. Eddins
%	Copyright (c) 1984-94 by The MathWorks, Inc.
%	$Revision: 1.7.1.2 $  $Date: 1995/08/30 15:57:26 $
%	PDEZOOM add's: M Ringh 1994/07/26. MR 1994/11/22.
%	Copyright (c) 1994-95 by The MathWorks, Inc.
%	Note: pdezoom uses the userdata of the zlabel of the axis and
%	the figure buttondown functions

fig=gcf;
ax=findobj(get(fig,'Children'),'flat','Tag','PDEAxes');
if isempty(ax), error('PDE Toolbox axis not found'), end

if any(get(ax,'view')~=[0 90]), error('Only works for 2-D plots'); end

getlimits = 1; rbbox_mode = 0;
if nargin==0, % Toggle buttondown function
   if strcmp(get(fig,'windowbuttondownfcn'),'pdezoom(''down'')'),
      set(fig,'windowbuttondownfcn','','windowbuttonupfcn','');
   else
      set(fig,'windowbuttondownfcn','pdezoom(''down'')',...
	      'windowbuttonupfcn','1;','interruptible','yes');
      set(ax,'interruptible','yes')
%      figure(fig)
   end
   return

elseif nargin==1, % Process call backs
  if isstr(m),
    m = lower(m);
    if strcmp(m,'down'),
      % Activate axis that is clicked in
%      ax = get(fig,'Children');
% hack: the graphical radio buttons are implemented as 'mini-axes', thus turning
% PDEZOOM on will destroy the button group layout. Fix: don't pay attention to axes
% other than 'PDEAxes'.
      ZOOM_found = 0;
      for i=1:length(ax),
	if strcmp(get(ax(i),'Type'),'axes'),
	  ZOOM_Pt1 = get(ax(i),'CurrentPoint');
	  xlim = get(ax(i),'XLim');
	  ylim = get(ax(i),'YLim');
	  if (xlim(1) <= ZOOM_Pt1(1,1) & ZOOM_Pt1(1,1) <= xlim(2) & ...
	      ylim(1) <= ZOOM_Pt1(1,2) & ZOOM_Pt1(1,2) <= ylim(2))
	    ZOOM_found = 1;
	    axes(ax(i))
	    break
	  end
	end
      end

      if ZOOM_found==0, return, end

      % Check for selection type
      selection_type = get(fig,'SelectionType');
      if (strcmp(selection_type, 'normal'))
	% zoom in
	m = 1;
      elseif (strcmp(selection_type, 'open'))
	% zoom all the way out
	pdezoom('out');
	return;
      else
	% zoom partially out
	m = -1;
      end
      ZOOM_Pt1 = get(ax,'currentpoint');
      ZOOM_Pt2 = ZOOM_Pt1;
      center = ZOOM_Pt1(1,1:2);

      if (m == 1)
	% zoom in
	rbbox([get(fig,'currentpoint') 0 0],get(fig,'currentpoint'))
	ZOOM_Pt2 = get(ax,'currentpoint');

	% Note the currentpoint is set by having a non-trivial up function.
	if min(abs(ZOOM_Pt1(1,1:2)-ZOOM_Pt2(1,1:2))) >= ...
	      min(.01*[diff(get(ax,'xlim')) diff(get(ax,'ylim'))]),
	  % determine axis from rbbox
	  a = [ZOOM_Pt1(1,1:2);ZOOM_Pt2(1,1:2)]; a = [min(a);max(a)];
	  rbbox_mode = 1;
	end
      end
      limits = get(get(ax,'ZLabel'),'UserData');
      if all(size(limits)==[1 4]), % Do simple checking of userdata
	if all(limits([1 3])<limits([2 4])),
	  getlimits = 0;
	else
	  getlimits = -1; % Don't munge data
	end
      else
	if isempty(limits), getlimits = 1; else getlimits = -1; end
      end

    elseif strcmp(m,'on'),
      set(fig,'windowbuttondownfcn','pdezoom(''down'')', ...
	      'windowbuttonupfcn','1;','interruptible','yes');

      set(ax,'interruptible','yes')
      h=findobj(get(fig,'Children'),'flat','Tag','PDEFileMenu');
      flags=get(h,'UserData'); mode_flag=flags(2);
      if mode_flag~=3
        set(ax,'drawmode','normal'), drawnow discard
      end
      figure(fig)
      return

    elseif strcmp(m,'off'),
      set(fig,'windowbuttondownfcn','','windowbuttonupfcn','')
      h=findobj(get(fig,'Children'),'flat','Tag','PDEFileMenu');
      flags=get(h,'UserData'); mode_flag=flags(2);
      if mode_flag~=3
        set(ax,'drawmode','fast'), drawnow discard
      end
      return

    elseif strcmp(m,'out'),
      limits = get(get(ax,'ZLabel'),'UserData');
      if all(size(limits)==[1 4]), % Do simple checking of userdata
	if all(limits([1 3])<limits([2 4])),
	  getlimits = 0;
	else
	  getlimits = -1; % Don't munge data
	end
      else
	if isempty(limits), getlimits = 1; else getlimits = -1; end
      end

      center = [sum(get(ax,'Xlim'))/2 sum(get(ax,'Ylim'))/2];
      m = -inf; % ZOOM totally out
    else
      error(['Unknown option: ',m,'.']);
    end

  else
    error('Only takes the strings ''on'',''off'', or ''out''.')
  end
end

% Determine which IMAGE coordinate system is being used.
s = [version '	  ']; k = find(s<46 & s>58);
if ~isempty(k), s = s(1:min(k)); end
[ver,count,msg,next] = sscanf(s,'%f',1);
if ver > 4.1,
  useNew = 1;
elseif ver < 4.1,
  useNew = 0;
else
  if s(next)>='a', useNew = 1; else useNew = 0; end
end

if getlimits~=0,  % Get min and max info for axis children

  if isempty(get(get(ax,'ZLabel'),'userdata')),
    % Use quick method if possible
    xlim = get(ax,'xlim'); xmin = xlim(1); xmax = xlim(2);
    ylim = get(ax,'ylim'); ymin = ylim(1); ymax = ylim(2);

  else

    % Use slow method only if someone else is using the userdata
    h = get(ax,'Children');
    xmin = inf; xmax = -inf; ymin = inf; ymax = -inf;
    for i=1:length(h),
      t = get(h(i),'Type');
      if ~strcmp(t,'text'),
	if strcmp(t,'image') & useNew, % Determine axis limits for image
	  x = get(h(i),'Xdata'); y = get(h(i),'Ydata');
	  x = [min(min(x)) max(max(x))];
	  y = [min(min(y)) max(max(y))];
	  [ma,na] = size(get(h(i),'Cdata'));
	  if na>1, dx = diff(x)/(na-1); else dx = 1; end
	  if ma>1, dy = diff(y)/(ma-1); else dy = 1; end
	  x = x + [-dx dx]/2; y = y + [-dy dy]/2;
	else
	  x = get(h(i),'Xdata'); y = get(h(i),'Ydata');
	end
	xmin = min(xmin,min(min(x)));
	xmax = max(xmax,max(max(x)));
	ymin = min(ymin,min(min(y)));
	ymax = max(ymax,max(max(y)));
      end
    end

    % Use automatic limits if in use.
    if strcmp(get(ax,'xLimMode'),'auto'),
      xlim = get(ax,'xlim'); xmin = xlim(1); xmax = xlim(2);
    end
    if strcmp(get(ax,'yLimMode'),'auto'),
      ylim = get(ax,'ylim'); ymin = ylim(1); ymax = ylim(2);
    end
  end

  limits = [xmin xmax ymin ymax];
  if getlimits~=-1, % Don't munge existing userdata.
    set(get(ax,'ZLabel'),'UserData',limits); % Store limits in ZLabel userdata
  end
end

%
% Actual zoom operation
%
set(fig,'Currentaxes',ax)
if rbbox_mode,
  newlims=a(:)';
  axis(newlims)
else
  xmin = limits(1); xmax = limits(2); ymin = limits(3); ymax = limits(4);
  if m==(-inf),
    dx = xmax-xmin;
    dy = ymax-ymin;
  else
    dx = diff(get(ax,'Xlim'))*(2.^(-m-1)); dx = min(dx,xmax-xmin);
    dy = diff(get(ax,'Ylim'))*(2.^(-m-1)); dy = min(dy,ymax-ymin);
  end

  % Limit zoom.
  center = max(center,[xmin ymin] + [dx dy]);
  center = min(center,[xmax ymax] - [dx dy]);
  newlims=[max(xmin,center(1)-dx) min(xmax,center(1)+dx) ...
  max(ymin,center(2)-dy) min(ymax,center(2)+dy)];
  axis(newlims)
end
% Hack: prevent zoomed axes to cover btngroup axes:
btnaxes=[...
findobj(get(fig,'Children'),'flat','Type','axes','Tag','draw'),...
findobj(get(fig,'Children'),'flat','Type','axes','Tag','solve'),...
findobj(get(fig,'Children'),'flat','Type','axes','Tag','zoom')];
for i=1:length(btnaxes),
   set(fig,'CurrentAxes',btnaxes(i))
end
