The document describes a BitBtn library that provides a bitmap button custom control. It includes constants, functions, and procedures for loading bitmaps, handling button states, painting the button, and responding to user input.
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0 ratings0% found this document useful (0 votes)
59 views13 pages
BITBTN
The document describes a BitBtn library that provides a bitmap button custom control. It includes constants, functions, and procedures for loading bitmaps, handling button states, painting the button, and responding to user input.
const ofReserved = 0; { Used by the dialog manager } ofState = 2; ofDownBits = 4; ofUpBits = 6; ofFocUpBits = 8; ofSize = 10; { Amount of window extra bytes to use }
{ GetAppInstance ----------------------------------------------- Returns a handle to the current client application. -------------------------------------------------------------- } function GetAppInstance: THandle; near; assembler; asm PUSH SS CALL GlobalHandle end;
{ IsWorkshopWindow --------------------------------------------- Returns true if the window belongs to Resource Workshop. Used to determine if the control is being edited; allowing the LoadResRW function to be called. -------------------------------------------------------------- } function IsWorkshopWindow(Wnd: HWnd): Boolean; var Parent: HWnd; ClassName: array[0..80] of Char; begin Parent := Wnd; repeat Wnd := Parent; Parent := GetParent(Wnd); until Parent = 0; GetClassName(Wnd, ClassName, SizeOf(ClassName)); IsWorkshopWindow := StrComp(ClassName, 'rwswnd') = 0; end;
{ LoadResRW ---------------------------------------------------- Load a resource from Resource Workshop. Initialized by ListClasses below. -------------------------------------------------------------- } var LoadResRW: TLoad;
{ LoadBitmapRW ------------------------------------------------- Load a bitmap from Resource Workshop. *MUST* be called from inside resource workshop (IsWorkshopWindow must be true). -------------------------------------------------------------- } function LoadBitmapRW(szTitle: PChar): HBitmap; var Res: THandle; Bits: PBitMapInfoHeader; DC: HDC; nColors: Integer;
function GetDInColors(BitCount: Integer): Integer;
begin case BitCount of 1, 3, 4, 8: GetDInColors := 1 shl BitCount; else GetDInColors := 0; end; end;
begin LoadBitmapRW := 0; Res := LoadResRW(rt_Bitmap, szTitle); if Res <> 0 then begin Bits := GlobalLock(Res); if Bits^.biSize = SizeOf(TBitMapInfoHeader) then begin nColors := GetDInColors(Bits^.biBitCount); DC := GetDC(0); if DC <> 0 then begin LoadBitmapRW := CreateDIBitmap(DC, Bits^, cbm_Init, Pointer(LongInt(Bits) + SizeOf(Bits^) + nColors * SizeOf(TRGBQuad)), PBitmapInfo(Bits)^, dib_RGB_Colors); ReleaseDC(0, DC); end; end; GlobalUnlock(Res); GlobalFree(Res); end; end;
{ Get ---------------------------------------------------------- Get a window instance word. -------------------------------------------------------------- } function Get(Ofs: Integer): Word; begin Get := GetWindowWord(HWindow, Ofs); end;
{ SetWord ------------------------------------------------------ Set the value of a window instance word. -------------------------------------------------------------- } procedure SetWord(Ofs: Integer; Val: Word); begin SetWindowWord(HWindow, Ofs, Val); end;
{ State -------------------------------------------------------- Get the button's state word. -------------------------------------------------------------- } function State: Word; begin State := Get(ofState); end;
{ DownBits ----------------------------------------------------- Get the "down" bitmap of the button. -------------------------------------------------------------- } function DownBits: Word; begin DownBits := Get(ofDownBits); end;
{ UpBits ------------------------------------------------------- Get the "up" bitmap of the button. -------------------------------------------------------------- } function UpBits: Word; begin UpBits := Get(ofUpBits); end;
{ FocUpBits ---------------------------------------------------- Get the "focused up" bitmap of the button. -------------------------------------------------------------- } function FocUpBits: Word; begin FocUpBits := Get(ofFocUpBits); end;
{ GetState ----------------------------------------------------- Get the value of a state bit. -------------------------------------------------------------- } function GetState(AState: Word): Boolean; begin GetState := (State and AState) = AState; end;
{ Paint -------------------------------------------------------- Paint the button. Called in responce to a WM_PAINT message and whenever the button changes state (called by Repaint). -------------------------------------------------------------- } procedure Paint(DC: HDC); const coGray = $00C0C0C0; var MemDC: HDC; Bits, Oldbitmap: HBitmap; BorderBrush, OldBrush: HBrush; LogBrush: TLogBrush; Frame: TRect; Height, Width: Integer; begin if (State and (bsMouseDown + bsKeyDown) <> 0) and not GetState(bsMouseUpDown) then Bits := DownBits else if GetState(bsFocus) then Bits := FocUpBits else Bits := UpBits;
{ Draw bitmap } MemDC := CreateCompatibleDC(DC); OldBitmap := SelectObject(MemDC, Bits); GetObject(Bits, Sizeof(Bitmap), @Bitmap); if GetState(bsDisabled) then begin { Gray out the button } OldBrush := SelectObject(DC, CreateSolidBrush(coGray)); PatBlt(DC, bdBorderWidth, bdBorderWidth, Bitmap.bmWidth, Bitmap.bmHeight, PatCopy); DeleteObject(SelectObject(DC, OldBrush)); { Draw the bitmap through a checked brush } LogBrush.lbStyle := bs_Pattern; LogBrush.lbHatch := LoadBitmap(HInstance, MakeIntResource(btDisableBits)); OldBrush := SelectObject(DC, CreateBrushIndirect(LogBrush)); BitBlt(DC, bdBorderWidth, bdBorderWidth, Bitmap.bmWidth, Bitmap.bmHeight, MemDC, 0, 0, $00A803A9 {DPSoa}); DeleteObject(SelectObject(DC, OldBrush)); DeleteObject(LogBrush.lbHatch); end else BitBlt(DC, bdBorderWidth, bdBorderWidth, Bitmap.bmWidth, Bitmap.bmHeight, MemDC, 0, 0, srcCopy); SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC); end;
{ Repaint ------------------------------------------------------ Repaint the button. Called whenever the button changes state. -------------------------------------------------------------- } procedure Repaint; var DC: HDC; begin DC := GetDC(HWindow); Paint(DC); ReleaseDC(HWindow, DC); end;
{ SetState ----------------------------------------------------- Sets the value of a state bit. If the word changes value the button is repainted. -------------------------------------------------------------- } procedure SetState(AState: Word; Enable: Boolean); var OldState, NewState: Word; begin OldState := State; if Enable then NewState := OldState or AState else NewState := OldState and not AState; if NewState <> OldState then begin SetWord(ofState, NewState); Repaint; end; end;
{ InMe --------------------------------------------------------- Returns true if the given point is in within the border of the button. -------------------------------------------------------------- } function InMe(lPoint: Longint): Boolean; var R: TRect; Point: TPoint absolute lPoint; begin GetClientRect(HWindow, R); InflateRect(R, -bdBorderWidth, -bdBorderWidth); InMe := PtInRect(R, Point); end;
{ ButtonPressed ------------------------------------------------ Called when the button is pressed by either the keyboard or by the mouse. -------------------------------------------------------------- } procedure ButtonPressed; begin SetState(bsMouseDown + bsMouseUpDown + bsKeyDown, False); SendMessage(GetParent(HWindow), wm_Command, GetDlgCtrlID(HWindow), Longint(HWindow)); end;
{ LoadBits ----------------------------------------------------- Load the bitmap for the button or the "NO BITMAP" version if it does not exist. -------------------------------------------------------------- } procedure LoadBits(Wrd: Word; MapNumber: Word); var MapBits: HBitmap; begin MapBits := LoadBitmap(HInstance, pChar(MapNumber)); if MapBits = 0 then if IsWorkshopWindow(HWindow) then MapBits := LoadBitmapRW(pChar(MapNumber)) else MapBits := LoadBitmap(GetAppInstance, pChar(MapNumber)); if MapBits = 0 then MapBits := LoadBitmap(HInstance, pChar(MapNumber - Get(gww_ID))); SetWord(Wrd, MapBits); end;
begin BitButtonWinFn := 0; case Message of wm_Create: begin { Detect EGA monitor } DC := GetDC(0); if (GetSystemMetrics(sm_CYScreen) < 480) or (GetDeviceCaps(DC, numColors) < 16) then BitsNumber := 2000 + Get(gww_ID) else BitsNumber := 1000 + Get(gww_ID); ReleaseDC(0, DC);
with PCreateStruct(lParam)^ do begin if style and $1F = bs_DefPushButton then SetState(bsDefault, True); if style and ws_Disabled <> 0 then SetState(bsDisabled, True); end; end; wm_NCDestroy: begin { Destroy all saved bitmaps before the button is destroyed } BitButtonWinFn := DefWindowProc(HWindow, Message, wParam, lParam); DeleteObject(UpBits); DeleteObject(DownBits); DeleteObject(FocUpBits); end; wm_Paint: begin BeginPaint(HWindow, PS); Paint(PS.hDC); EndPaint(HWindow, PS); end; wm_EraseBkGnd: begin { Squelch the painting of the background to eliminate flicker } end; wm_Enable: SetState(bsDisabled, wParam <> 0); wm_SetFocus: SetState(bsFocus, True); wm_KillFocus: SetState(bsFocus or bsKeyDown or bsMouseDown or bsMouseUpDown, False); wm_KeyDown: if (wParam = $20) and not GetState(bsKeyDown) and not GetState(bsMouseDown) then SetState(bsKeyDown, True); wm_KeyUp: if (wParam = $20) and GetState(bsKeyDown) then ButtonPressed; wm_LButtonDblClk, wm_LButtonDown: if InMe(lParam) and not GetState(bsKeyDown) then begin if GetFocus <> HWindow then SetFocus(HWindow); SetState(bsMouseDown, True); SetCapture(HWindow); end; wm_MouseMove: if GetState(bsMouseDown) then SetState(bsMouseUpDown, not InMe(lParam)); wm_LButtonUp: if GetState(bsMouseDown) then begin ReleaseCapture; if not GetState(bsMouseUpDown) then ButtonPressed else SetState(bsMouseDown + bsMouseUpDown, False); end;
{ *** Handling the rest of these messages are what, at least for the dialog manager, makes a push button a push button. ***} wm_GetDlgCode: { Sent by the dialog manager to determine the control kind of a child window. Returning dlgc_DefPushButton or dlgc_UndefPushButton causes the dialog manager to treat the control like a button, sending the bm_SetStyle message to move the default button style to the currenly focused button.
The dlgc_Button constant is not documented by Microsoft
(however, it is documented for OS/2 PM, and appears to work the same). If this constant is or'd in, the windows dialog manager will take care of all accelerator key processing, sending bm_SetState and bm_SetStyle messages when an acclerator key is pressed. There is a side effect to using the message, however, the dialog manager messes with the word at offset 0 from the user Window words. }
if GetState(bsDefault) then BitButtonWinFn:= dlgc_DefPushButton or dlgc_Button else BitButtonWinFn := dlgc_UndefPushButton or dlgc_Button; bm_GetState: BitButtonWinFn := Integer(GetState(bsKeyDown)); bm_SetState: SetState(bsKeyDown, wParam <> 0); bm_SetStyle: { Sent by the dialog manager when the button receives or looses focus and is not the default button, or when another button receives the focus and this button is the default button. } SetState(bsDefault, wParam = bs_DefPushButton); else BitButtonWinFn := DefWindowProc(HWindow, Message, wParam, lParam); end; end;
{ BitBtnInfo --------------------------------------------------- Return the information about the capabilities of the bit button class. -------------------------------------------------------------- } function BitBtnInfo: THandle; export; var hInfo: THandle; Info: PRWCtlInfo; begin hInfo := GlobalAlloc(gmem_Share or gmem_ZeroInit, SizeOf(TRWCtlInfo)); if hInfo <> 0 then begin Info := GlobalLock(hInfo); with Info^ do begin wVersion := $100; { Version 1.00 } wCtlTypes := 2; { 2 types } StrCopy(szClass, 'BitButton'); StrCopy(szTitle, 'Button');
{ Normal (Un-default) push button type }
with ctType[0] do begin wWidth := 63 or $8000; wHeight := 39 or $8000; StrCopy(szDescr, 'Push Button'); dwStyle := bs_PushButton or ws_TabStop; hToolBit := LoadBitmap(HInstance, MakeIntResource(btUndefBits)); hDropCurs := LoadCursor(HInstance, MakeIntResource(crUndefCurs)); end;
{ Default push button type }
with ctType[1] do begin wWidth := 63 or $8000; wHeight := 39 or $8000; StrCopy(szDescr, 'Default Push Button'); dwStyle := bs_DefPushButton or ws_TabStop; hToolBit := LoadBitmap(HInstance, MakeIntResource(btDefBits)); hDropCurs := LoadCursor(HInstance, MakeIntResource(crDefCurs)); end; end; GlobalUnlock(hInfo); end; BitBtnInfo := hInfo; end;
type PParamRec = ^TParamRec; TParamRec = record CtlStyle: THandle; IdToStr: TIdToStr; StrToId: TStrToId; end;
{ BitBtnStyleDlg ----------------------------------------------- Style dialog's dialog hook. Used by the dialog and called when the control is double-clicked inside the dialog editor. -------------------------------------------------------------- } function BitBtnStyleDlg(HWindow: HWnd; Message: Word; wParam: Word; lParam: Longint): Longint; export; const Prop = 'Prop'; var hRec: THandle; Rec: PParamRec; Style: PCtlStyle; S: array[0..256] of Char; Radio: Integer; begin case Message of wm_InitDialog: begin hRec := LoWord(lParam); Rec := GlobalLock(hRec); Style := GlobalLock(Rec^.CtlStyle); SetProp(HWindow, Prop, hRec); with Rec^, Style^ do begin { Set caption } SetDlgItemText(HWindow, idCaption, szTitle);
{ Set control id } IdToStr(wId, S, SizeOf(S)); SetDlgItemText(HWindow, idControlId, S);
{ Set type radio buttons }
if dwStyle and $F = bs_DefPushButton then Radio := idDefaultButton else Radio := idPushButton; CheckRadioButton(HWindow, idDefaultButton, idPushButton, Radio);
{ Initialize Tab Stop check box }
CheckDlgButton(HWindow, idTabStop, Integer(dwStyle and ws_TabStop <> 0));
{ Initialize Disabled check box }
CheckDlgButton(HWindow, idDisabled, Integer(dwStyle and ws_Disabled <> 0));
{ Initialize Group check box }
CheckDlgButton(HWindow, idGroup, Integer(dwStyle and ws_Group <> 0)); end; GlobalUnlock(Rec^.CtlStyle); GlobalUnlock(hRec); end; wm_Command: case wParam of idCancel: EndDialog(HWindow, 0); idOk: begin hRec := GetProp(HWindow, Prop); Rec := GlobalLock(hRec); Style := GlobalLock(Rec^.CtlStyle); with Rec^, Style^ do begin { Get caption } GetDlgItemText(HWindow, idCaption, szTitle, SizeOf(szTitle));
{ Get control id } GetDlgItemText(HWindow, idControlId, S, SizeOf(S)); wId := StrToId(S);
{ Get button type }
if IsDlgButtonChecked(HWindow, idDefaultButton) <> 0 then dwStyle := bs_DefPushButton else dwStyle := bs_PushButton; { Get tab stop } if IsDlgButtonChecked(HWindow, idTabStop) <> 0 then dwStyle := dwStyle or ws_TabStop;
{ Get disabled } if IsDlgButtonChecked(HWindow, idDisabled) <> 0 then dwStyle := dwStyle or ws_Disabled;
{ Get group } if IsDlgButtonChecked(HWindow, idGroup) <> 0 then dwStyle := dwStyle or ws_Group; end; GlobalUnlock(Rec^.CtlStyle); GlobalUnlock(hRec); EndDialog(HWindow, 1); end; else BitBtnStyleDlg := 0; end; wm_Destroy: RemoveProp(HWindow, Prop); else BitBtnStyleDlg := 0; end; end;
{ BitBtnStyle -------------------------------------------------- The function will bring up a dialog box to modify the style of the button. Called when the button is double-clicked in the dialog editor. -------------------------------------------------------------- } function BitBtnStyle(hWindow: HWnd; CtlStyle: THandle; StrToId: TStrToId; IdToStr: TIdToStr): Bool; export; var hRec: THandle; Rec: PParamRec; hFocus: HWnd; begin BitBtnStyle := False; hRec := GlobalAlloc(gmem_Share, SizeOf(TParamRec)); if hRec <> 0 then begin Rec := GlobalLock(hRec); Rec^.IdToStr := IdToStr; Rec^.StrToId := StrToId; Rec^.CtlStyle := CtlStyle; GlobalUnlock(hRec);
hFocus := GetFocus; BitBtnStyle := Bool(DialogBoxParam(HInstance, MakeIntResource(idButtonStyle), HWindow, @BitBtnStyleDlg, hRec)); if hFocus <> 0 then SetFocus(hFocus); GlobalFree(hRec); end; end;
{ BitBtnFlags -------------------------------------------------- Called to decompose the style double word into the .RC script expression that it represents. This only needs to decompose the style bits added to the style double word, it need not decompose the, for example, the ws_XXX bits. The expression returned must be a valid .RC expression (i.e. C syntax, case sensitive). -------------------------------------------------------------- } function BitBtnFlags(Style: LongInt; Buff: PChar; BuffLength: Word): Word; export; begin if Style and $F = bs_DefPushButton then StrLCopy(Buff, 'BS_DEFPUSHBUTTON', BuffLength) else StrLCopy(Buff, 'BS_PUSHBUTTON', BuffLength); BitBtnFlags := StrLen(Buff); end;
{ ListClasses -------------------------------------------------- Called by Resource Workshop retrieve the information necessary to edit the custom controls contain in this DLL. This is an alternative to the Microsoft xxxStyle convention. -------------------------------------------------------------- } function ListClasses(szAppName: PChar; wVersion: Word; fnLoad: TLoad; fnEdit: TEdit): THandle; export; var hClasses: THandle; Classes: PCtlClassList; begin LoadResRW := fnLoad; hClasses := GlobalAlloc(gmem_Share or gmem_ZeroInit, SizeOf(Integer) + SizeOf(TRWCtlClass)); if hClasses <> 0 then begin Classes := GlobalLock(hClasses); with Classes^ do begin nClasses := 1; with Classes[0] do begin fnInfo := BitBtnInfo; fnStyle := BitBtnStyle; fnFlags := BitBtnFlags; end; end; GlobalUnlock(hClasses); end; ListClasses := hClasses; end;
exports ListClasses, BitButtonWinFn;
var Class: TWndClass;
begin with Class do begin lpszClassName := 'BitButton'; hCursor := LoadCursor(0, idc_Arrow); lpszMenuName := nil; style := cs_HRedraw or cs_VRedraw or cs_DblClks or cs_GlobalClass; lpfnWndProc := TFarProc(@BitButtonWinFn); hInstance := System.hInstance; hIcon := 0; cbWndExtra := ofSize; cbClsExtra := 0; hbrBackground := 0; end; RegisterClass(Class); end.