function printpreview(varargin)
%PRINTPREVIEW  Display preview of figure to be printed
%    PRINTPREVIEW(fig), where fig is a figure handle,
%    displays a dialog with a 1/4 size thumbnail or a
%    full size image of the figure as it will be printed.
%
%    Print...       closes the Print Preview and opens the
%                   Print dialog.
%    Page Setup...  opens the Page Setup dialog.
%    Zoom In        displays a full size image of the page.
%    Zoom Out       displays a 1/4 scaled image of the page.
%


%   Copyright 1984-2000 The MathWorks, Inc. 
%   $Revision: 1.22 $  $Date: 2000/06/02 04:41:58 $


switch nargin
case {0 1}
   % take a snapshot of the page
   if nargin==1
      fig = varargin{1};
      if isempty(fig) | ~ishandle(fig)
         error('Invalid Figure handle.');
      end
   else
      fig = gcf;
   end

   oldPtr = get(fig,'Pointer');
   try
      ppwindows = findobj(allchild(0),'flat',...
              'Tag','TMWFigurePrintPreview',...
              'Type','Figure');
      fFound = 0;
      for p = ppwindows'
         d = getappdata(p,'PrintPreviewData');
         if ~isempty(d) & ishandle(d.fig) & d.fig==fig
            refresh(p);
            figure(p);
            fFound = 1;
         end
      end
      if ~fFound
         set(fig,'Pointer','watch');         
         LInitDlg(fig);
         set(fig,'Pointer',oldPtr);
      end
   catch
      errordlg(lasterr);
      set(fig,'Pointer',oldPtr);      
   end
case 2  % setlim, print, pagesetup, print, resize
   feval(varargin{1},varargin{2});
   return
end

function update(fig)
try 
   fNoUIC = isempty(findall(fig,'Type','uicontrol','Visible','on'));
   ppwindows = findobj(allchild(0),'Tag','TMWFigurePrintPreview');
   pagesetupwindow = findobj(allchild(0),'Tag','Page Dialog');
   for p = ppwindows'
      d = getappdata(p,'PrintPreviewData');
      if ~isempty(d) & ishandle(d.fig) & d.fig==fig
         if fNoUIC
            refresh(p);
            figure(p);
         else
            saveProp = get(fig,{'Pointer' 'Resize'});
            set(fig,'Pointer','watch','Resize','off');
            set([p; pagesetupwindow],...
                    'WindowStyle','normal');

            % bring figure forward to take a snapshot
            figure(fig);
            refresh(p);
            
            % bring the page setup window back to the front
            figure(p);
            figure(pagesetupwindow);         
            set([p; pagesetupwindow],...
                    'WindowStyle','modal');
            set(fig,{'Pointer' 'Resize'},saveProp);
         end
      end
   end
catch
   %lasterr
end
   
function refresh(dlg)
d = getappdata(dlg,'PrintPreviewData');
if ishandle(d.fig)
   set(dlg,'Pointer','watch');
   % units must precede position!
   paperProps = {...
              'PaperUnits' ...
              'PaperPosition' ...
              'PaperOrientation' ...
              'PaperType'};
   set(dlg,paperProps, get(d.fig, paperProps));
   % work in inches
   set(dlg,'PaperUnits','inches');
   
   % [izoomdata, ifulldata] = rerender(d.fig);
   set(dlg,'Pointer','arrow');
   zoomScale = get(getobj(d.ax),'ZoomScale');

   if isempty(findall(d.fig,'Type','uicontrol','Visible','on'))
      % no uicontrols: only render on demand
      if zoomScale < 0.5
         ifulldata = rerender(d.fig,0.25);
         izoomdata = [];
      else
         ifulldata = [];
         izoomdata = rerender(d.fig,1);
      end
   else
      ifulldata = rerender(d.fig,0.25);
      izoomdata = rerender(d.fig,1);      
   end
   
   if zoomScale < 0.5
      zoomvis = 'off';
      fullvis = 'on';
   else
      zoomvis = 'on';
      fullvis = 'off';
   end

   set([d.izoomHG d.ifullHG],...
           {'Visible' 'CData'},...
           { zoomvis  izoomdata; ...
             fullvis  ifulldata});
   % draw the page image
   [xFullPage, yFullPage] = LSetPagePatch(dlg);
   set([d.fullPagePatch d.fullPageEdge],...
           'XData',xFullPage,'YData',yFullPage);
   % set the axis limits to display things at the right scale
   LSetPaper(dlg, get(d.panx,'Value'), get(d.pany,'Value'));
   % set([d.izoomHG d.ifullHG],...
   %         {'Visible'},...
   %         { zoomvis ; ...
   %           fullvis });
   % set([d.izoomHG d.ifullHG],...
   %         { 'CData'},...
   %         { izoomdata; ...
   %           ifulldata});
