|
|
/*++
Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
Module Name:
worldmap.c
Abstract:
This module implements the world map for the Date/Time applet.
Revision History:
--*/
//
// Include Files.
//
#include "timedate.h"
#include <commctrl.h>
#include "worldmap.h"
////////////////////////////////////////////////////////////////////////////
//
// ZeroCDC
//
////////////////////////////////////////////////////////////////////////////
static void ZeroCDC( LPCDC cdc) { cdc->dc = NULL; cdc->bitmap = cdc->defbitmap = NULL; }
////////////////////////////////////////////////////////////////////////////
//
// CreateCDC
//
////////////////////////////////////////////////////////////////////////////
static BOOL CreateCDC( LPCDC cdc, HBITMAP bitmap) { cdc->dc = CreateCompatibleDC(NULL); cdc->bitmap = cdc->defbitmap = NULL;
if (!bitmap) { return (FALSE); }
if (!cdc->dc) { if (bitmap) { DeleteBitmap(bitmap); } return (FALSE); }
if (bitmap) { SetLayout(cdc->dc, LAYOUT_BITMAPORIENTATIONPRESERVED); // to avoid mirroring on mirrored builds
cdc->defbitmap = SelectBitmap(cdc->dc, cdc->bitmap = bitmap); }
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// DestroyCDC
//
////////////////////////////////////////////////////////////////////////////
static void DestroyCDC( LPCDC cdc) { if (cdc->dc) { if (cdc->defbitmap) { SelectBitmap(cdc->dc, cdc->defbitmap); } if (cdc->bitmap) { DeleteBitmap(cdc->bitmap); } DeleteDC(cdc->dc); cdc->dc = NULL; }
cdc->bitmap = cdc->defbitmap = NULL; }
////////////////////////////////////////////////////////////////////////////
//
// LoadWorldMap
//
////////////////////////////////////////////////////////////////////////////
BOOL LoadWorldMap( LPWORLDMAP map, HINSTANCE instance, LPCTSTR resource) { HDC tempdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); BOOL result = FALSE;
ZeroCDC(&map->original); ZeroCDC(&map->prepared);
map->size.cx = map->size.cy = 0; map->rotation = 0;
if (tempdc) { if (CreateCDC( &map->original, LoadImage( instance, resource, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ) )) { DIBSECTION ds;
if (GetObject(map->original.bitmap, sizeof(DIBSECTION), &ds)) { map->size.cx = ds.dsBm.bmWidth; map->size.cy = ds.dsBm.bmHeight; map->bits = (BYTE *)ds.dsBm.bmBits; map->scanbytes = ds.dsBm.bmWidthBytes;
if (( (GetDeviceCaps(tempdc, BITSPIXEL) * GetDeviceCaps(tempdc, PLANES)) > 4 ) || CreateCDC( &map->prepared, CreateCompatibleBitmap( tempdc, ds.dsBm.bmWidth, ds.dsBm.bmHeight ) )) { RGBQUAD init = { 127, 0, 0, 0 }; RGBQUAD *color = map->dirty.colors; int i = WORLDMAP_MAX_COLORS;
while (i--) { *color++ = init; }
//
// Mark everything as dirty.
//
map->dirty.first = 0; map->dirty.last = WORLDMAP_MAX_COLORS - 1; map->dirty.spans = NULL; map->dirty.freespans = NULL;
map->source = (map->prepared.dc) ? map->prepared.dc : map->original.dc;
result = TRUE; } } else { DestroyCDC(&map->original); } }
DeleteDC(tempdc); }
return (result); }
////////////////////////////////////////////////////////////////////////////
//
// FreeWorldMap
//
////////////////////////////////////////////////////////////////////////////
void FreeWorldMap( LPWORLDMAP map) { DIRTYSPAN *span = map->dirty.spans;
while (span) { DIRTYSPAN *next = span->next;
LocalFree((HANDLE)span); span = next; }
span = map->dirty.freespans;
while (span) { DIRTYSPAN *next = span->next;
LocalFree((HANDLE)span); span = next; }
DestroyCDC(&map->original); DestroyCDC(&map->prepared); }
////////////////////////////////////////////////////////////////////////////
//
// SetWorldMapRotation
//
////////////////////////////////////////////////////////////////////////////
void SetWorldMapRotation( LPWORLDMAP map, int rotation) { rotation %= (int)map->size.cx; if (rotation < 0) { rotation += (int)map->size.cx; } map->rotation = rotation; }
////////////////////////////////////////////////////////////////////////////
//
// RotateWorldMap
//
////////////////////////////////////////////////////////////////////////////
void RotateWorldMap( LPWORLDMAP map, int delta) { SetWorldMapRotation(map, map->rotation + delta); }
////////////////////////////////////////////////////////////////////////////
//
// WorldMapGetDisplayedLocation
//
////////////////////////////////////////////////////////////////////////////
int WorldMapGetDisplayedLocation( LPWORLDMAP map, int pos) { return ( (pos + map->rotation) % map->size.cx ); }
////////////////////////////////////////////////////////////////////////////
//
// EnumWorldMapDirtySpans
//
////////////////////////////////////////////////////////////////////////////
void EnumWorldMapDirtySpans( LPWORLDMAP map, ENUMSPANPROC proc, LPARAM data, BOOL rotate) { DIRTYSPAN *span = map->dirty.spans;
while (span) { if (rotate) { int left = (span->left + map->rotation) % map->size.cx; int right = left + span->right - span->left;
if (right > map->size.cx) { proc(data, left, map->size.cx);
left = 0; right -= map->size.cx; }
proc(data, left, right); } else { proc(data, span->left, span->right); }
span = span->next; } }
////////////////////////////////////////////////////////////////////////////
//
// GetWorldMapColorIndex
//
////////////////////////////////////////////////////////////////////////////
int GetWorldMapColorIndex( LPWORLDMAP map, int x, int y) { //
// Protect against faulting.
//
if ( !map->bits || (x < 0) || (x >= map->size.cx) || (y < 0) || (y >= map->size.cy) ) { return (-1); }
//
// Correct source X coordinate for map's virtual rotation.
//
x += 2 * (int)map->size.cx - map->rotation; x %= (int)map->size.cx;
//
// Correct for dib origin.
//
y = (LONG)map->size.cy - 1 - y;
return ( map->bits[map->scanbytes * y + x] ); }
////////////////////////////////////////////////////////////////////////////
//
// NewSpan
//
////////////////////////////////////////////////////////////////////////////
DIRTYSPAN *NewSpan( DIRTYSTUFF *dirty, DIRTYSPAN *a, DIRTYSPAN *b) { DIRTYSPAN *span = dirty->freespans;
if (span) { dirty->freespans = span->next; } else { if ((span = (DIRTYSPAN *)LocalAlloc(LPTR, sizeof(DIRTYSPAN))) == NULL) { return (NULL); } }
span->next = b;
if (a) { a->next = span; } else { dirty->spans = span; }
return (span); }
////////////////////////////////////////////////////////////////////////////
//
// DeleteSpan
//
////////////////////////////////////////////////////////////////////////////
void DeleteSpan( DIRTYSTUFF *dirty, DIRTYSPAN *a, DIRTYSPAN *b) { if (a) { a->next = b->next; } else { dirty->spans = b->next; }
b->next = dirty->freespans; dirty->freespans = b; }
////////////////////////////////////////////////////////////////////////////
//
// AddDirtySpan
//
////////////////////////////////////////////////////////////////////////////
void AddDirtySpan( DIRTYSTUFF *dirty, int left, int cx) { int right = left + cx; DIRTYSPAN *curr = dirty->spans; DIRTYSPAN *temp = NULL; DIRTYSPAN *span;
cx = left - 1; while (curr && (cx > curr->right)) { temp = curr; curr = curr->next; }
cx = right + 1; if (curr && (cx >= curr->left)) { if (left < curr->left) { curr->left = left; } span = temp = curr;
if (right > curr->right) { curr->right = right; curr = curr->next;
while (curr && (cx >= curr->left)) { span->right = curr->right;
DeleteSpan(dirty, temp, curr); temp = temp->next; curr = (temp ? temp->next : NULL); } } } else { if ((span = NewSpan(dirty, temp, curr)) == NULL) { if (!temp) { return; } span = temp; left = span->left; }
span->left = left; span->right = right; } }
////////////////////////////////////////////////////////////////////////////
//
// ChangeWorldMapColor
//
////////////////////////////////////////////////////////////////////////////
void ChangeWorldMapColor( LPWORLDMAP map, int index, const RGBQUAD *color, int x, int cx) { if ((index >= 0) && (index < WORLDMAP_MAX_COLORS)) { //
// Store the new color.
//
map->dirty.colors[index] = *color;
//
// Update the dirty markers to include this entry.
//
if (index < map->dirty.first) { map->dirty.first = index; } if (index > map->dirty.last) { map->dirty.last = index; } }
while (((x + cx) > map->size.cx) && (x >= 0)) { x -= map->size.cx; }
if (x < 0) { AddDirtySpan(&map->dirty, map->size.cx + x, -x); cx += x; x = 0; }
AddDirtySpan(&map->dirty, x, cx); }
////////////////////////////////////////////////////////////////////////////
//
// CommitChanges
//
////////////////////////////////////////////////////////////////////////////
void CommitChanges( LPWORLDMAP map) { if (map->dirty.last >= 0) { SetDIBColorTable( map->original.dc, map->dirty.first, 1 + map->dirty.last - map->dirty.first, map->dirty.colors + map->dirty.first );
//
// Reset the dirty markers.
//
map->dirty.first = WORLDMAP_MAX_COLORS; map->dirty.last = -1; }
while (map->dirty.spans) { DIRTYSPAN *span = map->dirty.spans;
if (map->prepared.dc) { BitBlt( map->prepared.dc, span->left, 0, span->right - span->left, (int)map->size.cy, map->original.dc, span->left, 0, SRCCOPY ); }
DeleteSpan(&map->dirty, NULL, span); } }
////////////////////////////////////////////////////////////////////////////
//
// DrawWorldMap
//
////////////////////////////////////////////////////////////////////////////
void DrawWorldMap( HDC dc, int xdst, int ydst, int cx, int cy, LPWORLDMAP map, int xmap, int ymap, DWORD rop) { CommitChanges(map);
//
// Lop off extra Y stuff cause there's nothing there.
//
if ((ymap + cy) > (int)map->size.cy) { cy = (int)map->size.cy - ymap; }
//
// Clip off extra X so we'll enter the case below only when we need to.
//
if (cx > (int)map->size.cx) { cx = (int)map->size.cx; }
//
// Correct source X coordinate for map's virtual rotation.
//
xmap += 2 * (int)map->size.cx - map->rotation; xmap %= (int)map->size.cx;
//
// See if the blt rect falls off the end of our flat little world.
//
if ((xmap + cx) > (int)map->size.cx) { //
// Compute the width of the first blt.
//
int firstcx = (int)map->size.cx - xmap;
//
// See bits. See bits blt.
//
BitBlt(dc, xdst, ydst, firstcx, cy, map->source, xmap, ymap, rop);
//
// Adjust the params so the second blt does the right wrapping.
//
xdst += firstcx; cx -= firstcx; xmap = 0; }
//
// blt bits blt!
//
BitBlt(dc, xdst, ydst, cx, cy, map->source, xmap, ymap, rop); }
|