Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

642 lines
14 KiB

  1. /*++
  2. Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. worldmap.c
  5. Abstract:
  6. This module implements the world map for the Date/Time applet.
  7. Revision History:
  8. --*/
  9. //
  10. // Include Files.
  11. //
  12. #include "timedate.h"
  13. #include <commctrl.h>
  14. #include "worldmap.h"
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. // ZeroCDC
  18. //
  19. ////////////////////////////////////////////////////////////////////////////
  20. static void ZeroCDC(
  21. LPCDC cdc)
  22. {
  23. cdc->dc = NULL;
  24. cdc->bitmap = cdc->defbitmap = NULL;
  25. }
  26. ////////////////////////////////////////////////////////////////////////////
  27. //
  28. // CreateCDC
  29. //
  30. ////////////////////////////////////////////////////////////////////////////
  31. static BOOL CreateCDC(
  32. LPCDC cdc,
  33. HBITMAP bitmap)
  34. {
  35. cdc->dc = CreateCompatibleDC(NULL);
  36. cdc->bitmap = cdc->defbitmap = NULL;
  37. if (!bitmap)
  38. {
  39. return (FALSE);
  40. }
  41. if (!cdc->dc)
  42. {
  43. if (bitmap)
  44. {
  45. DeleteBitmap(bitmap);
  46. }
  47. return (FALSE);
  48. }
  49. if (bitmap)
  50. {
  51. SetLayout(cdc->dc, LAYOUT_BITMAPORIENTATIONPRESERVED); // to avoid mirroring on mirrored builds
  52. cdc->defbitmap = SelectBitmap(cdc->dc, cdc->bitmap = bitmap);
  53. }
  54. return (TRUE);
  55. }
  56. ////////////////////////////////////////////////////////////////////////////
  57. //
  58. // DestroyCDC
  59. //
  60. ////////////////////////////////////////////////////////////////////////////
  61. static void DestroyCDC(
  62. LPCDC cdc)
  63. {
  64. if (cdc->dc)
  65. {
  66. if (cdc->defbitmap)
  67. {
  68. SelectBitmap(cdc->dc, cdc->defbitmap);
  69. }
  70. if (cdc->bitmap)
  71. {
  72. DeleteBitmap(cdc->bitmap);
  73. }
  74. DeleteDC(cdc->dc);
  75. cdc->dc = NULL;
  76. }
  77. cdc->bitmap = cdc->defbitmap = NULL;
  78. }
  79. ////////////////////////////////////////////////////////////////////////////
  80. //
  81. // LoadWorldMap
  82. //
  83. ////////////////////////////////////////////////////////////////////////////
  84. BOOL LoadWorldMap(
  85. LPWORLDMAP map,
  86. HINSTANCE instance,
  87. LPCTSTR resource)
  88. {
  89. HDC tempdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
  90. BOOL result = FALSE;
  91. ZeroCDC(&map->original);
  92. ZeroCDC(&map->prepared);
  93. map->size.cx = map->size.cy = 0;
  94. map->rotation = 0;
  95. if (tempdc)
  96. {
  97. if (CreateCDC( &map->original,
  98. LoadImage( instance,
  99. resource,
  100. IMAGE_BITMAP,
  101. 0,
  102. 0,
  103. LR_CREATEDIBSECTION ) ))
  104. {
  105. DIBSECTION ds;
  106. if (GetObject(map->original.bitmap, sizeof(DIBSECTION), &ds))
  107. {
  108. map->size.cx = ds.dsBm.bmWidth;
  109. map->size.cy = ds.dsBm.bmHeight;
  110. map->bits = (BYTE *)ds.dsBm.bmBits;
  111. map->scanbytes = ds.dsBm.bmWidthBytes;
  112. if (( (GetDeviceCaps(tempdc, BITSPIXEL) *
  113. GetDeviceCaps(tempdc, PLANES)) > 4 ) ||
  114. CreateCDC( &map->prepared,
  115. CreateCompatibleBitmap( tempdc,
  116. ds.dsBm.bmWidth,
  117. ds.dsBm.bmHeight ) ))
  118. {
  119. RGBQUAD init = { 127, 0, 0, 0 };
  120. RGBQUAD *color = map->dirty.colors;
  121. int i = WORLDMAP_MAX_COLORS;
  122. while (i--)
  123. {
  124. *color++ = init;
  125. }
  126. //
  127. // Mark everything as dirty.
  128. //
  129. map->dirty.first = 0;
  130. map->dirty.last = WORLDMAP_MAX_COLORS - 1;
  131. map->dirty.spans = NULL;
  132. map->dirty.freespans = NULL;
  133. map->source = (map->prepared.dc)
  134. ? map->prepared.dc
  135. : map->original.dc;
  136. result = TRUE;
  137. }
  138. }
  139. else
  140. {
  141. DestroyCDC(&map->original);
  142. }
  143. }
  144. DeleteDC(tempdc);
  145. }
  146. return (result);
  147. }
  148. ////////////////////////////////////////////////////////////////////////////
  149. //
  150. // FreeWorldMap
  151. //
  152. ////////////////////////////////////////////////////////////////////////////
  153. void FreeWorldMap(
  154. LPWORLDMAP map)
  155. {
  156. DIRTYSPAN *span = map->dirty.spans;
  157. while (span)
  158. {
  159. DIRTYSPAN *next = span->next;
  160. LocalFree((HANDLE)span);
  161. span = next;
  162. }
  163. span = map->dirty.freespans;
  164. while (span)
  165. {
  166. DIRTYSPAN *next = span->next;
  167. LocalFree((HANDLE)span);
  168. span = next;
  169. }
  170. DestroyCDC(&map->original);
  171. DestroyCDC(&map->prepared);
  172. }
  173. ////////////////////////////////////////////////////////////////////////////
  174. //
  175. // SetWorldMapRotation
  176. //
  177. ////////////////////////////////////////////////////////////////////////////
  178. void SetWorldMapRotation(
  179. LPWORLDMAP map,
  180. int rotation)
  181. {
  182. rotation %= (int)map->size.cx;
  183. if (rotation < 0)
  184. {
  185. rotation += (int)map->size.cx;
  186. }
  187. map->rotation = rotation;
  188. }
  189. ////////////////////////////////////////////////////////////////////////////
  190. //
  191. // RotateWorldMap
  192. //
  193. ////////////////////////////////////////////////////////////////////////////
  194. void RotateWorldMap(
  195. LPWORLDMAP map,
  196. int delta)
  197. {
  198. SetWorldMapRotation(map, map->rotation + delta);
  199. }
  200. ////////////////////////////////////////////////////////////////////////////
  201. //
  202. // WorldMapGetDisplayedLocation
  203. //
  204. ////////////////////////////////////////////////////////////////////////////
  205. int WorldMapGetDisplayedLocation(
  206. LPWORLDMAP map,
  207. int pos)
  208. {
  209. return ( (pos + map->rotation) % map->size.cx );
  210. }
  211. ////////////////////////////////////////////////////////////////////////////
  212. //
  213. // EnumWorldMapDirtySpans
  214. //
  215. ////////////////////////////////////////////////////////////////////////////
  216. void EnumWorldMapDirtySpans(
  217. LPWORLDMAP map,
  218. ENUMSPANPROC proc,
  219. LPARAM data,
  220. BOOL rotate)
  221. {
  222. DIRTYSPAN *span = map->dirty.spans;
  223. while (span)
  224. {
  225. if (rotate)
  226. {
  227. int left = (span->left + map->rotation) % map->size.cx;
  228. int right = left + span->right - span->left;
  229. if (right > map->size.cx)
  230. {
  231. proc(data, left, map->size.cx);
  232. left = 0;
  233. right -= map->size.cx;
  234. }
  235. proc(data, left, right);
  236. }
  237. else
  238. {
  239. proc(data, span->left, span->right);
  240. }
  241. span = span->next;
  242. }
  243. }
  244. ////////////////////////////////////////////////////////////////////////////
  245. //
  246. // GetWorldMapColorIndex
  247. //
  248. ////////////////////////////////////////////////////////////////////////////
  249. int GetWorldMapColorIndex(
  250. LPWORLDMAP map,
  251. int x,
  252. int y)
  253. {
  254. //
  255. // Protect against faulting.
  256. //
  257. if ( !map->bits ||
  258. (x < 0) || (x >= map->size.cx) ||
  259. (y < 0) || (y >= map->size.cy) )
  260. {
  261. return (-1);
  262. }
  263. //
  264. // Correct source X coordinate for map's virtual rotation.
  265. //
  266. x += 2 * (int)map->size.cx - map->rotation;
  267. x %= (int)map->size.cx;
  268. //
  269. // Correct for dib origin.
  270. //
  271. y = (LONG)map->size.cy - 1 - y;
  272. return ( map->bits[map->scanbytes * y + x] );
  273. }
  274. ////////////////////////////////////////////////////////////////////////////
  275. //
  276. // NewSpan
  277. //
  278. ////////////////////////////////////////////////////////////////////////////
  279. DIRTYSPAN *NewSpan(
  280. DIRTYSTUFF *dirty,
  281. DIRTYSPAN *a,
  282. DIRTYSPAN *b)
  283. {
  284. DIRTYSPAN *span = dirty->freespans;
  285. if (span)
  286. {
  287. dirty->freespans = span->next;
  288. }
  289. else
  290. {
  291. if ((span = (DIRTYSPAN *)LocalAlloc(LPTR, sizeof(DIRTYSPAN))) == NULL)
  292. {
  293. return (NULL);
  294. }
  295. }
  296. span->next = b;
  297. if (a)
  298. {
  299. a->next = span;
  300. }
  301. else
  302. {
  303. dirty->spans = span;
  304. }
  305. return (span);
  306. }
  307. ////////////////////////////////////////////////////////////////////////////
  308. //
  309. // DeleteSpan
  310. //
  311. ////////////////////////////////////////////////////////////////////////////
  312. void DeleteSpan(
  313. DIRTYSTUFF *dirty,
  314. DIRTYSPAN *a,
  315. DIRTYSPAN *b)
  316. {
  317. if (a)
  318. {
  319. a->next = b->next;
  320. }
  321. else
  322. {
  323. dirty->spans = b->next;
  324. }
  325. b->next = dirty->freespans;
  326. dirty->freespans = b;
  327. }
  328. ////////////////////////////////////////////////////////////////////////////
  329. //
  330. // AddDirtySpan
  331. //
  332. ////////////////////////////////////////////////////////////////////////////
  333. void AddDirtySpan(
  334. DIRTYSTUFF *dirty,
  335. int left,
  336. int cx)
  337. {
  338. int right = left + cx;
  339. DIRTYSPAN *curr = dirty->spans;
  340. DIRTYSPAN *temp = NULL;
  341. DIRTYSPAN *span;
  342. cx = left - 1;
  343. while (curr && (cx > curr->right))
  344. {
  345. temp = curr;
  346. curr = curr->next;
  347. }
  348. cx = right + 1;
  349. if (curr && (cx >= curr->left))
  350. {
  351. if (left < curr->left)
  352. {
  353. curr->left = left;
  354. }
  355. span = temp = curr;
  356. if (right > curr->right)
  357. {
  358. curr->right = right;
  359. curr = curr->next;
  360. while (curr && (cx >= curr->left))
  361. {
  362. span->right = curr->right;
  363. DeleteSpan(dirty, temp, curr);
  364. temp = temp->next;
  365. curr = (temp ? temp->next : NULL);
  366. }
  367. }
  368. }
  369. else
  370. {
  371. if ((span = NewSpan(dirty, temp, curr)) == NULL)
  372. {
  373. if (!temp)
  374. {
  375. return;
  376. }
  377. span = temp;
  378. left = span->left;
  379. }
  380. span->left = left;
  381. span->right = right;
  382. }
  383. }
  384. ////////////////////////////////////////////////////////////////////////////
  385. //
  386. // ChangeWorldMapColor
  387. //
  388. ////////////////////////////////////////////////////////////////////////////
  389. void ChangeWorldMapColor(
  390. LPWORLDMAP map,
  391. int index,
  392. const RGBQUAD *color,
  393. int x,
  394. int cx)
  395. {
  396. if ((index >= 0) && (index < WORLDMAP_MAX_COLORS))
  397. {
  398. //
  399. // Store the new color.
  400. //
  401. map->dirty.colors[index] = *color;
  402. //
  403. // Update the dirty markers to include this entry.
  404. //
  405. if (index < map->dirty.first)
  406. {
  407. map->dirty.first = index;
  408. }
  409. if (index > map->dirty.last)
  410. {
  411. map->dirty.last = index;
  412. }
  413. }
  414. while (((x + cx) > map->size.cx) && (x >= 0))
  415. {
  416. x -= map->size.cx;
  417. }
  418. if (x < 0)
  419. {
  420. AddDirtySpan(&map->dirty, map->size.cx + x, -x);
  421. cx += x;
  422. x = 0;
  423. }
  424. AddDirtySpan(&map->dirty, x, cx);
  425. }
  426. ////////////////////////////////////////////////////////////////////////////
  427. //
  428. // CommitChanges
  429. //
  430. ////////////////////////////////////////////////////////////////////////////
  431. void CommitChanges(
  432. LPWORLDMAP map)
  433. {
  434. if (map->dirty.last >= 0)
  435. {
  436. SetDIBColorTable( map->original.dc,
  437. map->dirty.first,
  438. 1 + map->dirty.last - map->dirty.first,
  439. map->dirty.colors + map->dirty.first );
  440. //
  441. // Reset the dirty markers.
  442. //
  443. map->dirty.first = WORLDMAP_MAX_COLORS;
  444. map->dirty.last = -1;
  445. }
  446. while (map->dirty.spans)
  447. {
  448. DIRTYSPAN *span = map->dirty.spans;
  449. if (map->prepared.dc)
  450. {
  451. BitBlt( map->prepared.dc,
  452. span->left,
  453. 0,
  454. span->right - span->left,
  455. (int)map->size.cy,
  456. map->original.dc,
  457. span->left,
  458. 0,
  459. SRCCOPY );
  460. }
  461. DeleteSpan(&map->dirty, NULL, span);
  462. }
  463. }
  464. ////////////////////////////////////////////////////////////////////////////
  465. //
  466. // DrawWorldMap
  467. //
  468. ////////////////////////////////////////////////////////////////////////////
  469. void DrawWorldMap(
  470. HDC dc,
  471. int xdst,
  472. int ydst,
  473. int cx,
  474. int cy,
  475. LPWORLDMAP map,
  476. int xmap,
  477. int ymap,
  478. DWORD rop)
  479. {
  480. CommitChanges(map);
  481. //
  482. // Lop off extra Y stuff cause there's nothing there.
  483. //
  484. if ((ymap + cy) > (int)map->size.cy)
  485. {
  486. cy = (int)map->size.cy - ymap;
  487. }
  488. //
  489. // Clip off extra X so we'll enter the case below only when we need to.
  490. //
  491. if (cx > (int)map->size.cx)
  492. {
  493. cx = (int)map->size.cx;
  494. }
  495. //
  496. // Correct source X coordinate for map's virtual rotation.
  497. //
  498. xmap += 2 * (int)map->size.cx - map->rotation;
  499. xmap %= (int)map->size.cx;
  500. //
  501. // See if the blt rect falls off the end of our flat little world.
  502. //
  503. if ((xmap + cx) > (int)map->size.cx)
  504. {
  505. //
  506. // Compute the width of the first blt.
  507. //
  508. int firstcx = (int)map->size.cx - xmap;
  509. //
  510. // See bits. See bits blt.
  511. //
  512. BitBlt(dc, xdst, ydst, firstcx, cy, map->source, xmap, ymap, rop);
  513. //
  514. // Adjust the params so the second blt does the right wrapping.
  515. //
  516. xdst += firstcx;
  517. cx -= firstcx;
  518. xmap = 0;
  519. }
  520. //
  521. // blt bits blt!
  522. //
  523. BitBlt(dc, xdst, ydst, cx, cy, map->source, xmap, ymap, rop);
  524. }