Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
DoBetterWZoom.c
/* |
File: DoBetterWZoom.c |
Contains: The new functionality is really cool. I now pass in maximum bounds for the window and |
make all sorts of adjustments to ensure that the window is zoomed to a good size at a |
good place while minimizing unnecessary window motion. This implementation is slightly |
better than the one used by the Finder in View by Icon. |
Written by: |
Copyright: Copyright © 1984-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/6/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
void DoZoomWindow (WindowPtr theWindow, short zoomDir, short hMax, short vMax) |
{ |
extern EventRecord gTheEvent; // from the main event loop |
extern Boolean gHasColorQD; |
Rect *windRect, *zoomRect; |
Rect globalPortRect, theSect, dGDRect; |
GDHandle nthDevice, dominantGDevice; |
long sectArea, greatestArea; |
if (TrackBox(theWindow, gTheEvent.where, zoomDir)) { |
SetPort(theWindow); |
EraseRect(&theWindow->portRect); // recommended for cosmetic reasons |
if (zoomDir == inZoomOut) { |
/* |
* ZoomWindow() is a good basic tool, but it doesn't do everything necessary to |
* implement a good human interface when zooming. In fact it's not even close for |
* more high-end hardware configurations. We must help it along by calculating an |
* appropriate window size and location any time a window zooms out. |
*/ |
windRect = &(**((WindowPeek) theWindow)->strucRgn).rgnBBox; |
dominantGDevice = nil; |
if (gHasColorQD) { |
/* |
* Color QuickDraw implies the possibility of multiple monitors. This is where |
* zooming becomes more interesting. One should zoom onto the monitor containing |
* the greatest portion of the window. This requires walking the gDevice list. |
*/ |
nthDevice = GetDeviceList(); |
greatestArea = 0; |
while (nthDevice != nil) { |
if (TestDeviceAttribute(nthDevice, screenDevice)) { |
if (TestDeviceAttribute(nthDevice, screenActive)) { |
SectRect(windRect, &(**nthDevice).gdRect, &theSect); |
sectArea = (long) rectWidth(theSect) * (long) rectHeight(theSect); |
if (sectArea > greatestArea) { |
greatestArea = sectArea; // save the greatest intersection |
dominantGDevice = nthDevice; // and which device it belongs to |
} |
} |
} |
nthDevice = GetNextDevice(nthDevice); |
} |
} |
/* |
* At this point, we know the dimensions of the window we're zooming, and we know |
* what screen we're going to put it on. To be more specific, however, we need a |
* rectangle which defines the maximum dimensions of the resized window's contents. |
* This rectangle accounts for the thickness of the window frame, the menu bar, and |
* one or two pixels around the edges for cosmetic compatibility with ZoomWindow(). |
*/ |
if (dominantGDevice != nil) { |
dGDRect = (**dominantGDevice).gdRect; |
if (dominantGDevice == GetMainDevice()) // account for menu bar on main device |
dGDRect.top += GetMBarHeight(); |
} |
else { |
dGDRect = qd.screenBits.bounds; // if no gDevice, use default monitor |
dGDRect.top += GetMBarHeight(); |
} |
globalPortRect = theWindow->portRect; |
LocalToGlobal(&topLeft(globalPortRect)); // calculate the window's portRect |
LocalToGlobal(&botRight(globalPortRect)); // in global coordinates |
// account for the window frame and inset it a few pixels |
dGDRect.left += 2 + globalPortRect.left - windRect->left; |
dGDRect.top += 2 + globalPortRect.top - windRect->top; |
dGDRect.right -= 1 + windRect->right - globalPortRect.right; |
dGDRect.bottom -= 1 + windRect->bottom - globalPortRect.bottom; |
/* |
* Now we know exactly what our limits are, and since there are input parameters |
* specifying the dimensions we'd like to see, we can move and resize the zoom |
* state rectangle for the best possible results. We have three goals in this: |
* 1. Display the window entirely visible on a single device. |
* 2. Resize the window to best represent the dimensions of the document itself. |
* 3. Move the window as short a distance as possible to achieve #1 and #2. |
*/ |
zoomRect = &(**(WStateDataHandle) ((WindowPeek) theWindow)->dataHandle).stdState; |
/* |
* Initially set the zoom rectangle to the size requested by the input parameters, |
* although not smaller than a minimum size. We do this without moving the origin. |
*/ |
zoomRect->right = (zoomRect->left = globalPortRect.left) + |
max(hMax, MinWindowWidth(theWindow)); |
zoomRect->bottom = (zoomRect->top = globalPortRect.top) + |
max(vMax, MinWindowHeight(theWindow)); |
// Shift the entire rectangle if necessary to bring its origin inside dGDRect. |
OffsetRect(zoomRect, |
max(dGDRect.left - zoomRect->left, 0), |
max(dGDRect.top - zoomRect->top, 0)); |
/* |
* Shift the rectangle up and/or to the left if necessary to accomodate the view, |
* and if it is possible to do so. The rectangle may not be moved such that its |
* origin would fall outside of dGDRect. |
*/ |
OffsetRect(zoomRect, |
-pin(zoomRect->right - dGDRect.right, 0, zoomRect->left - dGDRect.left), |
-pin(zoomRect->bottom - dGDRect.bottom, 0, zoomRect->top - dGDRect.top)); |
// Clip expansion to dGDRect, in case view is larger than dGDRect. |
zoomRect->right = min(zoomRect->right, dGDRect.right); |
zoomRect->bottom = min(zoomRect->bottom, dGDRect.bottom); |
} |
ZoomWindow(theWindow, zoomDir, false); // all it needed was a brain transplant |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-30