Subversion Repositories filter_foundry

Rev

Rev 193 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 193 Rev 259
Line 1... Line -...
1
#include <Types.h>
-
 
2
#include <Menus.h>
1
#include <Types.h>
-
 
2
#include <Menus.h>
-
 
3
#include <Quickdraw.h>
-
 
4
#include <Windows.h>
-
 
5
 
-
 
6
struct ZoomData {
-
 
7
        GDHandle                screenWithLargestPartOfWindow;
-
 
8
        unsigned long   largestArea;
-
 
9
        Rect                    windowBounds;
-
 
10
};
-
 
11
typedef struct ZoomData ZoomData, *ZoomDataPtr;
-
 
12
 
-
 
13
typedef void (*CalcIdealDocumentSizeProcPtr)(WindowPtr theWindow, Rect *idealContentSize);
-
 
14
 
-
 
15
enum {
-
 
16
        kNudgeSlop      =       4,
-
 
17
        kIconSpace      =       64
-
 
18
};
-
 
19
 
-
 
20
void ZoomTheWindow(WindowPeek theWindow, short zoomState,
-
 
21
                                        CalcIdealDocumentSizeProcPtr calcRoutine);
-
 
22
pascal void CalcWindowAreaOnScreen(short depth, short deviceFlags, GDHandle targetDevice,
-
 
23
                                                                        long userData);
-
 
24
short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint,
-
 
25
                                                        short idealOnScreenStartPoint, short idealOnScreenEndPoint,
-
 
26
                                                        short screenEdge1, short screenEdge2);
-
 
27
 
-
 
28
static RgnHandle GetWindowContentRegion(WindowPeek theWindow);
-
 
29
static RgnHandle GetWindowStructureRegion(WindowPeek theWindow);
-
 
30
static void GetWindowPortRect(WindowPeek theWindow, Rect *portRect);
-
 
31
static void SetWindowStandardState(WindowPeek theWindow, const Rect *standardState);
-
 
32
static void GetWindowUserState(WindowPeek theWindow, Rect *userState);
-
 
33
 
-
 
34
 
-
 
35
void ZoomTheWindow(WindowPeek theWindow, short zoomState,
-
 
36
                                        CalcIdealDocumentSizeProcPtr calcRoutine)
-
 
