source: trunk/src/helpers/animate.c@ 238

Last change on this file since 238 was 238, checked in by umoeller, 23 years ago

Misc fixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 18.3 KB
Line 
1
2/*
3 *@@sourcefile animate.c:
4 * contains a bit of helper code for animations.
5 *
6 * This is a new file with V0.81. Most of this code used to reside
7 * in common.c with previous versions.
8 * Note that with V0.9.0, the code for icon animations has been
9 * moved to the new comctl.c file.
10 *
11 * Usage: All PM programs.
12 *
13 * Function prefixes (new with V0.81):
14 * -- anm* Animation helper functions
15 *
16 * Note: Version numbering in this file relates to XWorkplace version
17 * numbering.
18 *
19 *@@header "helpers\animate.h"
20 */
21
22/*
23 * Copyright (C) 1997-2000 Ulrich M”ller.
24 * This file is part of the "XWorkplace helpers" source package.
25 * This is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published
27 * by the Free Software Foundation, in version 2 as it comes in the
28 * "COPYING" file of the XWorkplace main distribution.
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
33 */
34
35#define OS2EMX_PLAIN_CHAR
36 // this is needed for "os2emx.h"; if this is defined,
37 // emx will define PSZ as _signed_ char, otherwise
38 // as unsigned char
39
40#define INCL_DOSPROCESS
41#define INCL_DOSDEVICES
42#define INCL_DOSDEVIOCTL
43#define INCL_DOSMISC
44#define INCL_DOSERRORS
45
46#define INCL_WINWINDOWMGR
47#define INCL_WINPOINTERS
48#define INCL_WINSYS
49
50#define INCL_GPILOGCOLORTABLE
51#define INCL_GPIPRIMITIVES
52#define INCL_GPIBITMAPS // added UM 99-10-22; needed for EMX headers
53#include <os2.h>
54
55#include <stdlib.h>
56#include <string.h>
57
58#include "setup.h" // code generation and debugging options
59
60#include "helpers\winh.h"
61
62/*
63 *@@category: Helpers\PM helpers\Animation helpers
64 * See animate.c.
65 */
66
67/*
68 *@@ anmBlowUpBitmap:
69 * this displays an animation based on a given bitmap.
70 * The bitmap is "blown up" in that it is continually
71 * increased in size until the original size is reached.
72 * The animation is calculated so that it lasts exactly
73 * ulAnimation milliseconds, no matter how fast the
74 * system is.
75 *
76 * This function does not return until the animation
77 * has completed.
78 *
79 * You should run this routine in a thread with higher-
80 * than-normal priority, because otherwise the kernel
81 * might interrupt the thread, causing a somewhat jerky
82 * display.
83 *
84 * Returns the count of animation steps that were drawn.
85 * This is dependent on the speed of the system.
86 *
87 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
88 */
89
90BOOL anmBlowUpBitmap(HPS hps, // in: from WinGetScreenPS(HWND_DESKTOP)
91 HBITMAP hbm, // in: bitmap to be displayed
92 ULONG ulAnimationTime) // in: total animation time (ms)
93{
94 ULONG ulrc = 0;
95 ULONG ulInitialTime,
96 ulNowTime;
97 // ulCurrentSize = 10;
98
99 if (hps)
100 {
101 POINTL ptl = {0, 0};
102 RECTL rtlStretch;
103 ULONG ul,
104 ulSteps = 20;
105 BITMAPINFOHEADER bih;
106 GpiQueryBitmapParameters(hbm, &bih);
107 ptl.x = (G_cxScreen - bih.cx) / 2;
108 ptl.y = (G_cyScreen - bih.cy) / 2;
109
110 // we now use ul for the current animation step,
111 // which is a pointer on a scale from 1 to ulAnimationTime;
112 // ul will be recalculated after each animation
113 // step according to how much time the animation
114 // has cost on this display so far. This has the
115 // following advantages:
116 // 1) no matter how fast the system is, the animation
117 // will always last ulAnimationTime milliseconds
118 // 2) since large bitmaps take more time to calculate,
119 // the animation won't appear to slow down then
120 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
121 &ulInitialTime,
122 sizeof(ulInitialTime));
123 ul = 1;
124 ulSteps = 1000;
125 do {
126 LONG cx = (((bih.cx-20) * ul) / ulSteps) + 20;
127 LONG cy = (((bih.cy-20) * ul) / ulSteps) + 20;
128 rtlStretch.xLeft = ptl.x + ((bih.cx - cx) / 2);
129 rtlStretch.yBottom = ptl.y + ((bih.cy - cy) / 2);
130 rtlStretch.xRight = rtlStretch.xLeft + cx;
131 rtlStretch.yTop = rtlStretch.yBottom + cy;
132
133 WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&rtlStretch,
134 0, 0, // we don't need colors
135 DBM_STRETCH);
136
137 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
138 &ulNowTime,
139 sizeof(ulNowTime));
140
141 // recalculate ul: rule of three based on the
142 // time we've spent on animation so far
143 ul = (ulSteps
144 * (ulNowTime - ulInitialTime)) // time spent so far
145 / ulAnimationTime; // time to spend altogether
146
147 ulrc++; // return count
148
149 } while (ul < ulSteps);
150
151 // finally, draw the 1:1 version
152 WinDrawBitmap(hps, hbm, NULL, &ptl,
153 0, 0, // we don't need colors
154 DBM_NORMAL);
155
156 } // end if (hps)
157
158 return ulrc;
159}
160
161#define LAST_LINE_WIDTH 2
162
163/* ******************************************************************
164 *
165 * Other animations
166 *
167 ********************************************************************/
168
169/*
170 *@@ anmPowerOff:
171 * displays an animation that looks like a
172 * monitor being turned off; hps must have
173 * been acquired using WinGetScreenPS.
174 *
175 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
176 */
177
178VOID anmPowerOff(HPS hps,
179 ULONG ulMaxTime1, // = 500,
180 ULONG ulMaxTime2, // = 800,
181 ULONG ulMaxTime3, // = 200,
182 ULONG ulWaitEnd) // = 300
183{
184 RECTL rclScreen,
185 rclNow,
186 rclLast,
187 rclDraw;
188 ULONG ulPhase = 1,
189 ulCXLastLine;
190
191 ULONG ulStartTime = 0,
192 ulTimeNow = 0;
193
194 WinQueryWindowRect(HWND_DESKTOP, &rclScreen);
195 ulCXLastLine = rclScreen.xRight / 3;
196
197 WinShowPointer(HWND_DESKTOP, FALSE);
198
199 memcpy(&rclLast, &rclScreen, sizeof(RECTL));
200
201 // In order to draw the animation, we tell apart three
202 // "phases", signified by the ulPhase variable. While
203 // ulPhase != 99, we stay in a do-while loop.
204 ulPhase = 1;
205
206 do
207 {
208 // get current time
209 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
210 &ulTimeNow,
211 sizeof(ulTimeNow));
212
213 // get start time
214 if (ulStartTime == 0)
215 // this is reset when we enter a new phase
216 ulStartTime = ulTimeNow;
217
218 if (ulPhase == 1)
219 {
220 // Phase 1: "shrink" the screen by drawing black
221 // rectangles from the edges towards the center
222 // of the screen. With every loop, we draw the
223 // rectangles a bit closer to the center, until
224 // the center is black too. Sort of like this:
225
226 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
227 // º black º
228 // º º
229 // º ÚÄÄÄÄÄÄÄÄÄÄÄ¿ º
230 // º ³ rclNow: ³ º
231 // º -> ³ untouched ³ <- º
232 // º ÀÄÄÄÄÄÄÄÄÄÄÄÙ º
233 // º ^ º
234 // º | º
235 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
236
237 // This part lasts exactly (ulMaxTime1) milliseconds.
238
239 // rclNow contains the rectangle _around_ which
240 // the black rectangles are to be drawn. With
241 // every iteration, rclNow is reduced in size.
242 ULONG ulMaxX = (rclScreen.xRight - ulCXLastLine) / 2,
243 ulMaxY = rclScreen.yTop / 2 - LAST_LINE_WIDTH;
244 ULONG ulTimePassed = (ulTimeNow - ulStartTime);
245 if (ulTimePassed >= ulMaxTime1)
246 {
247 // time has elapsed:
248 ulTimePassed = ulMaxTime1;
249 // enter next phase on next loop
250 ulPhase++;
251 // reget start time
252 ulStartTime = 0;
253 }
254 rclNow.xLeft = ulMaxX * ulTimePassed / ulMaxTime1;
255 rclNow.yBottom = ulMaxY * ulTimePassed / ulMaxTime1;
256 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
257 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
258
259 /* rclNow.xLeft = ((rclScreen.yTop / 2) * ul / ulSteps );
260 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
261 rclNow.yBottom = ((rclScreen.yTop / 2) * ul / ulSteps );
262 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom; */
263
264 /* if (rclNow.yBottom > (rclNow.yTop - LAST_WIDTH) )
265 {
266 rclNow.yBottom = (rclScreen.yTop / 2) - LAST_WIDTH;
267 rclNow.yTop = (rclScreen.yTop / 2) + LAST_WIDTH;
268 } */
269
270 // draw black rectangle on top of rclNow
271 rclDraw.xLeft = rclLast.xLeft;
272 rclDraw.xRight = rclLast.xRight;
273 rclDraw.yBottom = rclNow.yTop;
274 rclDraw.yTop = rclLast.yTop;
275 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
276
277 // draw black rectangle left of rclNow
278 rclDraw.xLeft = rclLast.xLeft;
279 rclDraw.xRight = rclNow.xLeft;
280 rclDraw.yBottom = rclLast.yBottom;
281 rclDraw.yTop = rclLast.yTop;
282 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
283
284 // draw black rectangle right of rclNow
285 rclDraw.xLeft = rclNow.xRight;
286 rclDraw.xRight = rclLast.xRight;
287 rclDraw.yBottom = rclLast.yBottom;
288 rclDraw.yTop = rclLast.yTop;
289 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
290
291 // draw black rectangle at the bottom of rclNow
292 rclDraw.xLeft = rclLast.xLeft;
293 rclDraw.xRight = rclLast.xRight;
294 rclDraw.yBottom = rclLast.yBottom;
295 rclDraw.yTop = rclNow.yBottom;
296 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
297
298 // remember rclNow for next iteration
299 memcpy(&rclLast, &rclNow, sizeof(RECTL));
300
301 // done with "shrinking"?
302 /* if ( rclNow.xRight < ((rclScreen.xRight / 2) + LAST_WIDTH) )
303 {
304 ulPhase = 2; // exit
305 // reget start time
306 ulStartTime = 0;
307 } */
308
309 if (ulPhase == 2)
310 {
311 // this was the last step in this phase:
312 memcpy(&rclLast, &rclScreen, sizeof(RECTL));
313 }
314 }
315 else if (ulPhase == 2)
316 {
317 // Phase 2: draw a horizontal white line about
318 // where the last rclNow was. and shrink it
319 // towards the middle. This ends with a white
320 // dot in the middle of the screen.
321
322 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
323 // º black º
324 // º º
325 // º º
326 // º --> ÄwhiteÄÄÄÄ <-- º
327 // º º
328 // º º
329 // º º
330 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
331
332 // This part lasts exactly (ulMaxTime2) milliseconds.
333
334 // start is same as max in step 1
335 ULONG ulStartX = (rclScreen.xRight - ulCXLastLine) / 2,
336 ulY = rclScreen.yTop / 2 - LAST_LINE_WIDTH;
337 ULONG ulMaxX = (rclScreen.xRight) / 2 - LAST_LINE_WIDTH; // center
338 ULONG ulTimePassed = (ulTimeNow - ulStartTime);
339 if (ulTimePassed >= ulMaxTime2)
340 {
341 // time has elapsed:
342 ulTimePassed = ulMaxTime2;
343 // enter next phase on next loop
344 ulPhase++;
345 // reget start time
346 ulStartTime = 0;
347 }
348
349 rclNow.xLeft = ulStartX
350 + ( (ulMaxX - ulStartX) * ulTimePassed / ulMaxTime2 );
351 rclNow.yBottom = ulY;
352 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
353 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
354
355 // draw black rectangle left of rclNow
356 rclDraw.xLeft = rclLast.xLeft;
357 rclDraw.xRight = rclNow.xLeft;
358 rclDraw.yBottom = rclLast.yBottom;
359 rclDraw.yTop = rclLast.yTop;
360 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
361
362 // draw black rectangle right of rclNow
363 rclDraw.xLeft = rclNow.xRight;
364 rclDraw.xRight = rclLast.xRight;
365 rclDraw.yBottom = rclLast.yBottom;
366 rclDraw.yTop = rclLast.yTop;
367 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
368
369 // WinFillRect(hps, &rclNow, CLR_WHITE); // exclusive
370
371 // remember rclNow for next iteration
372 memcpy(&rclLast, &rclNow, sizeof(RECTL));
373
374 if (ulPhase == 3)
375 {
376 // this was the last step in this phase:
377 // keep the dot visible for a while
378 DosSleep(ulMaxTime3);
379
380 // draw a white line for phase 3
381 rclLast.xLeft = ulMaxX;
382 rclLast.yBottom = rclScreen.yTop / 4;
383 rclLast.xRight = rclScreen.xRight - rclLast.xLeft;
384 rclLast.yTop = rclScreen.yTop - rclLast.yBottom;
385
386 WinFillRect(hps, &rclLast, CLR_WHITE); // exclusive
387 }
388 }
389 else if (ulPhase == 3)
390 {
391 // Phase 3: make the white line shorter with
392 // every iteration by drawing black rectangles
393 // above and below it. These are drawn closer
394 // to the center with each iteration.
395
396 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
397 // º º
398 // º º
399 // º | º
400 // º | º
401 // º | º
402 // º º
403 // º º
404 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
405
406 // This part lasts exactly ulMaxTime3 milliseconds.
407 ULONG ulX = (rclScreen.xRight) / 2 - LAST_LINE_WIDTH, // center
408 ulStartY = rclScreen.yTop / 4;
409 ULONG ulMaxY = (rclScreen.yTop) / 2 - LAST_LINE_WIDTH; // center
410 ULONG ulTimePassed = (ulTimeNow - ulStartTime);
411 if (ulTimePassed >= ulMaxTime3)
412 {
413 // time has elapsed:
414 ulTimePassed = ulMaxTime3;
415 // stop
416 ulPhase = 99;
417 }
418
419 rclNow.xLeft = ulX;
420 rclNow.yBottom = ulStartY
421 + ( (ulMaxY - ulStartY) * ulTimePassed / ulMaxTime3 );
422 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
423 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
424
425 // draw black rectangle on top of rclNow
426 rclDraw.xLeft = rclLast.xLeft;
427 rclDraw.xRight = rclLast.xRight;
428 rclDraw.yBottom = rclNow.yTop;
429 rclDraw.yTop = rclLast.yTop;
430 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
431
432 // draw black rectangle at the bottom of rclNow
433 rclDraw.xLeft = rclLast.xLeft;
434 rclDraw.xRight = rclLast.xRight;
435 rclDraw.yBottom = rclLast.yBottom;
436 rclDraw.yTop = rclNow.yBottom;
437 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
438
439 // remember rclNow for next iteration
440 memcpy(&rclLast, &rclNow, sizeof(RECTL));
441
442 /* rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
443 rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
444 rclDraw.yTop = (rclScreen.yTop * 3 / 4);
445 rclDraw.yBottom = (rclScreen.yTop * 3 / 4) - ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
446 if (rclDraw.yBottom < ((rclScreen.yTop / 2) + LAST_LINE_WIDTH))
447 rclDraw.yBottom = ((rclScreen.yTop / 2) + LAST_LINE_WIDTH);
448 WinFillRect(hps, &rclDraw, CLR_BLACK);
449
450 rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
451 rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
452 rclDraw.yBottom = (rclScreen.yTop * 1 / 4);
453 rclDraw.yTop = (rclScreen.yTop * 1 / 4) + ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
454 if (rclDraw.yTop > ((rclScreen.yTop / 2) - LAST_LINE_WIDTH))
455 rclDraw.yBottom = ((rclScreen.yTop / 2) - LAST_LINE_WIDTH);
456
457 WinFillRect(hps, &rclDraw, CLR_BLACK);
458
459 ul++;
460 if (ul > LAST_STEPS) */
461 // ulPhase = 99;
462 }
463
464 } while (ulPhase != 99);
465
466 // sleep a while
467 DosSleep(ulWaitEnd / 2);
468 WinFillRect(hps, &rclScreen, CLR_BLACK); // exclusive
469 DosSleep(ulWaitEnd / 2);
470
471 WinShowPointer(HWND_DESKTOP, TRUE);
472}
473
474
475// testcase
476
477/* int main(int argc, char* argp)
478{
479 HENUM henum;
480 HWND hwndTop;
481 HAB hab = WinInitialize(0);
482 HMQ hmq = WinCreateMsgQueue(hab, 0);
483 HPS hps = WinGetScreenPS(HWND_DESKTOP);
484
485 anmPowerOff(hps);
486
487 henum = WinBeginEnumWindows(HWND_DESKTOP);
488 while ((hwndTop = WinGetNextWindow(henum)))
489 if (WinIsWindowShowing(hwndTop))
490 WinInvalidateRect(hwndTop, NULL, TRUE);
491 WinEndEnumWindows(henum);
492
493 WinShowPointer(HWND_DESKTOP, TRUE);
494
495 WinDestroyMsgQueue(hmq);
496 WinTerminate(hab);
497
498 return 0;
499} */
Note: See TracBrowser for help on using the repository browser.