source: trunk/src/helpers/animate.c

Last change on this file 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
RevLine 
[8]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.
[14]24 * This file is part of the "XWorkplace helpers" source package.
25 * This is free software; you can redistribute it and/or modify
[8]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
[14]40#define INCL_DOSPROCESS
[8]41#define INCL_DOSDEVICES
42#define INCL_DOSDEVIOCTL
[15]43#define INCL_DOSMISC
[14]44#define INCL_DOSERRORS
[8]45
[17]46#define INCL_WINWINDOWMGR
[14]47#define INCL_WINPOINTERS
[8]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
[35]58#include "setup.h" // code generation and debugging options
[8]59
[232]60#include "helpers\winh.h"
[8]61
62/*
63 *@@category: Helpers\PM helpers\Animation helpers
[21]64 * See animate.c.
[8]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.
[15]86 *
87 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
[8]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);
[232]107 ptl.x = (G_cxScreen - bih.cx) / 2;
108 ptl.y = (G_cyScreen - bih.cy) / 2;
[8]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
[15]120 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
121 &ulInitialTime,
122 sizeof(ulInitialTime));
[8]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,
[184]134 0, 0, // we don't need colors
135 DBM_STRETCH);
[8]136
[15]137 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
138 &ulNowTime,
139 sizeof(ulNowTime));
[8]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,
[184]153 0, 0, // we don't need colors
154 DBM_NORMAL);
[8]155
156 } // end if (hps)
157
[184]158 return ulrc;
[8]159}
160
[17]161#define LAST_LINE_WIDTH 2
[8]162
163/* ******************************************************************
[14]164 *
165 * Other animations
166 *
[8]167 ********************************************************************/
168
169/*
170 *@@ anmPowerOff:
171 * displays an animation that looks like a
172 * monitor being turned off; hps must have
[17]173 * been acquired using WinGetScreenPS.
[15]174 *
175 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
[8]176 */
177
[17]178VOID anmPowerOff(HPS hps,
179 ULONG ulMaxTime1, // = 500,
180 ULONG ulMaxTime2, // = 800,
181 ULONG ulMaxTime3, // = 200,
182 ULONG ulWaitEnd) // = 300
[8]183{
[17]184 RECTL rclScreen,
185 rclNow,
186 rclLast,
187 rclDraw;
188 ULONG ulPhase = 1,
189 ulCXLastLine;
[8]190
[17]191 ULONG ulStartTime = 0,
192 ulTimeNow = 0;
193
[8]194 WinQueryWindowRect(HWND_DESKTOP, &rclScreen);
[17]195 ulCXLastLine = rclScreen.xRight / 3;
[8]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
[15]206 do
207 {
[17]208 // get current time
[15]209 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
[17]210 &ulTimeNow,
211 sizeof(ulTimeNow));
[8]212
[17]213 // get start time
214 if (ulStartTime == 0)
215 // this is reset when we enter a new phase
216 ulStartTime = ulTimeNow;
217
[8]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
[17]226 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
227 // º black º
228 // º º
229 // º ÚÄÄÄÄÄÄÄÄÄÄÄ¿ º
230 // º ³ rclNow: ³ º
231 // º -> ³ untouched ³ <- º
232 // º ÀÄÄÄÄÄÄÄÄÄÄÄÙ º
233 // º ^ º
234 // º | º
235 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
[8]236
[17]237 // This part lasts exactly (ulMaxTime1) milliseconds.
238
[8]239 // rclNow contains the rectangle _around_ which
240 // the black rectangles are to be drawn. With
241 // every iteration, rclNow is reduced in size.
[17]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;
[8]256 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
257 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
258
[17]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) )
[15]265 {
[8]266 rclNow.yBottom = (rclScreen.yTop / 2) - LAST_WIDTH;
267 rclNow.yTop = (rclScreen.yTop / 2) + LAST_WIDTH;
[17]268 } */
[8]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;
[18]275 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[8]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;
[18]282 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[8]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;
[18]289 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[8]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;
[18]296 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[8]297
298 // remember rclNow for next iteration
299 memcpy(&rclLast, &rclNow, sizeof(RECTL));
300
301 // done with "shrinking"?
[17]302 /* if ( rclNow.xRight < ((rclScreen.xRight / 2) + LAST_WIDTH) )
303 {
[8]304 ulPhase = 2; // exit
[17]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 }
[15]314 }
315 else if (ulPhase == 2)
316 {
[8]317 // Phase 2: draw a horizontal white line about
[17]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.
[8]321
[17]322 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
323 // º black º
324 // º º
325 // º º
326 // º --> ÄwhiteÄÄÄÄ <-- º
327 // º º
328 // º º
329 // º º
330 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
[8]331
[17]332 // This part lasts exactly (ulMaxTime2) milliseconds.
[8]333
[17]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 }
[8]348
[17]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;
[18]360 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[17]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;
[18]367 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[17]368
[18]369 // WinFillRect(hps, &rclNow, CLR_WHITE); // exclusive
[17]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
[18]386 WinFillRect(hps, &rclLast, CLR_WHITE); // exclusive
[17]387 }
[15]388 }
389 else if (ulPhase == 3)
390 {
[8]391 // Phase 3: make the white line shorter with
392 // every iteration by drawing black rectangles
[17]393 // above and below it. These are drawn closer
394 // to the center with each iteration.
[8]395
[17]396 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
397 // º º
398 // º º
399 // º | º
400 // º | º
401 // º | º
402 // º º
403 // º º
404 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
[8]405
[17]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;
[18]430 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[17]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;
[18]437 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
[17]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;
[8]444 rclDraw.yTop = (rclScreen.yTop * 3 / 4);
445 rclDraw.yBottom = (rclScreen.yTop * 3 / 4) - ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
[17]446 if (rclDraw.yBottom < ((rclScreen.yTop / 2) + LAST_LINE_WIDTH))
447 rclDraw.yBottom = ((rclScreen.yTop / 2) + LAST_LINE_WIDTH);
[8]448 WinFillRect(hps, &rclDraw, CLR_BLACK);
449
[17]450 rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
451 rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
[8]452 rclDraw.yBottom = (rclScreen.yTop * 1 / 4);
453 rclDraw.yTop = (rclScreen.yTop * 1 / 4) + ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
[17]454 if (rclDraw.yTop > ((rclScreen.yTop / 2) - LAST_LINE_WIDTH))
455 rclDraw.yBottom = ((rclScreen.yTop / 2) - LAST_LINE_WIDTH);
[8]456
457 WinFillRect(hps, &rclDraw, CLR_BLACK);
458
459 ul++;
[17]460 if (ul > LAST_STEPS) */
461 // ulPhase = 99;
[8]462 }
463
464 } while (ulPhase != 99);
465
466 // sleep a while
[17]467 DosSleep(ulWaitEnd / 2);
[18]468 WinFillRect(hps, &rclScreen, CLR_BLACK); // exclusive
[17]469 DosSleep(ulWaitEnd / 2);
[8]470
471 WinShowPointer(HWND_DESKTOP, TRUE);
472}
473
474
[17]475// testcase
[8]476
[17]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
[238]498 return 0;
[17]499} */
Note: See TracBrowser for help on using the repository browser.