37
{
-
 
38
        ZoomData        zoomData;
-
 
39
        Rect            newStandardRect;
-
 
40
        Rect            scratchRect;
-
 
41
        Rect            screenRect;
-
 
42
        Rect            portRect;
-
 
43
        Rect            contentRegionBoundingBox;
-
 
44
        Rect            structureRegionBoundingBox;
-
 
45
        Rect            deviceLoopRect;
-
 
46
        GrafPtr         currentPort;
-
 
47
        RgnHandle       scratchRegion;
-
 
48
        RgnHandle       contentRegion;
-
 
49
        RgnHandle       structureRegion;
-
 
50
        GDHandle        mainDevice;
-
 
51
        short           horizontalAmountOffScreen;
-
 
52
        short           verticalAmountOffScreen;
-
 
53
        short           windowFrameTopSize;
-
 
54
        short           windowFrameLeftSize;
-
 
55
        short           windowFrameRightSize;
-
 
56
        short           windowFrameBottomSize;
-
 
57
       
-
 
58
 
-
 
59
        GetPort(&currentPort);
-
 
60
        SetPort((WindowPtr) theWindow);
-
 
61
        contentRegion = GetWindowContentRegion(theWindow);
-
 
62
        structureRegion = GetWindowStructureRegion(theWindow);
-
 
63
        GetWindowPortRect(theWindow, &portRect);
-
 
64
        contentRegionBoundingBox = (**contentRegion).rgnBBox;
-
 
65
        structureRegionBoundingBox = (**structureRegion).rgnBBox;
-
 
66
       
-
 
67
        // Determine the size of the window frame
-
 
68
        windowFrameTopSize = contentRegionBoundingBox.top -
-
 
69
                                                                        structureRegionBoundingBox.top;
-
 
70
        windowFrameLeftSize = contentRegionBoundingBox.left -
-
 
71
                                                                        structureRegionBoundingBox.left;
-
 
72
        windowFrameRightSize = structureRegionBoundingBox.right -
-
 
73
                                                                        contentRegionBoundingBox.right;
-
 
74
        windowFrameBottomSize = structureRegionBoundingBox.bottom -
-
 
75
                                                                        contentRegionBoundingBox.bottom;
-
 
76
                                                                       
-
 
77
        // If the window is being zoomed into the standard state, calculate the best size
-
 
78
        // to display the windowÕs information.
-
 
79
        mainDevice = GetMainDevice();
-
 
80
        if (zoomState == inZoomOut) {
-
 
81
                zoomData.screenWithLargestPartOfWindow = mainDevice;
-
 
82
                zoomData.largestArea = 0;
-
 
83
       
-
 
84
                // Usually, we would use the content regionÕs bounding box to determine the monitor
-
 
85
                // with largest portion of the windowÕs area. However, if the entire content region
-
 
86
                // of the window is not on any screen, the structure region should be used instead.
-
 
87
                scratchRegion = NewRgn();
-
 
88
                SectRgn(GetGrayRgn(), contentRegion, scratchRegion);
-
 
89
                if (EmptyRgn(scratchRegion))
-
 
90
                        zoomData.windowBounds = structureRegionBoundingBox;
-
 
91
                else
-
 
92
                        zoomData.windowBounds = contentRegionBoundingBox;
-
 
93
       
-
 
94
                // Use DeviceLoop to walk through all the active screens to find the one with the
-
 
95
                // largest portion of the zoomed window
-
 
96
                deviceLoopRect = zoomData.windowBounds;
-
 
97
                GlobalToLocal((Point *)&deviceLoopRect);
-
 
98
                GlobalToLocal((Point *)&deviceLoopRect.bottom);
-
 
99
                RectRgn(scratchRegion, &deviceLoopRect);
-
 
100
                DeviceLoop(scratchRegion, &CalcWindowAreaOnScreen, (long) &zoomData,
-
 
101
                                        (DeviceLoopFlags) singleDevices);
-
 
102
                DisposeRgn(scratchRegion);
-
 
103
                screenRect = (**(zoomData.screenWithLargestPartOfWindow)).gdRect;
-
 
104
               
-
 
105
                // If the monitor being zoomed to is the main monitor, change the top of the
-
 
106
                // useable screen area to avoid putting the title bar underneath the menubar.
-
 
107
                if (zoomData.screenWithLargestPartOfWindow == mainDevice)
-
 
108
                        screenRect.top += GetMBarHeight();
-
 
109
                       
-
 
110
                // Go figure out the perfect size for the window as if we had an infinitely large
-
 
111
                // screen
-
 
112
                (*calcRoutine)((WindowPtr) theWindow, &newStandardRect);
-
 
113
               
-
 
114
                // Anchor the new rectangle at the windowÕs current top left corner
-
 
115
                OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top);
-
 
116
                OffsetRect(&newStandardRect, contentRegionBoundingBox.left,
-
 
117
                                        contentRegionBoundingBox.top);
-
 
118
               
-
 
119
                // newStandardRect is the ideal size for the content area. The window frame
-
 
120
                // needs to be accounted for when we see if the window needs to be moved,
-
 
121
                // or resized, so add in the dimensions of the window frame.
-
 
122
                newStandardRect.top -= windowFrameTopSize;
-
 
123
                newStandardRect.left -= windowFrameLeftSize;
-
 
124
                newStandardRect.right += windowFrameRightSize;
-
 
125
                newStandardRect.bottom += windowFrameBottomSize;
-
 
126
               
-
 
127
                // If the new rectangle falls off the edge of the screen, nudge it so that itÕs just
-
 
128
                // on the screen. CalculateOffsetAmount determines how much of the window is offscreen.
-
 
129
                SectRect(&newStandardRect, &screenRect, &scratchRect);
-
 
130
                if (!EqualRect(&newStandardRect, &scratchRect)) {
-
 
131
                        horizontalAmountOffScreen = CalculateOffsetAmount(newStandardRect.left,
-
 
132
                                                                                                                           newStandardRect.right,
-
 
133
                                                                                                                           scratchRect.left,
-
 
134
                                                                                                                           scratchRect.right,
-
 
135
                                                                                                                           screenRect.left,
-
 
136
                                                                                                                           screenRect.right);
-
 
137
                        verticalAmountOffScreen = CalculateOffsetAmount(newStandardRect.top,
-
 
138
                                                                                                                        newStandardRect.bottom,
-
 
139
                                                                                                                        scratchRect.top,
-
 
140
                                                                                                                        scratchRect.bottom,
-
 
141
                                                                                                                        screenRect.top,
-
 
142
                                                                                                                        screenRect.bottom);
-
 
143
                        OffsetRect(&newStandardRect, horizontalAmountOffScreen,
-
 
144
                                                verticalAmountOffScreen);
-
 
145
                }
-
 
146
       
-
 
147
                // If weÕre still falling off the edge of the screen, that means that the perfect
-
 
148
                // size is larger than the screen, so we need to shrink down the standard size
-
 
149
                SectRect(&newStandardRect, &screenRect, &scratchRect);
-
 
150
                if (!EqualRect(&newStandardRect, &scratchRect)) {
-
 
151
 
-
 
152
                // First shrink the width of the window. If the window is wider than the screen
-
 
153
                // it is zooming to, we can just pin the standard rectangle to the edges of the
-
 
154
                // screen, leaving some slop. If the window is narrower than the screen, we know
-
 
155
                // we just nudged it into position, so nothing needs to be done.
-
 
156
                        if ((newStandardRect.right - newStandardRect.left) >
-
 
157
                                (screenRect.right - screenRect.left)) {
-
 
158
                                newStandardRect.left = screenRect.left + kNudgeSlop;
-
 
159
                                newStandardRect.right = screenRect.right - kNudgeSlop;
-
 
160
 
-
 
161
                                if ((zoomData.screenWithLargestPartOfWindow == mainDevice) &&
-
 
162
                                        (newStandardRect.right > (screenRect.right - kIconSpace)))
-
 
163
                                        newStandardRect.right = screenRect.right - kIconSpace;
-
 
164
                        }
-
 
165
 
-
 
166
                        // Move in the top. Like the width of the window, nothing needs to be done unless
-
 
167
                        // the window is taller than the height of the screen.
-
 
168
                        if ((newStandardRect.bottom - newStandardRect.top) >
-
 
169
                                (screenRect.bottom - screenRect.top)) {
-
 
170
                                newStandardRect.top = screenRect.top + kNudgeSlop;
-
 
171
                                newStandardRect.bottom = screenRect.bottom - kNudgeSlop;
-
 
172
                        }
-
 
173
                }
-
 
174
 
-
 
175
                // WeÕve got the best possible window position. Remove the
-
 
176
                // frame, slam it into the WStateData record and let ZoomWindow
-
 
177
                // take care of the rest.
-
 
178
                newStandardRect.top += windowFrameTopSize;
-
 
179
                newStandardRect.left += windowFrameLeftSize;
-
 
180
                newStandardRect.right -= windowFrameRightSize;
-
 
181
                newStandardRect.bottom -= windowFrameBottomSize;
-
 
182
                SetWindowStandardState(theWindow, &newStandardRect);
-
 
183
        }