% else
   % invalid figure handle
end

function LInitDlg(fig)

f = figure('Name','Print Preview',...
        'IntegerHandle','off',...
        'Tag','TMWFigurePrintPreview',...
        'DoubleBuffer','on',...
        'Renderer','painters',...
        'DeleteFcn','',...
        'MenuBar','none',...
        'ToolBar','none',...        
        'WindowStyle','modal',...
        'Units','pixels',...
        'Resize','on',...
        'Visible','off',...
        'NumberTitle','off');

try

DlgName = ['Print Preview - ' LGetFigName(fig)];
set(f,'Name',DlgName);

foh = scribehandle(figobj(f));
foh.DragObjects.ResetParent = 0;

figPos = get(f,'Position');

buttonProps = {
   'Print...'  'printpreview(''print'',gcbf)' ;
   'Page Setup...'  'printpreview(''pagesetup'',gcbf)' ;
   'Zoom In'  'printpreview setlim zoom' ;
   'Zoom Out'  'printpreview setlim unzoom' ;   
   'Close'  'close(gcbf)' ;   
   };
for i=1:size(buttonProps,1)
   
   buttons(i) = uicontrol(...
           'Parent',f,...
           'String',buttonProps{i,1},...
           'Callback',buttonProps{i,2});
end

zoom = buttons(3);
unzoom = buttons(4);
set(unzoom,'Enable','off');

scrPix = get(0,'ScreenPixelsPerInch');
scrollW = 12 * scrPix/72;
border = 2;

extent = get(buttons(2),'Extent');
buttonW = max(73.3,extent(3)+6);
buttonH = max(24,extent(4)+4);
headerH = buttonH + 3*border;


% need to set the axis position explicitly the first time so
% that the limits and page patch are set correctly
axPos =  [ border ...
           border+scrollW ...
           figPos(3)-scrollW-border ...
           figPos(4)-scrollW-border-headerH];

a = axes(...
        'Units', 'pixels',...
        'Parent',f,...
        'Position', axPos,...
        'Box','on',...
        'XTick',[],...
        'YTick',[],...
        'XLimMode','manual',...
        'YLimMode','manual',...
        'Layer','bottom',...
        'Color',[.7 .7 .7],...
        'NextPlot','add',...
        'ButtonDownFcn','',...
        'Tag','PageViewAxes');  % this needs to change...


ah = scribehandle(axisobj(a));
% start off full page view...
zoomScale = 1/4;
set(ah,'ZoomScale',zoomScale);

axPos = get(a,'Position');

% zoom = uicontrol('Parent',f, ...
%         'Callback','printpreview setlim zoom', ...
%         'FontSize',14,...        
%         'String','Zoom In', ...
%         'Tag','zoom');
% unzoom = uicontrol('Parent',f, ...
%         'Callback','printpreview setlim unzoom', ...
%         'FontSize',14,...        
%         'String','Zoom Out', ...
%         'Tag','unzoom');

panx = uicontrol('Parent',f, ...
        'Callback','printpreview setlim panx', ...
        'Style','slider', ...
        'Tag','panx', ...
        'Value',0.5);
pany = uicontrol('Parent',f, ...
        'Callback','printpreview setlim pany', ...
        'Style','slider', ...
        'Tag','pany', ...
        'Value',0.5);

% refresh() sets the xdata and ydata of this patch appropriately
fullPagePatch = patch([0 1],[0 1],'w',...
           'Tag','FullPagePatch',...
           'LineWidth',0.5,...
           'EdgeColor',[0 0 0],...
           'EraseMode','normal',...
           'Parent',a);

% the print image is rendered in data space in [0 0 1 1]
izoomHG = image([0 1],[0 1],ones(2,2,3),...
                   'EraseMode','normal',...
                   'Parent',a);
ifullHG = image([0 1],[0 1],ones(2,2,3),...
                   'EraseMode','normal',...
                   'Parent',a,...
                   'Visible','off');

% add a line to mark the edge of the paper in case the figure
% image runs over
fullPageEdge = line(...
           [0 0 1 1 0],[0 1 1 0 0],...
           'LineWidth',0.5,...
           'LineStyle',':',...
           'EraseMode','normal',...
           'Color',[0 0 0],...
           'Parent',a);

