mirror of https://github.com/lianthony/NT4.0
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.
716 lines
20 KiB
716 lines
20 KiB
#include "precomp.h"
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Windows Cardfile - Written by Mark Cliggett */
|
|
/* (c) Copyright Microsoft Corp. 1985, 1994 - All Rights Reserved */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#if !defined(UNICODE) && defined(JAPAN)
|
|
/* Edit Control tune up routine */
|
|
WORD NEAR PASCAL EatOneCharacter(HWND);
|
|
/*
|
|
* routine to retrieve WM_CHAR from the message queue associated with hwnd.
|
|
* this is called by EatString.
|
|
*/
|
|
WORD NEAR PASCAL EatOneCharacter(hwnd)
|
|
register HWND hwnd;
|
|
{
|
|
MSG msg;
|
|
register int i = 10;
|
|
|
|
while (!PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE))
|
|
{
|
|
if (--i == 0)
|
|
return -1;
|
|
Yield ();
|
|
}
|
|
return (msg.wParam & 0x00FF);
|
|
}
|
|
|
|
BOOL FAR PASCAL EatString(HWND,LPSTR,WORD);
|
|
/*
|
|
* This routine is called when the Edit Control receives WM_IME_REPORT
|
|
* with IR_STRINGSTART message. The purpose of this function is to eat
|
|
* all WM_CHARs between IR_STRINGSTART and IR_STRINGEND and to build a
|
|
* string block.
|
|
*/
|
|
BOOL FAR PASCAL EatString(hwnd, lpSp, cchLen)
|
|
register HWND hwnd;
|
|
LPSTR lpSp;
|
|
WORD cchLen;
|
|
{
|
|
MSG msg;
|
|
int i = 10; /* loop counter for avoid infinite loop */
|
|
int w;
|
|
|
|
*lpSp = '\0';
|
|
if (cchLen < 4)
|
|
return NULL; /* not enough */
|
|
cchLen -= 2;
|
|
|
|
while (i--)
|
|
{
|
|
while (PeekMessage (&msg, hwnd, NULL, NULL, PM_REMOVE))
|
|
{
|
|
i = 10;
|
|
switch (msg.message)
|
|
{
|
|
case WM_CHAR:
|
|
*lpSp++ = (BYTE)msg.wParam;
|
|
cchLen--;
|
|
if (IsDBCSLeadByte((BYTE)msg.wParam))
|
|
{
|
|
if ((w = EatOneCharacter(hwnd)) == -1)
|
|
{
|
|
/* Bad DBCS sequence - abort */
|
|
lpSp--;
|
|
goto WillBeDone;
|
|
}
|
|
*lpSp++ = (BYTE)w;
|
|
cchLen--;
|
|
}
|
|
if (cchLen <= 0)
|
|
goto WillBeDone; /* buffer exhausted */
|
|
break;
|
|
|
|
case WM_IME_REPORT:
|
|
if (msg.wParam == IR_STRINGEND)
|
|
{
|
|
if (cchLen <= 0)
|
|
goto WillBeDone; /* no more room to stuff */
|
|
if ((w = EatOneCharacter(hwnd)) == -1)
|
|
goto WillBeDone;
|
|
*lpSp++ = (BYTE)w;
|
|
if (IsDBCSLeadByte((BYTE)w))
|
|
{
|
|
if ((w = EatOneCharacter(hwnd)) == -1)
|
|
{
|
|
/* Bad DBCS sequence - abort */
|
|
lpSp--;
|
|
goto WillBeDone;
|
|
}
|
|
*lpSp++ = (BYTE)w;
|
|
}
|
|
goto WillBeDone;
|
|
}
|
|
|
|
/* Fall through */
|
|
|
|
default:
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* We don't get WM_IME_REPORT + IR_STRINGEND
|
|
* But received string will be OK
|
|
*/
|
|
|
|
WillBeDone:
|
|
|
|
*lpSp = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
/* These are C equivalents to functions that were in INDOS2.ASM */
|
|
|
|
VOID RepMov(
|
|
LPBYTE lpDest,
|
|
LPBYTE lpSrc,
|
|
UINT n)
|
|
{
|
|
while (n--)
|
|
{
|
|
*lpDest++ = *lpSrc++;
|
|
}
|
|
}
|
|
|
|
|
|
VOID RepMovDown(
|
|
LPBYTE lpDest,
|
|
LPBYTE lpSrc,
|
|
UINT n)
|
|
{
|
|
lpDest += n;
|
|
lpSrc += n;
|
|
|
|
lpDest--;
|
|
lpSrc--;
|
|
|
|
while (n--)
|
|
{
|
|
*lpDest-- = *lpSrc--;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
NOEXPORT BOOL NEAR CardKey( INT wParam);
|
|
|
|
/*
|
|
* Hook Proc for the multi line Edit control.
|
|
* In picture mode,
|
|
* WM_SETCURSOR - sets the arrow cursor,
|
|
* mouse msgs - responds to left button down, up, dbl click and mouse move
|
|
* WM_KEYDOWN - responds to VK_UP/DOWN/LEFT/RIGHT/INSERT/DELETE
|
|
* In text mode,
|
|
* implements hot key to move to a card(e.g. using Ctrl+A, goto first/last/
|
|
* next/prev card), by responding to WM_CHAR and WM_KEYDOWN.
|
|
*/
|
|
LONG EditWndProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LONG lParam)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
#if !defined(UNICODE) && defined(JAPAN)
|
|
LPSTR lpP;
|
|
HANDLE hMem;
|
|
HANDLE hClipSave;
|
|
#endif
|
|
|
|
switch (message) {
|
|
|
|
#if !defined(UNICODE) && defined(JAPAN)
|
|
/*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
case WM_IME_REPORT:
|
|
if (EditMode != I_TEXT)
|
|
break;
|
|
switch (wParam)
|
|
{
|
|
case IR_STRING:
|
|
/*OutputDebugString("IR_STRING\r\n");*/
|
|
if (lpP = (LPSTR) GlobalLock((HANDLE)lParam))
|
|
{
|
|
CallWindowProc(lpEditWndProc, hwnd, EM_REPLACESEL, 0, (DWORD)lpP);
|
|
GlobalUnlock((HANDLE)lParam);
|
|
return 1L; /* processed */
|
|
}
|
|
break;
|
|
|
|
case IR_STRINGSTART:
|
|
/* OutputDebugString("IR_STRINGSTART\r\n"); */
|
|
if ((hMem = GlobalAlloc(GMEM_MOVEABLE, 512)) == NULL)
|
|
{
|
|
/* OutputDebugString("Ga failed\r\n");*/
|
|
goto PassMessageOn;
|
|
}
|
|
if ((lpP = (LPSTR) GlobalLock(hMem)) == NULL)
|
|
{
|
|
/* OutputDebugString("Lock failed\r\n"); */
|
|
GlobalFree(hMem);
|
|
goto PassMessageOn;
|
|
}
|
|
if (EatString(hwnd, lpP, 512))
|
|
{
|
|
/* OutputDebugString("Eat ok\r\n"); */
|
|
CallWindowProc(lpEditWndProc, hwnd, EM_REPLACESEL, 0, (DWORD)lpP);
|
|
GlobalUnlock(hMem);
|
|
GlobalFree(hMem);
|
|
break;
|
|
}
|
|
GlobalUnlock(hMem);
|
|
GlobalFree(hMem);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case WM_DROPFILES:
|
|
DoDragDrop(hwnd, (HANDLE)wParam, TRUE);
|
|
break;
|
|
case WM_SETCURSOR:
|
|
/* use arrow cursor when in picture mode */
|
|
if (EditMode == I_OBJECT)
|
|
SetCursor(hArrowCurs);
|
|
else
|
|
goto PassMessageOn;
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_MOUSEMOVE:
|
|
case WM_LBUTTONUP:
|
|
if (EditMode == I_OBJECT)
|
|
BMMouse(hwnd, message, wParam, MYMAKEPOINT(lParam));
|
|
else /* In text mode, pass it to edit control */
|
|
goto PassMessageOn;
|
|
break;
|
|
|
|
case WM_CHAR:
|
|
/* In text mode, Ctrl+'char' acts as a hot key to move to a
|
|
* specific card. Respond to Ctrl+'A' etc */
|
|
if (!CardChar(wParam) && (EditMode == I_TEXT))
|
|
/* If it doesn't move our object, pass it to edit control */
|
|
goto PassMessageOn;
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
/* In text mode, respond to Ctrl+HOME, Ctrl+END(move to first/last card),
|
|
* VK_NEXT/VK_PRIOR(goto next and prev cards).
|
|
* In picture mode, respond to VK_UP/DOWN/LEFT/RIGHT/VK_INSERT/VK_DELETE
|
|
* keys */
|
|
if (!CardKey(wParam) && (EditMode == I_TEXT))
|
|
/* If it doesn't affect our object, ... */
|
|
goto PassMessageOn;
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
BeginPaint(hwnd, &ps);
|
|
CallWindowProc((WNDPROC)lpEditWndProc, hEditWnd, message, (LONG)ps.hdc, 0L);
|
|
CardPaint(ps.hdc);
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
|
|
default:
|
|
PassMessageOn:
|
|
return CallWindowProc((WNDPROC)lpEditWndProc, hEditWnd, message, wParam, lParam);
|
|
}
|
|
return(0L);
|
|
}
|
|
|
|
/*
|
|
* Responds to WM_KEYDOWN message.
|
|
* In text mode,
|
|
* Ctrl+HOME/END - goto first/last card
|
|
* VK_PRIOR/NEXT - goto previous/next card
|
|
*
|
|
* In picture mode,
|
|
* VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_INSERT, VK_DELETE handled
|
|
* in BMKey
|
|
*/
|
|
NOEXPORT BOOL NEAR CardKey( INT wParam)
|
|
{
|
|
switch(wParam)
|
|
{
|
|
case VK_HOME:
|
|
/* Home Beginning of line (don't process)
|
|
* Shft+Home Extend selection to beg. of line (don't process)
|
|
* Ctrl+Home Go to first card (process here)
|
|
*/
|
|
if (GetKeyState(VK_CONTROL) >= 0)
|
|
return(FALSE);
|
|
ScrollCards(hCardWnd, SB_THUMBPOSITION, 0);
|
|
break;
|
|
|
|
case VK_END:
|
|
/* End End of line (don't process)
|
|
* Shft+End Extend selection to end of line (don't process)
|
|
* Ctrl+End Go to last card (process here)
|
|
*/
|
|
if (GetKeyState(VK_CONTROL) >= 0)
|
|
return(FALSE);
|
|
ScrollCards(hCardWnd, SB_THUMBPOSITION, cCards-1);
|
|
break;
|
|
|
|
case VK_PRIOR:
|
|
ScrollCards(hCardWnd, SB_LINEUP, 0);
|
|
break;
|
|
|
|
case VK_NEXT:
|
|
ScrollCards(hCardWnd, SB_LINEDOWN, 0);
|
|
break;
|
|
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
case VK_LEFT:
|
|
case VK_RIGHT:
|
|
case VK_INSERT:
|
|
case VK_DELETE:
|
|
if (EditMode == I_TEXT) /* should be handled by the edit control */
|
|
return(FALSE);
|
|
else
|
|
BMKey((WORD) wParam); /* we will handle this */
|
|
return(TRUE);
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
ScrollCards(hCardWnd, SB_ENDSCROLL, 0);
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* Checks if the user is trying to move to a specific card using a hot key
|
|
* e.g. Ctrl+A will move it to a card starting with A
|
|
*/
|
|
BOOL CardChar(
|
|
int ch)
|
|
{
|
|
int fControl;
|
|
LPCARDHEADER Cards;
|
|
int i;
|
|
int iCard;
|
|
|
|
fControl = (GetKeyState(VK_CONTROL) < 0) && (GetKeyState(VK_SHIFT) < 0);
|
|
if (!fControl || ch >= TEXT(' '))
|
|
return(FALSE);
|
|
|
|
/* convert control char, i.e. from Ctrl+A get 'A' */
|
|
ch += TEXT('A') - 1;
|
|
|
|
Cards = (LPCARDHEADER) GlobalLock(hCards);
|
|
for (i = 0, iCard = iFirstCard+1; i < cCards; ++i, iCard++) {
|
|
if (iCard == cCards)
|
|
iCard = 0;
|
|
if ((TCHAR)(DWORD)CharUpper((LPTSTR)(DWORD)(BYTE)*(Cards[iCard].line)) == ch)
|
|
break;
|
|
}
|
|
GlobalUnlock(hCards);
|
|
|
|
if (i < cCards) /* make sure a card was found */
|
|
ScrollCards(hCardWnd, SB_THUMBPOSITION, iCard);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* this paints the bitmap in the edit window.
|
|
*/
|
|
void CardPaint(
|
|
HDC hDC)
|
|
{
|
|
RECT rc;
|
|
|
|
if (CardPhone == PHONEBOOK || /* list mode */
|
|
!CurCard.lpObject || /* no object to draw */
|
|
fInsertComplete == FALSE) /* InsertObject in progress */
|
|
{
|
|
return;
|
|
}
|
|
|
|
Hourglass(TRUE);
|
|
|
|
/* If RECT is null, reget scaled object size */
|
|
/* This will never happen with a plain static BITMAP */
|
|
if (!CurCard.rcObject.right)
|
|
{
|
|
if (OleQueryBounds(CurCard.lpObject, &rc) != OLE_OK)
|
|
{
|
|
Hourglass(FALSE);
|
|
ErrorMessage(E_BOUNDS_QUERY_FAILED);
|
|
return;
|
|
}
|
|
FixBounds(&rc);
|
|
SetRect(&(CurCard.rcObject),
|
|
CurCard.rcObject.left, CurCard.rcObject.top,
|
|
CurCard.rcObject.left + (rc.right - rc.left),
|
|
CurCard.rcObject.top + (rc.bottom - rc.top));
|
|
}
|
|
|
|
/* Draw the object */
|
|
PicDraw(&CurCard, hDC, FALSE);
|
|
Hourglass(FALSE);
|
|
}
|
|
|
|
/*
|
|
* Delete the ith card by removing its header
|
|
*/
|
|
void DeleteCard(
|
|
int iCard)
|
|
{
|
|
LPCARDHEADER Cards;
|
|
|
|
cCards--;
|
|
Cards = (LPCARDHEADER) GlobalLock(hCards);
|
|
RepMov((LPBYTE)&Cards[iCard], (LPBYTE)&Cards[iCard+1], (cCards-iCard)*sizeof(CARDHEADER));
|
|
GlobalUnlock(hCards);
|
|
|
|
InitPhoneList(hListWnd, iFirstCard);
|
|
}
|
|
|
|
/*
|
|
* Add a card in order in the card array.
|
|
*/
|
|
int AddCurCard(
|
|
void)
|
|
{
|
|
LPCARDHEADER Cards;
|
|
int i;
|
|
|
|
Cards = (LPCARDHEADER) GlobalLock(hCards);
|
|
for (i = 0; i < cCards; i++)
|
|
{
|
|
if (lstrcmp(CurCardHead.line, Cards[i].line) <= 0)
|
|
break;
|
|
}
|
|
|
|
if (i != cCards)
|
|
RepMovDown((LPBYTE)&Cards[i+1], (LPBYTE)&Cards[i], (cCards - i) * sizeof(CARDHEADER));
|
|
|
|
Cards[i] = CurCardHead;
|
|
GlobalUnlock(hCards);
|
|
cCards++;
|
|
/* Set highlight to the new card */
|
|
InitPhoneList(hListWnd, i);
|
|
|
|
return(i);
|
|
}
|
|
|
|
/*
|
|
* save CurCardHead and assorted things??
|
|
*/
|
|
BOOL SaveCurrentCard(
|
|
int iCard)
|
|
{
|
|
LPCARDHEADER Cards;
|
|
|
|
/* save the card if it's dirty */
|
|
/* dirty if bitmap has changed or edittext has changed */
|
|
if (CurCardHead.flags & (FDIRTY+FNEW) || SendMessage(hEditWnd, EM_GETMODIFY, 0, 0L))
|
|
{
|
|
/* get modified text from edit window */
|
|
GetWindowText(hEditWnd, szText, CARDTEXTSIZE);
|
|
if (WriteCurCard(&CurCardHead, &CurCard, szText))
|
|
{
|
|
if (CurCardHead.flags & FDIRTY || SendMessage(hEditWnd, EM_GETMODIFY, 0, 0L))
|
|
fFileDirty = TRUE;
|
|
|
|
SendMessage(hEditWnd, EM_SETMODIFY, FALSE, 0L);
|
|
CurCardHead.flags &= (!FNEW);
|
|
CurCardHead.flags &= (!FDIRTY);
|
|
CurCardHead.flags |= FTMPFILE;
|
|
Cards = (LPCARDHEADER) GlobalLock(hCards);
|
|
Cards[iCard] = CurCardHead;
|
|
GlobalUnlock(hCards);
|
|
}
|
|
else
|
|
return(FALSE);
|
|
}
|
|
if (CurCard.lpObject)
|
|
PicDelete(&CurCard);
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* make card # iCard the current (editable and displayed) card
|
|
*
|
|
* copy the header into CurCardHead (from global memory)
|
|
* copy the bitmap into CurCard (from the file)
|
|
* copy the text into the Edit window (from the file)
|
|
*
|
|
*/
|
|
void SetCurCard(
|
|
int iCard)
|
|
{
|
|
LPCARDHEADER Cards;
|
|
|
|
/* Setting new card, remove undo possibility... */
|
|
DeleteUndoObject();
|
|
/* copy the header info */
|
|
Cards = (LPCARDHEADER) GlobalLock(hCards);
|
|
CurCardHead = Cards[iCard];
|
|
GlobalUnlock(hCards);
|
|
|
|
/* read in the bitmap and text stuff from the file */
|
|
if (ReadCurCardData(&CurCardHead, &CurCard, szText))
|
|
{
|
|
SetEditText(szText);
|
|
DoSetHostNames(CurCard.lpObject, CurCard.otObject);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set edit windows text
|
|
*/
|
|
void SetEditText(
|
|
TCHAR *pText)
|
|
{
|
|
fNeedToUpdateObject = TRUE;
|
|
SendMessage(hEditWnd, WM_SETTEXT, 0, (LONG)pText);
|
|
}
|
|
|
|
int iCardStartScroll;
|
|
int fScrolling = FALSE;
|
|
|
|
/*
|
|
* scroll through the stack of cards
|
|
*
|
|
* this gets called when using the scroll bar control
|
|
* or when a card is selected by clicking on on or
|
|
* when someone presses movement keys
|
|
*
|
|
* the user can hold down a key or a mouse button and cause repetitive
|
|
* scroll messages to be sent. this action will update the headers but
|
|
* the edit window should only be updated when the key or mouse is
|
|
* released. saving of data also follows this.
|
|
* see the fScrolling stuff below.
|
|
*
|
|
* also note: some routines send SB_THUMBPOS messages here (we won't
|
|
* get a SB_ENDSCROLL). This case works because !fScrolling and
|
|
* iCardStartScroll gets set correctly.
|
|
*/
|
|
BOOL ScrollCards(
|
|
HWND hWindow,
|
|
int cmd,
|
|
int pos)
|
|
{
|
|
int OldFirst = iFirstCard; /* note where we started */
|
|
|
|
if (cCards < 2)
|
|
return TRUE; /* only one card, can't scroll */
|
|
|
|
/* two states:
|
|
fScrolling - we are receiving scroll messages (mouse is not released)
|
|
!fScrolling - enter scrolling state, save current position
|
|
*/
|
|
|
|
if (!fScrolling)
|
|
{
|
|
iCardStartScroll = iFirstCard;
|
|
fScrolling = TRUE;
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
/* these cases always change the card and leave us in
|
|
* Scrolling state */
|
|
case SB_LINEUP:
|
|
iFirstCard--; /* next card */
|
|
if (iFirstCard < 0)
|
|
iFirstCard = cCards-1;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
iFirstCard++; /* prev card */
|
|
if (iFirstCard == cCards)
|
|
iFirstCard = 0;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
if (cFSHeads == cCards) /* already at top? */
|
|
break;
|
|
iFirstCard -= cFSHeads;
|
|
if (iFirstCard < 0)
|
|
iFirstCard += cCards; /* a negative number */
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
if (cFSHeads == cCards) /* already at bottom? */
|
|
break;
|
|
iFirstCard += cFSHeads;
|
|
if (iFirstCard >= cCards)
|
|
iFirstCard -= cCards;
|
|
break;
|
|
|
|
/* these cases may change the current card and
|
|
* always leave Scrolling state */
|
|
case SB_THUMBPOSITION:
|
|
iFirstCard = pos; /* for single SB_THUMB calls */
|
|
/* fall through... */
|
|
|
|
case SB_ENDSCROLL:
|
|
fScrolling = FALSE; /* leave scrolling mode */
|
|
|
|
if (iFirstCard != iCardStartScroll)
|
|
{
|
|
if (SaveCurrentCard(iCardStartScroll))
|
|
{
|
|
SetCurCard(iFirstCard);
|
|
}
|
|
else
|
|
{
|
|
iFirstCard = iCardStartScroll;
|
|
return FALSE; /* save failed */
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (iFirstCard != OldFirst) /* did the above change anything? */
|
|
{
|
|
HDC hDC;
|
|
hDC= GetDC( hWindow );
|
|
PaintNewHeaders( hDC ); /* yes, so redraw headers */
|
|
ReleaseDC( hWindow, hDC );
|
|
}
|
|
|
|
return TRUE; /* sucessful scroll */
|
|
}
|
|
|
|
void DoCutCopy(int event)
|
|
{
|
|
if (EditMode == I_TEXT)
|
|
SendMessage(hEditWnd, event == CUT ? WM_CUT : WM_COPY, 0, 0L);
|
|
else if (CurCard.lpObject)
|
|
PicCutCopy(&CurCard, (event == CUT));
|
|
}
|
|
|
|
void DoPaste(int event)
|
|
{
|
|
if (EditMode == I_TEXT) {
|
|
if (!SendMessage(hEditWnd, WM_PASTE, 0, 0L))
|
|
IndexOkError(ECLIPEMPTYTEXT);
|
|
} else
|
|
PicPaste(&CurCard, (event == PASTE), 0);
|
|
}
|
|
|
|
/*
|
|
* update the text in the card headers
|
|
*/
|
|
void PaintNewHeaders( HDC hDC )
|
|
{
|
|
int idCard;
|
|
LPCARDHEADER Cards;
|
|
LPCARDHEADER lpTCards;
|
|
int xCur;
|
|
int yCur;
|
|
int i;
|
|
RECT rect;
|
|
DWORD rgbOld;
|
|
DWORD rgbTextOld;
|
|
HFONT hOldFont;
|
|
|
|
|
|
yCur = yFirstCard - (cScreenHeads - 1) * ySpacing;
|
|
xCur = xFirstCard + (cScreenHeads - 1) * (2 * CharFixWidth);
|
|
idCard = (iFirstCard + cScreenHeads-1) % cCards;
|
|
|
|
Cards = (LPCARDHEADER) GlobalLock(hCards);
|
|
lpTCards = &Cards[idCard];
|
|
|
|
hOldFont= SelectObject(hDC, hFont); // use our selected font
|
|
|
|
/* for all cards with headers showing */
|
|
|
|
rgbOld = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
|
|
rgbTextOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
|
|
for (i = 0; i < cScreenHeads; i++) /* cScreenHeads */
|
|
{
|
|
SetRect(&rect, xCur+1, yCur+1, xCur+CardWidth-1, yCur+ySpacing);
|
|
ExtTextOut(hDC,
|
|
xCur+1, yCur+1+(ExtLeading/2),
|
|
ETO_OPAQUE|ETO_CLIPPED, // use background color as fill
|
|
&rect, // clipping rect
|
|
lpTCards->line, // title
|
|
lstrlen(lpTCards->line), // length of title
|
|
NULL); // interchar spacing
|
|
|
|
xCur -= (2*CharFixWidth);
|
|
yCur += ySpacing;
|
|
lpTCards--;
|
|
idCard--;
|
|
if (idCard < 0)
|
|
{
|
|
idCard = cCards - 1;
|
|
lpTCards = &Cards[idCard];
|
|
}
|
|
}
|
|
SetBkColor(hDC, rgbOld);
|
|
SetTextColor(hDC, rgbTextOld);
|
|
SelectObject(hDC, hOldFont);
|
|
GlobalUnlock(hCards);
|
|
|
|
}
|