-
 
184
        else
-
 
185
                GetWindowUserState(theWindow, &newStandardRect);
-
 
186
               
-
 
187
        // If the window is still anchored at the current location, then just resize it
-
 
188
        if ((newStandardRect.left == contentRegionBoundingBox.left) &&
-
 
189
                (newStandardRect.top == contentRegionBoundingBox.top)) {
-
 
190
                OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top);
-
 
191
                SizeWindow((WindowPtr) theWindow, newStandardRect.right, newStandardRect.bottom,
-
 
192
                                        true);
-
 
193
        }
-
 
194
        else {
-
 
195
                scratchRegion = NewRgn();
-
 
196
                GetClip(scratchRegion);
-
 
197
                ClipRect(&portRect);
-
 
198
                EraseRect(&portRect);
-
 
199
                ZoomWindow((WindowPtr) theWindow, zoomState, false);
-
 
200
                SetClip(scratchRegion);
-
 
201
                DisposeRgn(scratchRegion);
-
 
202
        }
-
 
203
       
-
 
204
        SetPort(currentPort);
-
 
205
}
-
 
206
 
-
 
207
pascal void     CalcWindowAreaOnScreen(short depth, short deviceFlags, GDHandle targetDevice, long userData)
-
 
208
{
-
 
209
#pragma unused (depth, deviceFlags)
-
 
210
        ZoomDataPtr     zoomData = (ZoomDataPtr) userData;
-
 
211
        long            windowAreaOnScreen;
-
 
212
        Rect            windowPortionOnScreen;
-
 
213
       
-
 
214
        // Find the rectangle that encloses the intersection of the window and this screen.
-
 
215
        SectRect(&(zoomData->windowBounds), &((**targetDevice).gdRect), &windowPortionOnScreen);
-
 
216
       
-
 
217
        // Offset the rectangle so that itÕs right and bottom are also itÕs width and height.
-
 
218
        OffsetRect(&windowPortionOnScreen, -windowPortionOnScreen.left, -windowPortionOnScreen.top);
-
 
219
       
-
 
220
        // Calculate the area of the portion of the window thatÕs on this screen.
-
 
221
        windowAreaOnScreen = (long) windowPortionOnScreen.right * (long) windowPortionOnScreen.bottom;
-
 
222
       
-
 
223
        // If this is the largest portion of the window that has been encountered so far,
-
 
224
        // remember this screen as the potential screen to zoom to.
-
 
225
        if (windowAreaOnScreen > zoomData->largestArea) {
-
 
226
                zoomData->largestArea = windowAreaOnScreen;
-
 
227
                zoomData->screenWithLargestPartOfWindow = targetDevice;
-
 
228
        }
-
 
229
}
-
 