d = struct(...
        'dlg',f,...
        'fig',fig,...
        'ax',a,...
        'zoom',zoom,...
        'border',border,...
        'scrollW',scrollW,...
        'headerH',headerH,...
        'buttonH',buttonH,...
        'buttonW',buttonW,...        
        'unzoom',unzoom,...        
        'buttons',buttons,...
        'panx',panx,...
        'pany',pany,...
        'fullPagePatch',fullPagePatch,...
        'fullPageEdge',fullPageEdge,...        
        'izoomHG',izoomHG,...
        'ifullHG',ifullHG);
setappdata(f,'PrintPreviewData',d);

refresh(f);

resize(f);

set(f,  'ResizeFcn','printpreview(''resize'',gcbf)',...
        'HandleVisibility','callback',...
        'Visible','on');
catch
   lasterr
   if ishandle(f)
      delete(f)
   end
end
      

function LSetPaper(fig,x,y)
% x,y are the current values of the x and y sliders...
ax = findall(fig,'Type','axes','Tag','PageViewAxes');

% get current axis position
[axisW, axisH] = LGetAxisSize(ax);

% set zoom scale
axObj = getobj(ax);
if isempty(axObj)
   return
end
zoomScale = get(axObj,'ZoomScale');

% set axis limits
[scaledPaperW, scaledPaperH] = LGetScaledPaperSize(zoomScale, fig);

oldUnits = get(fig,'PaperUnits');
set(fig,'PaperUnits','normal');
normalPrintArea = get(fig,'PaperPosition');
set(fig,'PaperUnits',oldUnits);

% get the dimensions of the paper image in data space
printAreaDataW = 1/normalPrintArea(3);
printAreaDataH = 1/normalPrintArea(4);

xLimRange = printAreaDataW * axisW/scaledPaperW;
yLimRange = printAreaDataH * axisH/scaledPaperH;

% center on the paper patch
[L B R T] = LNormPos2XY(normalPrintArea);
xMid = x;
yMid = y;

xlim = [xMid xMid] + [-xLimRange/2  xLimRange/2];
ylim = [yMid yMid] + [-yLimRange/2  yLimRange/2];
set(ax,'XLim',xlim,'YLim',ylim);


function [x,y] = LGetAxisSize(ax)
oldUnits = get(ax,'Units');
set(ax,'Units','points');
pos = get(ax,'Position');
x = pos(3);
y = pos(4);
set(ax,'Units',oldUnits);


function [x,y] = LGetScaledPaperSize(zoomScale, fig)

oldUnits = get(fig,'PaperUnits');
set(fig,'PaperUnits','points');
psize = get(fig,'PaperSize') * zoomScale;
x = psize(1);
y = psize(2);
set(fig,'PaperUnits',oldUnits);


function [xFullPage, yFullPage] = LSetPagePatch(f);

oldUnits = get(f,'PaperUnits');
set(f,'PaperUnits','normal');
normPaperPosition = get(f,'PaperPosition');
set(f,'PaperUnits',oldUnits);

[pageL, pageB, pageR, pageT] =  LNormPos2XY(normPaperPosition);

xFullPage = [pageL pageL pageR pageR pageL];
yFullPage = [pageB pageT pageT pageB pageB];


function [dL, dB, dR, dT] = LNormPos2XY(pos)
L = pos(1);
W = pos(3);
B = pos(2);
H = pos(4);

dL = 0 - L/W;
dR = 1 + (1-(L+W))/W;

dB = 0 - B/H;
dT = 1 + (1-(B+H))/H;


function pos = LXY2NormPos(dL, dB, dR, dT)

L = dL;
W = dR-dL;
B = dB;
H = dT-dB;
pos = [L B W H];




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LSetlim

function setlim(action)
% setlim
%   scroll and zoom
dlg = gcbf;

d = getappdata(dlg,'PrintPreviewData');
uictrl = gcbo;
ifull = d.ifullHG;
izoom = d.izoomHG;

a = d.ax;
axObj = getobj(d.ax);

switch action
case 'panx'
   xlim = get(a,'XLim');
   val = get(uictrl,'Value');
   xhalfrange = (xlim(2)-xlim(1))/2;   
   set(a,'XLim',[val-xhalfrange val+xhalfrange]);

case 'pany'
   ylim = get(a,'YLim');   
   val = get(uictrl,'Value');
   yhalfrange = (ylim(2)-ylim(1))/2;      
   set(a,'YLim',[val-yhalfrange val+yhalfrange]);

