source: branches/branch-1-0/src/helpers/animate.c@ 297

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

Second round of fixes for 0.9.19.

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