[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]
{
From: jmillard@nmsu.edu (James B. Millard)
: Howdy...yet another wacky question here. Anyone have any sample code to
: create a custom object? Like a spin button, for example. Can you create a
: button in resource workshop that's not a borland style button OR a windows
: style button....i.e. A windows style button with a bitmap on it. If you
: can tell me, I'll be your friend forever. :)
Here is an "interface" unit and a "spin" control dll, written in pascal.
I have not included the RW interface functions, because I haven't written
them yet (and I may not).
Let me say a little bit about the control. It is probably not like the normal
spin control in that it only includes the up and down buttons. It was written
to provide an addon spin control to an existing edit object I already have.
In the resource workshop, create a window next to the edit you want to have
the spin control for, rename the class to "JBM_SpinButton". Then have the
edit control send a message to the spin control before the inherited setup
window is called. This message is the WM_SPINSETEDIT shown below, the
WPARAM should be the HWindow of the edit control. This associates the edit
control with the spin control - the spin control will ensure it is properly
aligned. When the spin button gets a mouse click it sends the edit control
a WM_SPINUP or WM_SPINDOWN message as appropriate, whatever you do with it is
up to you. (It doesn't have to be an edit window for that matter...)
At the very least, it provides a working example of a control created in
TP. (Note the bitmaps are included after the spin.dll file... as spin.rc)
If you have any questions, just email me.
*******************************************************************************
File: spinlib.pas
*******************************************************************************
}
Unit SpinLib;
Interface
Uses WinTypes, WinProcs;
{* messages used by spin control and edit control}
Const WM_SPINSETEDIT = WM_USER + 500;
WM_SPINUP = WM_USER + 501;
WM_SPINDOWN = WM_USER + 502;
{* State flags}
STATE_NOSPIN = $0000;
STATE_SPINUP = $0001;
STATE_SPINDOWN = $0002;
STATE_CAPTURE = $0010;
{* record used by spin control}
Type PSpinStruct = ^TSpinStruct;
TSpinStruct = Record
hwndNotify : HWnd;
wState : Word;
Count : Integer;
End;
Procedure LoadSpinLibrary;
Implementation
Var hSpin : THandle;
OldExitProc : Pointer;
{* procedure to load "spin.dll"}
Procedure LoadSpinLibrary;
Begin
hSpin:=LoadLibrary('spin.dll');
End;
{* new exit procedure to automatically unload "spin.dll"}
Procedure SpinExit; Far;
Begin
ExitProc:=OldExitProc;
If (hSpin<>0) Then FreeLibrary(hSpin);
End;
Begin
OldExitProc:=ExitProc;
ExitProc:=@SpinExit;
hSpin:=0;
End.
*******************************************************************************
File: spin.pas
*******************************************************************************
{
Windows's "spin" control by Brad Millard, JBM, P.O. Box 3648, University Park,
NM 88003
There is no warranty, no license, or restrictions, use at your own risk, feel
free to
distribute...
If you find any bugs, please let me know... jmillard@nmsu.edu
}
Library SpinCtl;
{$R SPIN.RES}
Uses WinProcs, WinTypes, Win31, SpinLib;
Const ID_SPINTIMER = 1000;
{***** Spin Button painting procedure *****}
Procedure Paint(AWnd : HWnd; DC : HDC; SS : PSpinStruct);
Var bm, obm : HBitMap;
mdc : HDC;
tbm : TBitMap;
Begin
{* Get state and load the correct bitmap}
Case (SS^.wState AND $000F) Of
STATE_NOSPIN : bm:=LoadBitMap(HInstance, 'SPIN_NOSPIN');
STATE_SPINUP : bm:=LoadBitMap(HInstance, 'SPIN_UP');
STATE_SPINDOWN : bm:=LoadBitMap(HInstance, 'SPIN_DOWN');
End;
{* If the bitmap is OK, then paint}
If (bm<>0) Then Begin
GetObject(bm, SizeOf(TBitMap), @tbm);
mdc:=CreateCompatibleDC(DC);
obm:=SelectObject(mdc, bm);
BitBlt(DC, 0, 0, tbm.bmWidth, tbm.bmHeight, mdc, 0, 0, SRCCOPY);
SelectObject(mdc, obm);
DeleteObject(bm);
DeleteDC(mdc);
End;
End;
{* function GetState returns the state constant depending on mouse hit
position}
Function GetState(AWnd : HWnd; WParam : Word; LParam : LongInt; SS :
PSpinStruct) : Word;
Var r : TRect;
Begin
GetClientRect(AWnd, r);
If (PtInRect(r, TPoint(LParam))) Then Begin
If (TPoint(LParam).Y>12) Then GetState:=STATE_SPINDOWN
Else GetState:=STATE_SPINUP;
End
Else GetState:=0;
End;
{* notifies the edit control (hwndNotify) and increments the notification
count}
Function NotifyWnd(AWnd : HWnd; SS : PSpinStruct) : LongInt;
Begin
NotifyWnd:=0;
If (SS<>NIL) Then With SS^ Do Begin
Case (wState AND $000F) Of
STATE_SPINUP : NotifyWnd:=SendMessage(hwndNotify, WM_SPINUP, AWnd,
Count);
STATE_SPINDOWN : NotifyWnd:=SendMessage(hwndNotify, WM_SPINDOWN, AWnd,
Count);
End;
Inc(Count);
End;
End;
{***** Message Specific Procedures *****}
{* paints the button in the current state}
Function wmPaint(AWnd : HWnd; SS : PSpinStruct) : LongInt;
Var PS : TPaintStruct;
Begin
BeginPaint(AWnd, PS);
Paint(AWnd, PS.hDC, SS);
EndPaint(AWnd, PS);
wmPaint:=0;
End;
{* sets focus to hwndNotify, sets capture, notifies hwndNotify of the first
hit,
and resets the count, also starts timer for continuous mouse hits, then
paints
the new state}
Function wmLButtonDown(AWnd : HWnd; WParam : Word; LParam : LongInt) : LongInt;
Var dc : HDC;
ss : PSpinStruct;
Begin
ss:=PSpinStruct(GetWindowLong(AWnd, 0));
If (ss<>NIL) Then With ss^ Do Begin
SetFocus(hwndNotify);
SetCapture(AWnd);
wState:=STATE_CAPTURE OR GetState(AWnd, WParam, LParam, ss);
NotifyWnd(AWnd, ss);
Count:=-1;
SetTimer(AWnd, ID_SPINTIMER, 40, NIL);
dc:=GetDC(AWnd);
Paint(AWnd, dc, ss);
ReleaseDC(AWnd, dc);
End;
wmLButtonDown:=0;
End;
{* if the button has set capture, paints the button in the correct state}
Function wmMouseMove(AWnd : HWnd; WParam : Word; LParam : LongInt) : LongInt;
Var dc : HDC;
ss : PSpinStruct;
r : TRect;
ns : Word;
Begin
ss:=PSpinStruct(GetWindowLong(AWnd, 0));
If (ss<>NIL) Then With ss^ Do Begin
If (wState AND STATE_CAPTURE = STATE_CAPTURE) Then Begin
ns:=GetState(AWnd, WParam, LParam, ss);
{* only paint if we have to...}
If (ns<>wState AND $000F) Then Begin
wState:=STATE_CAPTURE OR ns;
dc:=GetDC(AWnd);
Paint(AWnd, dc, ss);
ReleaseDC(AWnd, dc);
End;
End;
End;
wmMouseMove:=0;
End;
{* Cleans up -- releases capture, repaints, and kills the timer}
Function wmLButtonUp(AWnd : HWnd; WParam : Word; LParam : LongInt) : LongInt;
Var dc : HDC;
ss : PSpinStruct;
Begin
ss:=PSpinStruct(GetWindowLong(AWnd, 0));
If (ss<>NIL) Then With ss^ Do Begin
If (wState AND STATE_CAPTURE = STATE_CAPTURE) Then Begin
KillTimer(AWnd, ID_SPINTIMER);
wState:=0;
dc:=GetDC(AWnd);
Paint(AWnd, dc, ss);
ReleaseDC(AWnd, dc);
ReleaseCapture;
End;
End;
wmLButtonUp:=0;
End;
{* Responds to timer messages when capturing. Counts negative for 12 counts.
When the count is negative, the hwndNotify is not "spun" (except for the
initial hit). When the count reaches -13, it is reset to 0 and then
hwndNotify is spun on each timer message. This provides the delay after
the first mouse click}
Function wmTimer(AWnd : HWnd; WParam : Word; LParam : LongInt) : LongInt;
Var ss : PSpinStruct;
Begin
ss:=PSpinStruct(GetWindowLong(AWnd, 0));
With ss^ Do Begin
If (wState AND STATE_CAPTURE <> 0) AND (hwndNotify<>0) Then Begin
If (Count<0) Then Dec(Count);
If (Count<-12) OR (Count>0) Then Begin
Count:=0;
NotifyWnd(AWnd, ss);
End;
End;
End;
wmTimer:=0;
End;
{* This message is recieved from the edit control before either are shown. The
spin control calculates it's correct position and moves itself accordingly.}
Function wmSpinSetEdit(AWnd : HWnd; WParam : Word; LParam : LongInt) : LongInt;
Var ss : PSpinStruct;
r : TRect;
x, y : Integer;
Begin
ss:=PSpinStruct(GetWindowLong(AWnd, 0));
If (ss<>NIL) Then With ss^ Do Begin
hwndNotify:=WParam;
GetWindowRect(hwndNotify, r);
MapWindowPoints(0, GetParent(AWnd), r, 2);
x:=r.Right + 6;
y:=r.Top + (r.Bottom - r.Top - 23) DIV 2 - 1;
MoveWindow(AWnd, x, y, 17, 23, False);
End;
wmSpinSetEdit:=0;
End;
{***** Spin control Window Procedure *****}
Function SpinWndProc(AWnd : HWnd; Msg, WParam : Word; LParam : LongInt) :
LongInt; Export;
Var SpinStruct : PSpinStruct;
Begin
SpinWndProc:=0;
Case Msg Of
WM_CREATE : Begin
{* Create the TSpinStruct and set it at the extra bytes}
SpinStruct:=PSpinStruct(GetWindowLong(AWnd, 0));
GetMem(SpinStruct, SizeOf(TSpinStruct));
If (SpinStruct<>NIL) Then SpinStruct^.wState:=0;
SetWindowLong(AWnd, 0, LongInt(SpinStruct));
End;
WM_DESTROY : Begin
{* Get rid of TSpinStruct}
SpinStruct:=PSpinStruct(GetWindowLong(AWnd, 0));
If (SpinStruct<>NIL) Then FreeMem(SpinStruct, SizeOf(TSpinStruct));
End;
WM_PAINT : Begin
SpinStruct:=PSpinStruct(GetWindowLong(AWnd, 0));
If (SpinStruct<>NIL) Then SpinWndProc:=wmPaint(AWnd, SpinStruct);
End;
WM_GETDLGCODE : SpinWndProc:=DLGC_BUTTON;
WM_SPINSETEDIT : SpinWndProc:=wmSpinSetEdit(AWnd, WParam, LParam);
WM_LBUTTONDOWN : SpinWndProc:=wmLButtonDown(AWnd, WParam, LParam);
WM_MOUSEMOVE : SpinWndProc:=wmMouseMove(AWnd, WParam, LParam);
WM_LBUTTONUP : SpinWndProc:=wmLButtonUp(AWnd, WParam, LParam);
WM_TIMER : SpinWndProc:=wmTimer(AWnd, WParam, LParam);
Else SpinWndProc:=DefWindowProc(AWnd, Msg, WParam, LParam);
End;
End;
{***** Class Registration Procedure *****}
Procedure RegisterSpinClass;
Var w : TWndClass;
Begin
w.cbClsExtra := 0;
{* reserve extra space for TSpinStruct}
w.cbWndExtra := SizeOf(Pointer);
{* this is the DLL instance, I guess..., it works...}
w.hInstance := System.hInstance;
w.hIcon := 0;
w.hCursor := LoadCursor(0, idc_Arrow);
{* Since we use a bitmap that covers the whole window, don't mess with the
background.}
w.hbrBackground := 0;
w.lpszMenuName := NIL;
w.lpszClassName := 'JBM_SpinButton';
w.style := cs_HRedraw or cs_VRedraw or cs_GlobalClass;
w.lpfnWndProc := @SpinWndProc;
RegisterClass(w);
End;
Exports
SpinWndProc;
Begin
{* register the class when the library is loaded}
RegisterSpinClass;
End.
*******************************************************************************
File: spin.rc
*******************************************************************************
SPIN_DOWN BITMAP
BEGIN
'42 4D 8A 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 11 00 00 00 17 00 00 00 01 00 04 00 00 00'
'00 00 14 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 10 00 00 00 00 00 00 00 00 00 BF 00 00 BF'
'00 00 00 BF BF 00 BF 00 00 00 BF 00 BF 00 BF BF'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'
'00 00 08 77 77 77 77 77 77 77 00 00 00 00 08 77'
'77 77 77 77 77 77 0F 00 00 00 08 77 77 77 77 77'
'77 77 00 00 00 00 08 77 77 77 70 77 77 77 00 00'
'00 00 08 77 77 77 00 07 77 77 00 00 00 00 08 77'
'77 70 00 00 77 77 00 00 00 00 08 77 77 00 00 00'
'07 77 00 00 00 00 08 77 77 77 77 77 77 77 00 00'
'00 00 08 77 77 77 77 77 77 77 00 00 00 00 08 88'
'88 88 88 88 88 88 00 00 00 00 07 70 00 00 00 00'
'00 88 00 00 00 00 0F F7 77 77 77 77 77 88 00 00'
'00 00 0F F7 77 77 77 77 77 88 00 00 00 00 0F F7'
'70 00 00 00 77 88 00 00 00 00 0F F7 77 00 00 07'
'77 88 0F 00 00 00 0F F7 77 70 00 77 77 88 00 00'
'00 00 0F F7 77 77 07 77 77 88 00 00 00 00 0F F7'
'77 77 77 77 77 88 00 00 00 00 0F F7 77 77 77 77'
'77 88 00 00 00 00 0F FF FF FF FF FF FF F8 00 00'
'00 00 0F FF FF FF FF FF FF FF 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00'
END
SPIN_NOSPIN BITMAP
BEGIN
'42 4D 8A 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 11 00 00 00 17 00 00 00 01 00 04 00 00 00'
'00 00 14 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 10 00 00 00 00 00 00 00 00 00 BF 00 00 BF'
'00 00 00 BF BF 00 BF 00 00 00 BF 00 BF 00 BF BF'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'
'00 00 0F 88 88 88 88 88 88 88 00 00 00 00 0F F8'
'88 88 88 88 88 88 0F 00 00 00 0F F7 77 77 77 77'
'77 88 00 00 00 00 0F F7 77 77 77 77 77 88 00 00'
'00 00 0F F7 77 77 07 77 77 88 00 00 00 00 0F F7'
'77 70 00 77 77 88 00 00 00 00 0F F7 77 00 00 07'
'77 88 00 00 00 00 0F F7 70 00 00 00 77 88 00 00'
'00 00 0F F7 77 77 77 77 77 88 00 00 00 00 0F F7'
'77 77 77 77 77 88 00 00 00 00 07 70 00 00 00 00'
'00 88 00 00 00 00 0F F7 77 77 77 77 77 88 00 00'
'00 00 0F F7 77 77 77 77 77 88 00 00 00 00 0F F7'
'70 00 00 00 77 88 00 00 00 00 0F F7 77 00 00 07'
'77 88 0F 00 00 00 0F F7 77 70 00 77 77 88 00 00'
'00 00 0F F7 77 77 07 77 77 88 00 00 00 00 0F F7'
'77 77 77 77 77 88 00 00 00 00 0F F7 77 77 77 77'
'77 88 00 00 00 00 0F FF FF FF FF FF FF F8 00 00'
'00 00 0F FF FF FF FF FF FF FF 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00'
END
SPIN_UP BITMAP
BEGIN
'42 4D 8A 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 11 00 00 00 17 00 00 00 01 00 04 00 00 00'
'00 00 14 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 10 00 00 00 00 00 00 00 00 00 BF 00 00 BF'
'00 00 00 BF BF 00 BF 00 00 00 BF 00 BF 00 BF BF'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'
'00 00 0F 88 88 88 88 88 88 88 00 00 00 00 0F F8'
'88 88 88 88 88 88 01 00 00 00 0F F7 77 77 77 77'
'77 88 00 00 00 00 0F F7 77 77 77 77 77 88 00 00'
'00 00 0F F7 77 77 07 77 77 88 00 00 00 00 0F F7'
'77 70 00 77 77 88 00 00 00 00 0F F7 77 00 00 07'
'77 88 00 00 00 00 0F F7 70 00 00 00 77 88 00 00'
'00 00 0F F7 77 77 77 77 77 88 00 00 00 00 0F F7'
'77 77 77 77 77 88 00 00 00 00 08 88 88 88 88 88'
'88 88 00 00 00 00 08 77 77 77 77 77 77 77 00 00'
'00 00 08 77 77 00 00 00 07 77 00 00 00 00 08 77'
'77 70 00 00 77 77 00 00 00 00 08 77 77 77 00 07'
'77 77 01 00 00 00 08 77 77 77 70 77 77 77 00 00'
'00 00 08 77 77 77 77 77 77 77 00 00 00 00 08 77'
'77 77 77 77 77 77 00 00 00 00 08 77 77 77 77 77'
'77 77 00 00 00 00 08 77 77 77 77 77 77 77 00 00'
'00 00 08 88 88 88 88 88 88 88 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00'
END
[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]