230
 
-
 
231
// Figure out how much we need to move the window to get it entirely on the monitor.  If
-
 
232
// the window wouldnÕt fit completely on the monitor anyway, donÕt move it at all; weÕll
-
 
233
// make it fit later on.
-
 
234
 
-
 
235
short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint, short idealOnScreenStartPoint,
-
 
236
                                                        short idealOnScreenEndPoint, short screenEdge1, short screenEdge2)
-
 
237
{
-
 
238
        short   offsetAmount;
-
 
239
 
-
 
240
        // First check to see if the window fits on the screen in this dimension.
-
 
241
        if ((idealStartPoint < screenEdge1) && (idealEndPoint > screenEdge2))
-
 
242
                offsetAmount = 0;
-
 
243
        else {
-
 
244
       
-
 
245
                // Find out how much of the window lies off this screen by subtracting the amount of the window
-
 
246
                // that is on the screen from the size of the entire window in this dimension. If the window
-
 
247
                // is completely offscreen, the offset amount is going to be the distance from the ideal
-
 
248
                // starting point to the first edge of the screen.
-
 
249
                if ((idealOnScreenStartPoint - idealOnScreenEndPoint) == 0) {
-
 
250
                        // See if the window is lying to the left or above the screen
-
 
251
                        if (idealEndPoint < screenEdge1)
-
 
252
                                offsetAmount = screenEdge1 - idealStartPoint + kNudgeSlop;
-
 
253
                        else
-
 
254
                        // Otherwise, itÕs below or to the right of the screen
-
 
255
                                offsetAmount = screenEdge2 - idealEndPoint - kNudgeSlop;
-
 
256
                }
-
 
257
                else {
-
 
258
                        // Window is already partially or completely on the screen
-
 
259
                        offsetAmount = (idealEndPoint - idealStartPoint) -
-
 
260
                                                        (idealOnScreenEndPoint - idealOnScreenStartPoint);
-
 
261
       
-
 
262
                        // If we are offscreen a little, move the window in a few more pixels from the edge of the screen.
-
 
263
                        if (offsetAmount != 0)
-
 
264
                                offsetAmount += kNudgeSlop;
-
 
265
                       
-
 
266
                        // Check to see which side of the screen the window was falling off of, so that it can be
-
 
267
                        // nudged in the opposite direction.
-
 
268
                        if (idealEndPoint > screenEdge2)
-
 
269
                                offsetAmount = -offsetAmount;
-
 
270
                }
-
 
271
        }
-
 
272
       
-
 
273
        return offsetAmount;
-
 
274
}
-
 
275
 
-
 
276
/*
-
 
277
        WindowRecord accessor functions
-
 
278
*/
-
 
279
 
-
 
280
RgnHandle GetWindowContentRegion(WindowPeek theWindow)
-
 
281
{
-
 
282
        return (theWindow->contRgn);
-
 
283
}
-
 
284
 
-
 
285
RgnHandle GetWindowStructureRegion(WindowPeek theWindow)
-
 
286
{
-
 
287
        return (theWindow->strucRgn);
-
 
288
}
-
 
289
 
-
 
290
void GetWindowPortRect(WindowPeek theWindow, Rect *portRect)
-
 
291
{
-
 
292
        *portRect = theWindow->port.portRect;
-
 
293
}
-
 
294
 
-
 
295
void SetWindowStandardState(WindowPeek theWindow, const Rect *standardState)
-
 
296
{
-
 
297
        (**((WStateDataHandle) theWindow->dataHandle)).stdState = *standardState;
-
 
298
}
-
 
299
 
-
 
300
void GetWindowUserState(WindowPeek theWindow, Rect *userState)
-
 
301
{
-
 
302
        *userState = (**((WStateDataHandle) theWindow->dataHandle)).userState;
-
 
303
}
-
 
304