home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_03_02
/
3n02018a
< prev
next >
Wrap
Text File
|
1991-12-16
|
17KB
|
541 lines
/* fader.c - main code for fader custom control */
#include <windows.h>
#include "fader.h"
#define NO_DRAG 0 /* Values of FADER_THUMBSTATE */
#define DRAG 1
#define FADER_THUMB_OFFSET 2 /* Distance in pixels from edge */
/* Window extra bytes */
#define FADER_RANGE 0 /* logical range values returned */
#define FADER_VALUE 4 /* Current logical value */
#define FADER_THUMBSTATE 6 /* DRAG or NO_DRAG */
#define FADER_WNDEXTRA 8 /* Total # of window extra bytes */
HANDLE hGlobFaderInstance = NULL;
char szGlobControlName[] = "Fader";
/* Forward declarations for completeness */
static BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance);
LONG FAR PASCAL FaderWndFn (HWND hWnd, WORD wMsg,
WORD wParam, LONG lParam);
int GetThumbHeight(int iTotalHeight);
void GetFaderThumbRect(HWND hWnd, LPRECT pRc, LPRECT pThumbRect,
int iCurPos);
int XlatPosPhysicalToLogical(LONG lLogRange, int iPhysMax,
int iPhysMin, int iCurPos);
int XlatPosLogicalToPhysical(LONG lLogRange, int iPhysMax,
int iPhysMin, int iLogPos);
static void DrawCaret(HDC hDC, LPRECT lprc);
static void PaintFader(HWND hWnd);
/* These are DLL initialization and control functions */
BOOL FAR PASCAL LibMain (HANDLE hModule, WORD wDataSeg,
WORD wHeapSize, LPSTR lpszCmdLine)
{
hGlobFaderInstance = hModule;
if (wHeapSize != 0) /* Moveable DS */
UnlockData(0);
return RegisterControlClass(hModule);
}
int FAR PASCAL WEP (int nSystemExit)
{
UnregisterClass(szGlobControlName, hGlobFaderInstance);
return 1; /* never fails */
}
/* This function can be static if you only plan to use it
in a DLL */
BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance)
{
WNDCLASS wc;
wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = FaderWndFn;
wc.cbClsExtra = 0;
wc.cbWndExtra = FADER_WNDEXTRA;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_SIZENS);
wc.hbrBackground = COLOR_WINDOW + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = szGlobControlName;
return RegisterClass(&wc);
}
/* This function is handy for sending the FDRN_... messages
back to the parent. Note that FDRN_THUMBTRACK is disabled
unless FDRS_TRACK is enabled */
static LONG NEAR PASCAL NotifyParent (HWND hWnd,
WORD wNotifyCode)
{
BOOL bSend=TRUE;
if (wNotifyCode == FDRN_THUMBTRACK)
bSend = (BOOL) (GetWindowLong(hWnd, GWL_STYLE) & FDRS_TRACK);
if (bSend)
return SendMessage(GetParent(hWnd), WM_COMMAND,
GetWindowWord(hWnd, GWW_ID),
MAKELONG(hWnd, wNotifyCode));
else
return 0;
}
/* This is the main "window function" procedure, it is called
sometimes by the SDK Dialog box editor */
LONG FAR PASCAL FaderWndFn (HWND hWnd, WORD wMsg,
WORD wParam, LONG lParam)
{
LONG lResult = 0;
HDC hDC;
POINT pt;
RECT rc;
int iLogPos;
int iOldLogPos;
int iPhyPos;
int iMaxLog;
int iMinLog;
RECT thumb_rect;
LONG lLogRange;
int iThumbHalf;
HANDLE hNewBrush, hOldBrush;
switch (wMsg) {
case WM_CREATE:
SendMessage(hWnd, FDRM_SETRANGE, 0, MAKELONG(0, 100));
SendMessage(hWnd, FDRM_SETLOGVALUE, 0, 0);
break;
case WM_GETDLGCODE: /* interface query by dialog manager */
lResult = DLGC_WANTARROWS;
break;
case WM_PAINT:
PaintFader(hWnd);
break;
case WM_SETFOCUS: /* receiving the keyboard focus */
case WM_KILLFOCUS: /* losing the keyboard focus */
/* calculate update region */
GetClientRect(hWnd, &rc);
iLogPos = GetWindowWord(hWnd, FADER_VALUE);
GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect,
iLogPos);
if (thumb_rect.left == rc.left)
break;
/* force a repaint */
hDC = GetDC( hWnd );
if (hDC) {
/* define appropriate brush & text colors */
if (hNewBrush = (HBRUSH)SendMessage( GetParent(hWnd),
WM_CTLCOLOR, hDC, MAKELONG(hWnd,CTLCOLOR_BTN) ) )
hOldBrush = SelectObject(hDC,hNewBrush);
else
hOldBrush = NULL;
/* draw caret */
DrawCaret(hDC, (LPRECT)&thumb_rect);
/* restore original brush */
if ( hNewBrush ) {
SelectObject( hDC, hOldBrush );
DeleteObject( hNewBrush );
}
/* release display context */
ReleaseDC( hWnd, hDC );
}
break;
case WM_KEYDOWN: /* process virtual key code */
GetClientRect(hWnd, &rc);
iLogPos = (int)GetWindowWord(hWnd, FADER_VALUE);
iOldLogPos = iLogPos;
lLogRange = GetWindowLong(hWnd, FADER_RANGE);
iMaxLog = HIWORD(lLogRange);
iMinLog = LOWORD(lLogRange);
switch (wParam) {
case VK_HOME : /* home key */
iLogPos = iMinLog;
break;
case VK_END : /* end key */
iLogPos = iMaxLog;
break;
case VK_LEFT : /* cursor left key */
case VK_DOWN : /* cursor down key */
if (iLogPos < iMaxLog)
iLogPos++;
break;
case VK_UP : /* cursor up key */
case VK_RIGHT : /* cursor right key */
if (iLogPos > iMinLog)
iLogPos--;
break;
case VK_PRIOR : /* page up key */
iLogPos -= (iMaxLog - iMinLog) / 8;
if (iLogPos < iMinLog)
iLogPos = iMinLog;
break;
case VK_NEXT : /* page down key */
iLogPos += (iMaxLog - iMinLog) / 8;
if (iLogPos > iMaxLog)
iLogPos = iMaxLog;
break;
default : /* something else */
break;
}
if (iLogPos != iOldLogPos) /* did it change? */
{
SendMessage(hWnd, FDRM_SETLOGVALUE, iLogPos, 0);
NotifyParent(hWnd, FDRN_THUMBTRACK);
/* Invalidate old position */
GetFaderThumbRect(hWnd, (LPRECT)&rc,
(LPRECT)&thumb_rect, iOldLogPos);
InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
/* Invalidate new position */
GetFaderThumbRect(hWnd, (LPRECT)&rc,
(LPRECT)&thumb_rect, iLogPos);
InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
}
break;
case WM_LBUTTONDOWN:
GetClientRect(hWnd, &rc);
iLogPos = GetWindowWord(hWnd, FADER_VALUE);
GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
pt = MAKEPOINT(lParam);
/* is the mouse in the "hot" rectangle? */
if ((thumb_rect.top <= pt.y) && (thumb_rect.bottom >= pt.y) &&
(thumb_rect.left <= pt.x) && (thumb_rect.right >= pt.x)) {
SetWindowWord(hWnd, FADER_THUMBSTATE, DRAG);
hDC = GetDC(hWnd);
InvertRect(hDC, (LPRECT)&thumb_rect);
ReleaseDC(hWnd, hDC);
NotifyParent(hWnd, FDRN_THUMBTRACK);
/* grab focus if necessary */
if ( GetFocus() != hWnd )
SetFocus( hWnd );
/* Lock mouse on to this window */
SetCapture(hWnd);
}
break;
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
/* Nothing to do if not in drag! */
if ((wMsg == WM_MOUSEMOVE) &&
(GetWindowWord(hWnd, FADER_THUMBSTATE) != DRAG) ) {
lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
break;
}
/* set the new current position and ask for redraw */
pt = MAKEPOINT(lParam);
GetClientRect(hWnd, &rc);
iLogPos = GetWindowWord(hWnd, FADER_VALUE);
lLogRange = GetWindowLong(hWnd, FADER_RANGE);
/* Invalidate old position */
GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
iPhyPos = pt.y;
iThumbHalf = GetThumbHeight(rc.bottom)/2;
if (iPhyPos < iThumbHalf)
iPhyPos = iThumbHalf;
if (iPhyPos > rc.bottom-iThumbHalf)
iPhyPos = rc.bottom-iThumbHalf;
iLogPos = XlatPosPhysicalToLogical(lLogRange,
rc.bottom-iThumbHalf, rc.top+iThumbHalf, iPhyPos);
GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
SetWindowWord(hWnd, FADER_VALUE, iLogPos);
NotifyParent(hWnd, FDRN_THUMBTRACK);
if (wMsg == WM_LBUTTONUP) {
SetWindowWord(hWnd, FADER_THUMBSTATE, NO_DRAG);
NotifyParent(hWnd, FDRN_ENDFADER);
ReleaseCapture();
}
break;
case FDRM_SETRANGE:
GetClientRect(hWnd, &rc);
InvalidateRect(hWnd, (LPRECT)&rc, TRUE);
SetWindowLong(hWnd, FADER_RANGE, lParam);
break;
case FDRM_GETRANGE:
lResult = GetWindowLong(hWnd, FADER_RANGE);
break;
case FDRM_SETLOGVALUE:
GetClientRect(hWnd, &rc);
InvalidateRect(hWnd, (LPRECT)&rc, TRUE);
SetWindowWord(hWnd, FADER_VALUE, wParam);
break;
case FDRM_GETLOGVALUE:
lResult = GetWindowWord(hWnd, FADER_VALUE);
break;
case FDRM_GETPHYSVALUE:
GetClientRect(hWnd, &rc);
iThumbHalf = GetThumbHeight(rc.bottom)/2;
lLogRange = GetWindowLong(hWnd, FADER_RANGE);
iLogPos = GetWindowWord(hWnd, FADER_VALUE);
lResult = (long) XlatPosLogicalToPhysical(lLogRange,
rc.bottom-iThumbHalf, rc.top+iThumbHalf, iLogPos);
break;
case FDRM_SETPHYSVALUE:
GetClientRect(hWnd, &rc);
iThumbHalf = GetThumbHeight(rc.bottom)/2;
lLogRange = GetWindowLong(hWnd, FADER_RANGE);
iLogPos = XlatPosPhysicalToLogical(lLogRange,
rc.bottom-iThumbHalf, rc.top+iThumbHalf, wParam);
SetWindowWord(hWnd, FADER_VALUE, iLogPos);
InvalidateRect(hWnd, NULL, TRUE);
break;
default:
lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
break;
}
return(lResult);
}
/* This is a "helper" function which draws the entire fader */
static void PaintFader(HWND hWnd)
{
PAINTSTRUCT ps;
HANDLE hOldPen;
HANDLE hNewBrush, hOldBrush;
HANDLE hMyParent;
RECT thumb_rect;
int x_center, y_coord;
int iLogPos;
int iPhyPos;
int iThumbHalf;
LONG lLogRange;
HDC hDC;
RECT rc;
/* Default system color is COLOR_BTNFACE from WNDCLASS structure */
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
hOldPen = SelectObject( hDC,
CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOWFRAME)) );
/* define appropriate brush & text colors */
hMyParent = GetParent(hWnd);
if (hNewBrush = (HBRUSH)SendMessage( hMyParent, WM_CTLCOLOR,
ps.hdc, MAKELONG(hWnd,CTLCOLOR_FADER) ) )
hOldBrush = SelectObject(ps.hdc,hNewBrush);
else
hOldBrush = NULL;
/* Draws with horizontal symmetry */
x_center = rc.right / 2;
/* draw fader slot (clockwise) */
MoveTo(hDC, x_center, 1);
LineTo(hDC, x_center+1, 2);
LineTo(hDC, x_center+1, rc.bottom-2);
LineTo(hDC, x_center, rc.bottom-1);
LineTo(hDC, x_center-1, rc.bottom-2);
LineTo(hDC, x_center-1, 2);
LineTo(hDC, x_center, 1);
/* draw gridlines (top to bottom, left to right) */
for (y_coord=3; y_coord < rc.bottom-3; y_coord+=3) {
/* Left half first */
MoveTo(hDC, 1, y_coord);
LineTo(hDC, x_center-1, y_coord);
/* Then right half */
MoveTo(hDC, x_center+2, y_coord);
LineTo(hDC, rc.right-1, y_coord);
}
/* draw filled box and then dividing line */
iThumbHalf = GetThumbHeight(rc.bottom)/2;
iLogPos = GetWindowWord(hWnd, FADER_VALUE);
lLogRange = GetWindowLong(hWnd, FADER_RANGE);
iPhyPos = XlatPosLogicalToPhysical(lLogRange, rc.bottom-iThumbHalf,
rc.top+iThumbHalf, iLogPos);
GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
/* restore original brush */
DeleteObject( SelectObject(hDC,hOldBrush) );
/* now go to 3D button face brush */
hOldBrush = SelectObject( hDC,
CreateSolidBrush(GetSysColor(COLOR_BTNFACE)) );
Rectangle(hDC, thumb_rect.left, thumb_rect.top,
thumb_rect.right, thumb_rect.bottom);
DeleteObject( SelectObject(hDC,hOldBrush) );
if (iThumbHalf > 2) /* Big enough for 3D paint */
{
DeleteObject( SelectObject(hDC,hOldPen) );
hOldPen = SelectObject( hDC,
CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOW)) );
MoveTo(hDC, thumb_rect.left+1, thumb_rect.bottom-1);
LineTo(hDC, thumb_rect.left+1, thumb_rect.top+1);
LineTo(hDC, thumb_rect.right-1, thumb_rect.top+1);
DeleteObject( SelectObject(hDC,hOldPen) );
hOldPen = SelectObject( hDC,
CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNSHADOW)) );
MoveTo(hDC, thumb_rect.right-1, thumb_rect.top+1);
LineTo(hDC, thumb_rect.right-1, thumb_rect.bottom-1);
LineTo(hDC, thumb_rect.left+1, thumb_rect.bottom-1);
}
/* restore original pen */
DeleteObject( SelectObject(hDC,hOldPen) );
DeleteObject( SelectObject(hDC,hOldBrush) );
EndPaint(hWnd, &ps);
}
/* Thumb height is magically 1/8th of window height */
int GetThumbHeight(int iTotalHeight)
{
return max(iTotalHeight/8, 2);
}
/* The fader button is always 1/8th the heighth of the window
and 1/2 the width of the window */
void GetFaderThumbRect(HWND hWnd, LPRECT pRc,
LPRECT pThumbRect, int iLogPos)
{
int x_center;
int iPhyPos;
int iThumbHalf;
LONG lLogRange;
lLogRange = GetWindowLong(hWnd, FADER_RANGE);
iThumbHalf = GetThumbHeight(pRc->bottom) / 2;
iPhyPos = XlatPosLogicalToPhysical(lLogRange,
pRc->bottom - iThumbHalf, pRc->top + iThumbHalf,
iLogPos);
x_center = pRc->right / 2;
pThumbRect->left = x_center / 2;
pThumbRect->top = iPhyPos - iThumbHalf;
pThumbRect->right = (3 * x_center) / 2;
pThumbRect->bottom = iPhyPos + iThumbHalf;
}
/* This "helper" function maps from pixel coordinates to
logical positions */
int XlatPosPhysicalToLogical(LONG lLogRange, int iPhysMax,
int iPhysMin, int iPhyPos)
{
int iLogMin;
int iLogMax;
int iResult;
double dScale;
iLogMax = HIWORD(lLogRange);
iLogMin = LOWORD(lLogRange);
dScale = (double)(iPhysMax - iPhyPos) /
(double)(iPhysMax - iPhysMin);
iResult = (int) ((double)iLogMin + (iLogMax-iLogMin)*(1-dScale));
return iResult;
}
/* This "helper" function maps from logical positions to
physical pixel coordinates */
int XlatPosLogicalToPhysical(LONG lLogRange, int iPhysMax,
int iPhysMin, int iLogPos)
{
int iLogMin;
int iLogMax;
int iResult;
double dScale;
iLogMax = HIWORD(lLogRange);
iLogMin = LOWORD(lLogRange);
dScale = (double)(iLogMax - iLogPos) /
(double)(iLogMax - iLogMin);
iResult = (int) ((double)iPhysMin + (iPhysMax-iPhysMin)*(1-dScale));
return iResult;
}
/* The "caret" is a way of highlighting the controls which are
active and inactive. Note that a ones-complement is used so we
don't need to know the previous state */
void DrawCaret(HDC hDC, LPRECT lprc)
{
HBRUSH hOldBrush;
int iWidth;
int iHeight;
if (lprc->bottom - lprc->top < 4)
return;
/* initialize display context */
hOldBrush = (HBRUSH)SelectObject( hDC,
GetStockObject(GRAY_BRUSH) );
/* draw caret */
iWidth = lprc->right - lprc->left;
iHeight = lprc->bottom - lprc->top;
PatBlt( hDC, lprc->left+1, lprc->top+1, iWidth-2, 3, PATINVERT );
PatBlt( hDC, lprc->right-4, lprc->top+1, 3, iHeight-2, PATINVERT );
PatBlt( hDC, lprc->left+1, lprc->bottom-4, iWidth-2, 3, PATINVERT );
PatBlt( hDC, lprc->left+1, lprc->top+1, 3, iHeight-2, PATINVERT );
/* restore display context */
SelectObject( hDC, hOldBrush );
}