|
|
#define OEMRESOURCE // setting this gets OBM_ constants in windows.h
#include <windows.h>
#include "ctls.h"
#pragma hdrstop
#define MyModuleHandle GetModuleHandle( NULL )
#define MYASSERT(x)
#define MyFree(x) LocalFree( x )
PWSTR DuplicateString( PWSTR pszOriginal ) { PWSTR pszCopy;
pszCopy = LocalAlloc( LPTR, ( 1 + lstrlenW( pszOriginal ) ) * sizeof( *pszOriginal ) );
if ( NULL != pszCopy ) { lstrcpy( pszCopy, pszOriginal ); }
return pszCopy; }
////////////////////////////////////////////
//
// Bitmap control
//
////////////////////////////////////////////
PCWSTR szBMPCLASS = L"_mybmp";
LRESULT BmpClassWndProc( IN HWND hwnd, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam );
BOOL InitializeBmpClass( VOID ) { WNDCLASS wc; BOOL b;
if(GetClassInfo(MyModuleHandle,szBMPCLASS,&wc)) { b = TRUE; } else {
wc.lpszClassName = szBMPCLASS; wc.style = CS_GLOBALCLASS; wc.lpfnWndProc = BmpClassWndProc; wc.hInstance = MyModuleHandle; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.cbClsExtra = 0; wc.cbWndExtra = 0;
b = RegisterClass(&wc); }
return(b); }
VOID DestroyBmpClass( VOID ) { WNDCLASS wc;
if(GetClassInfo(MyModuleHandle,szBMPCLASS,&wc)) { //
// Hope there are no more windows using the class!
//
MYASSERT(!FindWindow(szBMPCLASS,NULL)); UnregisterClass(szBMPCLASS,MyModuleHandle); } }
VOID BmpClassPaint( IN HWND hwnd ) { PAINTSTRUCT ps; unsigned BmpId; HDC hdc, hdcMem; HBITMAP hbm,hbmOld; BITMAP bm;
BmpId = GetDlgCtrlID(hwnd);
hdc = BeginPaint(hwnd,&ps); if(hbm = LoadBitmap((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(BmpId))) { GetObject(hbm, sizeof(bm),&bm); if(hdcMem = CreateCompatibleDC(hdc)) { if(hbmOld = SelectObject(hdcMem,hbm)) { BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hdcMem,0,0,SRCCOPY); SelectObject(hdcMem,hbmOld); } DeleteDC(hdcMem); } DeleteObject(hbm); } EndPaint(hwnd,&ps); }
LRESULT BmpClassWndProc( IN HWND hwnd, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { switch(msg) {
case WM_NCCREATE:
SetWindowLong( hwnd, GWL_STYLE, GetWindowLong(hwnd,GWL_STYLE) | WS_BORDER );
return(TRUE);
case WM_PAINT:
BmpClassPaint(hwnd); return(0); }
return(DefWindowProc(hwnd,msg,wParam,lParam)); }
////////////////////////////////////////////
//
// Action item list control
//
////////////////////////////////////////////
//
// Define locations in extra window storage
//
#define AIL_FONT (0)
#define AIL_BOLDFONT (sizeof(LONG))
#define AIL_BOLDITEM (2*sizeof(LONG))
#define AIL_TEXT (3*sizeof(LONG))
#define AIL_LINECOUNT (4*sizeof(LONG))
#define AIL_FREEFONTS (5*sizeof(LONG))
#define AIL_EXTRA 6
PCWSTR szActionItemListClassName = L"$$$ActionItemList";
VOID ActionItemListPaint( IN HWND hwnd ) {
PAINTSTRUCT PaintStruct; PWSTR p,Text; UINT LineCount; HFONT OldFont,Font,BoldFont; UINT HighlightedItem; UINT i; int Length; int y; int yDelta; HBITMAP Bitmap,OldBitmap; BITMAP bitmap; HDC MemoryDC; SIZE Size; RECT rect; int Spacing; #define BORDER 3
if(!BeginPaint(hwnd,&PaintStruct)) { return; }
//
// If no text, nothing to do.
//
if(Text = (PWSTR)GetWindowLong(hwnd,AIL_TEXT)) { LineCount = (UINT)GetWindowLong(hwnd,AIL_LINECOUNT); }
if(!Text || !LineCount) { return; }
//
// Get value indicating which item is to be bolded.
//
HighlightedItem = (UINT)GetWindowLong(hwnd,AIL_BOLDITEM);
//
// Get font handles.
//
Font = (HFONT)GetWindowLong(hwnd,AIL_FONT); BoldFont = (HFONT)GetWindowLong(hwnd,AIL_BOLDFONT);
//
// Select the non-boldface font to get the handle of
// the currently selected font.
//
OldFont = SelectObject(PaintStruct.hdc,Font);
//
// Set text background color.
//
SetBkColor(PaintStruct.hdc,GetSysColor(COLOR_3DFACE));
//
// Load the little triangle bitmap and create a compatible DC for it.
//
Bitmap = LoadBitmap(NULL,MAKEINTRESOURCE(OBM_MNARROW));
if(MemoryDC = CreateCompatibleDC(PaintStruct.hdc)) {
OldBitmap = SelectObject(MemoryDC,Bitmap); GetObject(Bitmap,sizeof(BITMAP),&bitmap); }
Spacing = GetSystemMetrics(SM_CXICON) / 2;
//
// Treat the text as a series of lines and draw each one.
//
p = Text; y = 0; for(i=0; i<LineCount; i++) {
//
// Calculate the line's height based on the boldface font.
// This is used to get to the y coord of the next line.
//
SelectObject(PaintStruct.hdc,BoldFont);
GetClientRect(hwnd,&rect); rect.left = (2 * BORDER) + Spacing; rect.bottom = 0;
DrawText(PaintStruct.hdc,p,lstrlen(p),&rect,DT_CALCRECT|DT_WORDBREAK);
yDelta = rect.bottom + (2*BORDER);
//
// Change font to non-boldface for this line if necessary.
//
if(i != HighlightedItem) { SelectObject(PaintStruct.hdc,Font); }
rect.top = y + BORDER; rect.left = (2 * BORDER) + Spacing; rect.bottom = rect.top + yDelta;
//
// Draw the line's text.
//
Length = lstrlen(p); DrawText(PaintStruct.hdc,p,Length,&rect,DT_WORDBREAK);
//
// Draw the little triangle thing if necessary.
//
if((i == HighlightedItem) && Bitmap && MemoryDC) {
GetTextExtentPoint(PaintStruct.hdc,L"WWWWW",5,&Size);
BitBlt( PaintStruct.hdc, BORDER, y + ((Size.cy - bitmap.bmHeight) / 2) + BORDER, bitmap.bmWidth, bitmap.bmHeight, MemoryDC, 0,0, 0x220326 // (NOT src) AND dest [DSna]
); }
//
// Point to next line's text.
//
p += Length + 1; y += yDelta; }
//
// Clean up.
//
if(OldFont) { SelectObject(PaintStruct.hdc,OldFont); }
if(MemoryDC) { if(OldBitmap) { SelectObject(MemoryDC,OldBitmap); } if(Bitmap) { DeleteObject(Bitmap); } DeleteDC(MemoryDC); }
EndPaint(hwnd,&PaintStruct); }
LRESULT ActionItemListWndProc( IN HWND hwnd, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { LRESULT rc; HFONT OldFont,Font,BoldFont; LOGFONT LogFont; PWSTR Text; PWSTR p; UINT LineCount; BOOL FreeFont,FreeBoldFont;
switch(msg) {
case WM_CREATE:
//
// Create fonts.
//
OldFont = (HFONT)SendMessage(GetParent(hwnd),WM_GETFONT,0,0); if(!OldFont) { //
// Using system font.
//
OldFont = GetStockObject(DEFAULT_GUI_FONT); }
FreeFont = TRUE; FreeBoldFont = TRUE; if(OldFont && GetObject(OldFont,sizeof(LOGFONT),&LogFont)) {
LogFont.lfWeight = 400; Font = CreateFontIndirect(&LogFont); if(!Font) { Font = GetStockObject(DEFAULT_GUI_FONT); FreeFont = FALSE; }
LogFont.lfWeight = 700; BoldFont = CreateFontIndirect(&LogFont); if(!BoldFont) { BoldFont = Font; FreeBoldFont = FALSE; } }
SetWindowLong(hwnd,AIL_FONT,(LONG)Font); SetWindowLong(hwnd,AIL_BOLDFONT,(LONG)BoldFont); SetWindowLong(hwnd,AIL_BOLDITEM,0); SetWindowLong(hwnd,AIL_TEXT,0); SetWindowLong(hwnd,AIL_LINECOUNT,0); SetWindowLong(hwnd,AIL_FREEFONTS,MAKELONG(FreeFont,FreeBoldFont));
rc = 0; break;
case WM_DESTROY: //
// Get rid of fonts we created if necessary.
//
FreeFont = (BOOL)GetWindowLong(hwnd,AIL_FREEFONTS); FreeBoldFont = HIWORD(FreeFont); FreeFont = LOWORD(FreeFont);
if(FreeFont && (Font = (HFONT)GetWindowLong(hwnd,AIL_FONT))) { DeleteObject(Font); }
if(FreeBoldFont && (BoldFont = (HFONT)GetWindowLong(hwnd,AIL_BOLDFONT))) { DeleteObject(BoldFont); }
if(Text = (PWSTR)GetWindowLong(hwnd,AIL_TEXT)) { MyFree(Text); } rc = 0; break;
case WM_SETTEXT: //
// Free old text and remember new text.
//
if(Text = (PWSTR)GetWindowLong(hwnd,AIL_TEXT)) { MyFree(Text); }
LineCount = 0; if(Text = DuplicateString((PVOID)lParam)) { //
// Count lines in the text. This is equal to the number of
// newlines. We require that the last line have a newline
// to be counted.
//
for(LineCount=0,p=Text; *p; p++) {
if(*p == L'\r') { *p = L' '; } else { if(*p == L'\n') { *p = 0; LineCount++; } } } }
//
// Cheat a little: we expect wParam to be the 0-based index
// of the boldfaced line. Callers will have to use SendMessage
// instead of SetWindowText().
//
SetWindowLong(hwnd,AIL_BOLDITEM,(LONG)wParam); SetWindowLong(hwnd,AIL_LINECOUNT,LineCount); SetWindowLong(hwnd,AIL_TEXT,(LONG)Text);
rc = (Text != NULL); break;
case WM_PAINT:
ActionItemListPaint(hwnd); rc = 0; break;
default: rc = DefWindowProc(hwnd,msg,wParam,lParam); break; }
return(rc); }
BOOL RegisterActionItemListControl( IN BOOL Init ) { WNDCLASS wc; BOOL b; static BOOL Registered;
if(Init) { if(Registered) { b = TRUE; } else { wc.style = CS_PARENTDC; wc.lpfnWndProc = ActionItemListWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = AIL_EXTRA * sizeof(LONG); wc.hInstance = MyModuleHandle; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szActionItemListClassName;
if(b = (RegisterClass(&wc) != 0)) { Registered = TRUE; } } } else { if(Registered) { if(b = UnregisterClass(szActionItemListClassName,MyModuleHandle)) { Registered = FALSE; } } else { b = TRUE; } }
return(b); }
|