case 'unzoom'
   set(dlg,'Pointer','watch');
   xlim = get(a,'XLim');
   xmid = mean(xlim);
   xrange = xlim(2)-xlim(1);
   ylim = get(a,'YLim');
   ymid = mean(ylim);
   yrange = ylim(2)-ylim(1);
   
   oldZoomScale = get(axObj,'ZoomScale');
   if oldZoomScale < 1/2, return, end;
   
   zoomScale = 1/4;

   set(a,'XLim', [xmid-xrange*2 xmid+xrange*2],...
   'YLim', [ymid-yrange*2 ymid+yrange*2]);

   set([ifull izoom],{'Visible'},{'on'; 'off'});
   set([d.unzoom d.zoom],{'Enable'},{'off'; 'on'});
   if isempty(get(ifull,'CData'))
      set(ifull,'CData', rerender(d.fig,0.25));
   end
   set(axObj,'ZoomScale', zoomScale);

case 'zoom'
   set(dlg,'Pointer','watch');
   xlim = get(a,'XLim');
   ylim = get(a,'YLim');

   xmid = mean(xlim);
   ymid = mean(ylim);      
   
   oldZoomScale = get(axObj,'ZoomScale');
   if oldZoomScale > .5, return, end
   
   zoomScale = 1;

   xQuarterRange = (xlim(2)-xlim(1))/8;
   yQuarterRange = (ylim(2)-ylim(1))/8;
   set(a,'XLim', [xmid-xQuarterRange xmid+xQuarterRange],...
   'YLim', [ymid-yQuarterRange ymid+yQuarterRange]);

   set([ifull izoom],{'Visible'},{'off'; 'on'});
   set([d.unzoom d.zoom],{'Enable'},{'on'; 'off'});
   if isempty(get(izoom,'CData'))
      set(izoom,'CData', rerender(d.fig,1));
   end
   set(axObj,'ZoomScale', zoomScale);

end
set(dlg,'Pointer','arrow');

function print(dlg)
d = getappdata(dlg,'PrintPreviewData');
if ishandle(d.fig)
   try
      close(dlg);
      printdlg(d.fig);
   catch
   end
else
   errordlg('The figure to be printed is no longer open.');
end

function pagesetup(dlg)
d = getappdata(dlg,'PrintPreviewData');
if ishandle(d.fig)
   try
      set(dlg,'Pointer','watch');
      pagesetupdlg(d.fig);
      refresh(dlg);
      set(dlg,'Pointer','arrow');      
   catch
   end
else
   errordlg('The figure to be printed is no longer open.');
end


function resize(dlg)

d = getappdata(dlg,'PrintPreviewData');

oldAxPos = get(d.ax,'Position');
oldAxXLim = get(d.ax,'XLim');
oldAxYLim = get(d.ax,'YLim');   
figPos = get(dlg,'Position');
newPos = oldAxPos;

border = d.border;
scrollW = d.scrollW;
headerH = d.headerH;

axPos =  [ border ...
           border+scrollW ...
           figPos(3)-scrollW-border ...
           figPos(4)-scrollW-border-headerH];

% enforce minimum height
if axPos(4)<10 | axPos(3)<20
   return
end

btnPos = [border axPos(2)+axPos(4)+border d.buttonW d.buttonH];
nBtns = length(d.buttons);
btnPosV = ones(length(d.buttons),1)*btnPos;
% distribute
btnPosV(:,1) = btnPosV(:,1) + (d.buttonW+border)*[0:nBtns-1]';
btnPosV = num2cell(btnPosV,2);

