home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
winutil
/
adg_4_6
/
spin.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-21
|
9KB
|
285 lines
/****************************************************************************
Module name: Spin.C
Programmer : Jeffrey M. Richter.
*****************************************************************************/
#include "..\nowindws.h"
#define OEMRESOURCE
#undef NOCOLOR
#undef NOCTLMGR
#undef NOGDI
#undef NOKERNEL
#undef NOLSTRING
#undef NOMEMMGR
#undef NORASTEROPS
#undef NOUSER
#undef NOVIRTUALKEYCODES
#undef NOWINMESSAGES
#undef NOWINOFFSETS
#undef NOWINSTYLES
#include <windows.h>
#include "spin.h"
#define CBWNDEXTRA (8)
#define GWL_RANGE (0)
#define GWW_CRNTVALUE (4)
#define GWW_TRIANGLEDOWN (6)
#define SPNM_SCROLLVALUE (WM_USER + 500)
// Time delay between scrolling events in milliseconds.
#define TIME_DELAY (150)
typedef enum { TD_NONE, TD_UP, TD_DOWN } TRIANGLEDOWN;
HANDLE _hInstance = NULL;
char _szControlName[] = "Spin";
static BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance);
LONG FAR PASCAL SpinWndFn (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam);
/********* Window's Dynamic-Link Library Initialization Routines ***********/
BOOL FAR PASCAL LibMain (HANDLE hModule, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine) {
BOOL fOk;
_hInstance = hModule;
if (wHeapSize != 0) UnlockData(0); // Let data segment move
fOk = RegisterControlClass(hModule);
return(fOk); // return TRUE if initialization is successful
}
int FAR PASCAL WEP (int nSystemExit) {
switch (nSystemExit) {
case WEP_SYSTEM_EXIT: // System is shutting down.
break;
case WEP_FREE_DLL: // Usage count is zero (0)
break;
}
UnregisterClass(_szControlName, _hInstance);
return(1); // WEP function successful.
}
static BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance) {
WNDCLASS wc;
wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = SpinWndFn;
wc.cbClsExtra = 0;
wc.cbWndExtra = CBWNDEXTRA;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = COLOR_BTNFACE + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = _szControlName;
return(RegisterClass(&wc));
}
static LONG NEAR PASCAL NotifyParent (HWND hWnd, WORD wNotifyCode) {
LONG lResult;
lResult = SendMessage(GetParent(hWnd), WM_COMMAND,
GetWindowWord(hWnd, GWW_ID),
MAKELONG(hWnd, wNotifyCode));
return(lResult);
}
LONG FAR PASCAL SpinWndFn (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam) {
LONG lResult = 0;
HDC hDC;
POINT pt;
RECT rc;
PAINTSTRUCT ps;
int nCrntVal, nNewVal, x, y;
TRIANGLEDOWN TriangleDown, OldTriangleDown;
DWORD dwTime, dwRange;
BOOL fWrap;
switch (wMsg) {
case WM_GETDLGCODE:
lResult = DLGC_STATIC;
break;
case WM_CREATE: // lParam == &CreateStruct
SendMessage(hWnd, SPNM_SETRANGE, 0, MAKELONG(0, 0));
SendMessage(hWnd, SPNM_SETCRNTVALUE, 0, 0);
break;
case WM_PAINT:
// Calling BeginPaint sends a WM_ERASEBKGND message. Because that
// message is not trapped, DefWindowProc uses the system color
// COLOR_BTNFACE because it was specified in the hbrBackground
// member of the WNDCLASS structure when this class was registered.
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
x = rc.right / 2;
y = rc.bottom / 2;
// Draw middle separator bar
MoveTo(hDC, 0, y);
LineTo(hDC, rc.right, y);
// Whenever a DC is retrieved, it is created with a WHITE_BRUSH
// by default, we must change this to a BLACK_BRUSH so that we
// can fill the triangles.
SelectObject(hDC, GetStockObject(BLACK_BRUSH));
// Draw top triangle & fill it in
MoveTo(hDC, x, 2);
LineTo(hDC, rc.right - 2, y - 2);
LineTo(hDC, 2, y - 2);
LineTo(hDC, x, 2);
FloodFill(hDC, x, y - 3, RGB(0, 0, 0));
// Draw bottom triangle & fill it in
MoveTo(hDC, 2, y + 2);
LineTo(hDC, rc.right - 2, y + 2);
LineTo(hDC, x, rc.bottom - 2);
LineTo(hDC, 2, y + 2);
FloodFill(hDC, x, y + 3, RGB(0, 0, 0));
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
// Get coordinates for the Spin Button's window.
GetClientRect(hWnd, &rc);
if ((int) HIWORD(lParam) < rc.bottom / 2) { // Up arrow
TriangleDown = TD_UP;
// Change coordinates so rectangle includes only the top-half
// of the window.
rc.bottom /= 2;
} else {
TriangleDown = TD_DOWN;
// Change coordinates so rectangle includes only the bottom-half
// of the window.
rc.top = rc.bottom / 2;
}
// Save which triangle the mouse was clicked over.
SetWindowWord(hWnd, GWW_TRIANGLEDOWN, TriangleDown);
// Invert the top or bottom half of the window where the
// mouse was clicked.
hDC = GetDC(hWnd);
InvertRect(hDC, &rc);
ReleaseDC(hWnd, hDC);
SetCapture(hWnd);
// Subtract TIME_DELAY so that action is performed at least once.
dwTime = GetTickCount() - TIME_DELAY;
do {
// If TIME_DELAY hasn't passed yet, test loop condition.
if (dwTime + TIME_DELAY > GetTickCount())
continue;
// Time delay has passed, scroll value in Spin Button.
SendMessage(hWnd, SPNM_SCROLLVALUE, 0, 0l);
// Get last time when scroll occurred.
dwTime = GetTickCount();
// Check if left mouse button is still down.
} while (GetAsyncKeyState(VK_LBUTTON) & 0x8000);
ReleaseCapture();
// Invalidate the entire window. This will force Windows to send
// a WM_PAINT message restoring the window to its original colors.
InvalidateRect(hWnd, NULL, TRUE);
break;
case SPNM_SCROLLVALUE:
// Get the location of the mouse.
GetCursorPos(&pt);
// Convert the point from screen coordinates to client coordinates.
ScreenToClient(hWnd, &pt);
// If the point is NOT is Spin's client area, nothing to do.
GetClientRect(hWnd, &rc);
if (!PtInRect(&rc, pt)) break;
// Get the Spin Button's current value and range,
nNewVal = (int) SendMessage(hWnd, SPNM_GETCRNTVALUE, 0, 0l);
nCrntVal = nNewVal;
dwRange = SendMessage(hWnd, SPNM_GETRANGE, 0, 0l);
// Get Spin Button's styles and test if the "wrap" flag is set.
fWrap = (BOOL) (GetWindowLong(hWnd, GWL_STYLE) & SPNS_WRAP);
// Determine whether the up- or down- triangle was selected.
OldTriangleDown = GetWindowWord(hWnd, GWW_TRIANGLEDOWN);
// Determine whether the mouse is now over the up- or down- triangle.
TriangleDown = (pt.y < rc.bottom / 2) ? TD_UP : TD_DOWN;
// If the user has switched triangles, invert the entire rectangle.
// This restores the half that was inverted in the WM_LBUTTONDOWN
// message and inverts the new half.
if (OldTriangleDown != TriangleDown) {
hDC = GetDC(hWnd);
InvertRect(hDC, &rc);
ReleaseDC(hWnd, hDC);
}
if (TriangleDown == TD_UP) {
// If value is not at top of range, increment it.
if ((int) HIWORD(dwRange) > nCrntVal) nNewVal++;
else {
// If value at top of range and the "wrap" flag is set,
// set the value to the bottom of the range.
if (fWrap) nNewVal = (int) LOWORD(dwRange);
}
} else {
// If value is not at bottom of range, decrement it.
if ((int) LOWORD(dwRange) < nCrntVal) nNewVal--;
else {
// If value at bottom of range and the "wrap" flag is set,
// set the value to the top of the range.
if (fWrap) nNewVal = (int) HIWORD(dwRange);
}
}
// If the value has been changed, set the new value.
if (nNewVal != nCrntVal)
SendMessage(hWnd, SPNM_SETCRNTVALUE, nNewVal, 0l);
// Set the new triangle that is down for the next call to here.
SetWindowWord(hWnd, GWW_TRIANGLEDOWN, TriangleDown);
break;
case SPNM_SETRANGE:
SetWindowLong(hWnd, GWL_RANGE, lParam);
break;
case SPNM_GETRANGE:
lResult = GetWindowLong(hWnd, GWL_RANGE);
break;
case SPNM_SETCRNTVALUE:
SetWindowWord(hWnd, GWW_CRNTVALUE, wParam);
NotifyParent(hWnd, SPNN_VALUECHANGE);
break;
case SPNM_GETCRNTVALUE:
lResult = (LONG) GetWindowWord(hWnd, GWW_CRNTVALUE);
break;
default:
lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
break;
}
return(lResult);
}