set([d.ax d.panx d.pany d.zoom d.unzoom d.buttons],{'Position'},...
        {  axPos ...
           [border border axPos(3) scrollW] ...
           [axPos(1)+axPos(3) border+scrollW scrollW axPos(4)]...
           [border border scrollW scrollW]...
           [border+scrollW border scrollW scrollW]...
           btnPosV{:}}');

oldAxXRange = oldAxXLim(2)-oldAxXLim(1);
newAxXLim = oldAxXLim(1) + [0  oldAxXRange*axPos(3)/oldAxPos(3)];
oldAxYRange = oldAxYLim(2)-oldAxYLim(1);
newAxYLim = oldAxYLim(2) - [oldAxYRange*axPos(4)/oldAxPos(4) 0];
set(d.ax,'XLim',newAxXLim,'YLim',newAxYLim);


function imap = rerender(fig,scale)
pj = printjob;
pj.DriverColor = defaultprtcolor;

warnMode = LSuppressBacktrace;

fRenderError = 0;
try
   pt = get(fig,'PrintTemplate');
   if isempty(pt)
      pj.DriverColorSet = 1;	% Use color from print job
   else
      pj.DriverColorSet = 0;	% Use color from print template
   end
   
   pj.DriverClass = 'IM';
   pj.Driver = '-dzbuffer';
   
   scrPix = get(0,'ScreenPixelsPerInch');
   scaledScreenRes = scrPix*scale;
   % check to see if we're about to generate a huge image
   % set threshold for full resolution preview just above full
   % page arch-B: 12x18 inches = 1990656 pixels
   % at typical windows resolution of 96 dpi.
   % at larger sizes, limit total image size to 2,000,000 pixels
   oldPaperUnits = get(fig,'PaperUnits');
   set(fig,'PaperUnits','inches');
   paperPos = get(fig,'PaperPosition');
   set(fig,'PaperUnits',oldPaperUnits);
   imageMatrixSize = prod(scaledScreenRes * paperPos(3:4));
   if imageMatrixSize > 2000000    % larger than full page arch-B
      % cut resolution to decrease rendering time
      if imageMatrixSize > 8000000 % larger than full page arch-D
         scaledScreenRes = scaledScreenRes/3;
      else
         scaledScreenRes = scaledScreenRes/2;
      end
      warning(['Print Preview is rendering this page on screen at a lower ' ...
                 'resolution to' sprintf('\n') 'conserve memory. ' ...
                 'The quality of the printed page will not be ' ...
                 'affected.']);
   end
   % just in case
   while imageMatrixSize > 2000000
      scaledScreenRes = scaledScreenRes/2;
      imageMatrixSize = prod(scaledScreenRes * paperPos(3:4));   
   end
   
   pj.DPI = ceil(scaledScreenRes);
   
   DPISwitch = ['-r' num2str(pj.DPI)];
   pj = printprepare(pj,fig);
   db = get(fig,'DoubleBuffer');
   set(fig,'DoubleBuffer','on');
   try
      imap = flipdim(hardcopy(fig,'-dzbuffer',DPISwitch),1);
   catch
      fRenderError = 1;
   end
   set(fig,'DoubleBuffer',db);   
   pj = printrestore(pj,fig);
catch
   fRenderError = 1;
end

warning(warnMode);
if fRenderError
   imap = [];
   f = errordlg(lasterr,'Error','modal');
   waitfor(f);
end

% case 3  % move or resize paper position (not used)
%    d = getappdata(gcbf,'PrintPreviewData');
%    set(gcbo,'WindowButtonMotionFcn','');
%    % rerender the figure
%    x = get(gco,'xdata');
%    y = get(gco,'ydata');
%    l = min(x);
%    r = max(x);
%    b = min(y);
%    t = max(y);
% 
%    [l r b t]
%    normpos = LXY2NormPos(l,b,r,t)
%    oldUnits = get(d.dlg,'PaperUnits');
%    originalPos = get(d.dlg,'PaperPosition');
% %   set(d.dlg,'PaperUnits','normalized');
%    oldW = originalPos(3);
%    oldH = originalPos(4);
%    figUnitPos = normpos.*[oldW oldH oldW oldH]
%    newPos = [originalPos(1)+figUnitPos(1)...
%               originalPos(2)+figUnitPos(2)...
%               figUnitPos(3)...
%               figUnitPos(4)]
%    set(d.dlg,'PaperPosition',newPos);
% %   set(d.dlg,'PaperUnits',oldUnits);
%    [izoomdata, ifulldata] = rerender(d.dlg);
% 
%    set(d.izoomHG,'cdata',izoomdata,'XData',x,'YData',y);
%    set(d.ifullHG,'cdata',ifulldata,'XData',x,'YData',y);
%    return

function FigName = LGetFigName(Fig)
FigName = get(Fig,'Name');
if strcmp(get(Fig,'NumberTitle'),'on') 
   if (length(FigName)>0)
      FigName = [': ' FigName];
   end
   if strcmp(get(Fig,'IntegerHandle'),'on'),
      FigName = ['Figure ' sprintf('%d',Fig) FigName];
   else,
      FigName = ['Figure ' sprintf('%.16g',Fig) FigName];
   end
end

if isempty(FigName)   % no name, number title off
   if strcmp(get(Fig,'IntegerHandle'),'on'),
      FigName = ['Figure ' sprintf('%d',Fig)];
   else,
      FigName = ['Figure ' sprintf('%.16f',Fig)];
   end
end


function warnMode = LSuppressBacktrace
warnMode = warning;
switch warnMode
case 'backtrace'
   warning on;
end
