Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

573 lines
14 KiB

/////////////////////////////////////////////////////////////////////////////
// LB.C
//
// Simple owner draw list box modified for Row major ordering for
// displaying Control Panel ICONs across rows first before starting
// another row. This is different from how USER does their list
// boxes. They go in Column major order when allowing for multiple
// columns.
//
// History:
// 01/15/89 toddla Created
// Tue Jan 15 1991 -by- MichaelE
// Added generating WM_CHARTOITEM message.
// 10:30 on Tues 04 Feb 1992 -by- Steve Cathcart [stevecat]
// Updated code to latest Win 3.1 sources
// 18:30 on Fri 24 Jun 1994 -by- Steve Cathcart [stevecat]
// Changed to work better with Window Full Drag on
//
// Copyright (C) 1990-1994 Microsoft Corporation
//
/////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include "lb.h"
#define BOUND(x,min,max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
#define SWAP(x,y) ((x)^=(y)^=(x)^=(y))
#define MIN(x,y) (((x) <= (y)) : x ? y)
#define ALIGNB(x) (((x) + 7) & ~0x07)
#define MAX_LB 200 // max items in a list-box for now
#define GWL_HANDLE 0
#define LONG2POINT(l, pt) (pt.y = (int) HIWORD(l), pt.x = (int) LOWORD(l))
#define EXPORT FAR PASCAL _export
#define PUBLIC FAR PASCAL
#define LBH(hwnd) (HANDLE)(GetWindowLong(hwnd,GWL_HANDLE))
#define LBP(hwnd) ((PLB)LBH(hwnd))
LRESULT APIENTRY lbWndProc (HWND hwnd, UINT msg, WPARAM wParam, LONG lParam);
#define SCROLLWIDTH (GetSystemMetrics(SM_CXVSCROLL) - GetSystemMetrics(SM_CXBORDER))
/*--------------------------------------------------------------------------*\
| lbInit (hPrev,hInst ) |
| |
| Description: |
| This is called when the application is first loaded into |
| memory. It performs all initialization. |
| |
| Arguments: |
| hPrev instance handle of previous instance |
| hInst instance handle of current instance |
| |
| Returns: |
| TRUE if successful, FALSE if not |
| |
\*--------------------------------------------------------------------------*/
BOOL PUBLIC lbInit (HANDLE hInst)
{
WNDCLASS cls;
cls.hCursor = LoadCursor (NULL, IDC_ARROW);
cls.hIcon = NULL;
cls.lpszMenuName = NULL;
cls.lpszClassName = LBCLASS;
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
cls.hInstance = hInst;
// [stevecat] - remove the CS_HREDRAW style for FULL Drag
// cls.style = CS_HREDRAW | CS_DBLCLKS; // | CS_VREDRAW;
cls.style = CS_DBLCLKS; // CS_HREDRAW | CS_VREDRAW;
cls.lpfnWndProc = lbWndProc;
cls.cbClsExtra = 0;
cls.cbWndExtra = sizeof(HANDLE);
RegisterClass(&cls);
return TRUE;
}
LONG lbNotifyParent (PLB plb, UINT msg, DWORD wParam, LONG lParam)
{
if(plb->hwndOwner)
return SendMessage (plb->hwndOwner, msg, wParam, lParam);
return 0L;
}
void lbCmdNotify (PLB plb, WORD wNotify)
{
lbNotifyParent (plb, WM_COMMAND, MAKELONG(plb->id, wNotify), (LONG)plb->hwnd);
}
BOOL lbDeleteItem (PLB plb, int i)
{
DELETEITEMSTRUCT di;
if (!plb || i < 0 || i >= plb->nItems)
return FALSE;
di.CtlType = ODT_LISTBOX;
di.CtlID = plb->id;
di.itemID = i;
di.hwndItem = plb->hwnd;
di.itemData = plb->lData[i];
lbNotifyParent (plb, WM_DELETEITEM, 0, (LONG)&di);
plb->nItems--;
for (; i < plb->nItems; i++)
plb->lData[i] = plb->lData[i+1];
return TRUE;
}
void lbItemRect (PLB plb, int i, RECT* prc)
{
if (!plb || !plb->nx || i < 0 || i >= plb->nItems)
return;
prc->left = (i % plb->nx) * plb->dx;
prc->right = prc->left + plb->dx;
prc->top = (i / plb->nx) * plb->dy;
prc->top -= plb->dyScroll * plb->dy;
prc->bottom = prc->top + plb->dy;
}
int lbItemFromPoint (PLB plb, POINT pt)
{
int i;
pt.y += plb->dyScroll * plb->dy;
if (!plb || !plb->dx || !plb->dy)
return -1;
if (pt.x > plb->dx * plb->nx)
return -1;
i = (pt.x / plb->dx);
i += (pt.y / plb->dy) * plb->nx;
if (i < 0 || i >= plb->nItems)
i = -1;
return i;
}
BOOL lbDrawItem (PLB plb, HDC hdc, int i, int itemAction)
{
DRAWITEMSTRUCT di;
BOOL fGetDC;
if (!plb || i < 0 || i >= plb->nItems)
return FALSE;
if (fGetDC = !hdc)
{
hdc = GetDC (plb->hwnd);
lbNotifyParent (plb, WM_CTLCOLORLISTBOX, (DWORD)hdc, (LONG)plb->hwnd);
}
lbItemRect (plb, i, &di.rcItem);
if (RectVisible (hdc, &di.rcItem))
{
di.CtlType = ODT_LISTBOX;
di.CtlID = plb->id;
di.itemID = i;
di.itemAction = itemAction;
di.itemState = 0;
di.hwndItem = plb->hwnd;
di.hDC = hdc;
di.itemData = plb->lData[i];
if (i == plb->iCurSel)
di.itemState |= ODS_SELECTED;
if (plb->flb & LB_FOCUS)
di.itemState |= ODS_FOCUS;
lbNotifyParent (plb, WM_DRAWITEM, 0, (LONG)&di);
}
if (fGetDC)
ReleaseDC (plb->hwnd,hdc);
return TRUE;
}
void GetRealClientRect (HWND hwnd, PRECT prc)
{
DWORD dwStyle;
dwStyle = GetWindowLong (hwnd, GWL_STYLE);
GetClientRect (hwnd, prc);
#if 0
if (dwStyle & WS_HSCROLL)
prc->bottom += GetSystemMetrics (SM_CYHSCROLL);
#endif
if (dwStyle & WS_VSCROLL)
prc->right += SCROLLWIDTH;
}
void lbCalcSizes (PLB plb, RECT *prc)
{
plb->nx = prc->right / plb->dx;
if (plb->nx == 0)
plb->nx = 1;
plb->ny = (plb->nItems + plb->nx-1) / plb->nx ;
plb->nyScroll = plb->ny - (prc->bottom / plb->dy);
if (plb->nyScroll < 0)
plb->nyScroll = 0;
}
void lbSize (PLB plb)
{
RECT rc;
int ix;
if (!plb || !plb->dx)
return;
GetRealClientRect (plb->hwnd, &rc);
//
// Save current number of items per row
//
ix = plb->nx;
lbCalcSizes (plb, &rc);
if (plb->nyScroll)
{
rc.right -= SCROLLWIDTH;
lbCalcSizes (plb, &rc);
}
SetScrollRange (plb->hwnd, SB_VERT, 0, plb->nyScroll, TRUE);
if (plb->dyScroll > plb->nyScroll)
{
plb->dyScroll = plb->nyScroll;
InvalidateRect (plb->hwnd, NULL, TRUE);
return;
}
//
// Force a redraw of listbox contents if horizontal size changes
// by enough to allow more or less icons per row.
//
if (ix != plb->nx)
{
InvalidateRect (plb->hwnd, NULL, TRUE);
}
}
void lbPaint (PLB plb, HDC hdc)
{
int i;
HBRUSH hbr;
RECT rc;
if (!plb)
return;
GetClientRect (plb->hwnd, &rc);
hbr = (HBRUSH)lbNotifyParent (plb, WM_CTLCOLORLISTBOX, (DWORD)hdc, (LONG)plb->hwnd);
FillRect (hdc, &rc, hbr);
for (i=0; i < plb->nItems; i++)
lbDrawItem (plb, hdc, i, ODA_DRAWENTIRE);
}
void lbShowItem (PLB plb, int i)
{
RECT rc;
int row;
int rows;
GetClientRect (plb->hwnd, &rc);
row = (i / plb->nx);
rows= (rc.bottom / plb->dy);
if (row < plb->dyScroll)
SendMessage(plb->hwnd, WM_VSCROLL, MAKELONG(SB_THUMBPOSITION, row), (LONG)plb->hwnd);
else if (row >= plb->dyScroll+rows)
SendMessage(plb->hwnd, WM_VSCROLL, MAKELONG(SB_THUMBPOSITION, row-rows+1), (LONG)plb->hwnd);
}
BOOL lbCreate (HWND hwnd)
{
MEASUREITEMSTRUCT mi;
HANDLE h;
PLB plb;
h = LocalAlloc (LPTR, sizeof(LB) + MAX_LB * sizeof(LONG));
if (!h)
return FALSE;
SetWindowLong (hwnd, GWL_HANDLE, (LONG)h);
plb = LBP(hwnd);
mi.CtlType = ODT_LISTBOX;
mi.CtlID = plb->id;
mi.itemID = (UINT) (int) -1;
mi.itemWidth = 1;
mi.itemHeight = 1;
mi.itemData = 0l;
plb->hwnd = hwnd;
plb->hwndOwner = GetParent (hwnd);
plb->id = GetWindowLong (hwnd, GWL_ID);
//plb->nx = 0;
//plb->nItems = 0;
//plb->dyScroll = 0;
//plb->flb = 0;
//plb->iCurSel = 0;
lbNotifyParent (plb, WM_MEASUREITEM, 0, (LONG)&mi);
plb->dx = mi.itemWidth;
plb->dy = mi.itemHeight;
SetScrollRange (plb->hwnd, SB_HORZ, 0, 0, FALSE);
SetScrollRange (plb->hwnd, SB_VERT, 0, 0, FALSE);
return TRUE;
}
/*--------------------------------------------------------------------------*\
| lbWndProc (hwnd, msg, wParam, lParam)
|
| Description:
| This is called when the application is first loaded into
| memory. It performs all initialization.
|
| Arguments:
| hPrev instance handle of previous instance
| hInst instance handle of current instance
|
| Returns:
| TRUE if successful, FALSE if not
|
\*--------------------------------------------------------------------------*/
LRESULT APIENTRY lbWndProc (HWND hwnd, UINT msg, WPARAM wParam, LONG lParam)
{
PAINTSTRUCT ps;
HANDLE h;
PLB plb;
int i;
int dn,iPos,iMax;
POINT pt;
plb = LBP(hwnd);
switch (msg)
{
case WM_CREATE:
if (!lbCreate (hwnd))
return -1L;
break;
case WM_LBUTTONDOWN:
if (plb->flb & LB_CAPTURE)
return 0L;
plb->flb |= LB_CAPTURE;
SetFocus (hwnd);
SetCapture (hwnd);
// fall through
case WM_TIMER:
// fall through
case WM_MOUSEMOVE:
if (plb->flb & LB_CAPTURE)
{
LONG2POINT(lParam, pt);
i = lbItemFromPoint (plb, pt);
if(i >= 0)
SendMessage (hwnd, LB_SETCURSEL, i, 0l);
}
return 0l;
case WM_LBUTTONDBLCLK:
LONG2POINT(lParam, pt);
if (lbItemFromPoint (plb, pt) >= 0)
lbCmdNotify (plb, LBN_DBLCLK);
break;
case WM_LBUTTONUP:
if (plb->flb & LB_CAPTURE)
{
ReleaseCapture ();
plb->flb &= ~LB_CAPTURE;
}
return 0L;
case WM_DESTROY:
if (h = LBH(hwnd))
{
SendMessage (hwnd,LB_RESETCONTENT,0,0l);
SetWindowLong (hwnd,GWL_HANDLE,0);
LocalFree (h);
}
break;
case WM_ERASEBKGND:
return 0L;
case WM_PAINT:
BeginPaint (hwnd, &ps);
lbPaint (plb,ps.hdc);
EndPaint (hwnd, &ps);
return 0L;
case WM_VSCROLL:
iPos = plb->dyScroll;
iMax = plb->nyScroll;
switch (LOWORD(wParam))
{
case SB_LINEDOWN: dn = 1; break;
case SB_LINEUP: dn = -1; break;
case SB_PAGEDOWN: dn = 1; break;
case SB_PAGEUP: dn = -1; break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION: dn = HIWORD(wParam)-iPos; break;
default: dn = 0;
}
if (dn = BOUND(iPos+dn,0,iMax) - iPos)
{
plb->dyScroll = iPos + dn;
ScrollWindow (hwnd, 0, -dn*plb->dy, NULL, NULL);
SetScrollPos (hwnd, SB_VERT, plb->dyScroll, TRUE);
UpdateWindow (hwnd);
}
break;
case WM_SIZE:
lbSize(plb);
break;
case WM_CHAR:
if ( GetWindowLong (hwnd, GWL_STYLE) & LBS_WANTKEYBOARDINPUT )
if ((i = (int)lbNotifyParent (plb, WM_CHARTOITEM,
MAKELONG(wParam, plb->iCurSel), (LONG)hwnd)) >= 0)
{
SendMessage (hwnd, LB_SETCURSEL, i, 0L);
lbShowItem (plb, plb->iCurSel);
}
break;
case WM_KEYDOWN:
switch (wParam)
{
default:
i = 0;
break;
case VK_RETURN:
lbCmdNotify (plb,LBN_DBLCLK);
break;
case VK_LEFT:
i = -1;
break;
case VK_RIGHT:
i = +1;
break;
case VK_UP:
i = -plb->nx;
break;
case VK_DOWN:
i = +plb->nx;
break;
case VK_HOME:
i = -plb->iCurSel;
break;
case VK_END:
i = plb->nItems - plb->iCurSel - 1;
break;
}
if (i != 0)
{
SendMessage (hwnd, LB_SETCURSEL, plb->iCurSel+i, 0L);
lbShowItem (plb, plb->iCurSel);
}
break;
case WM_KILLFOCUS:
case WM_SETFOCUS:
lbDrawItem(plb, NULL, plb->iCurSel, ODA_FOCUS);
break;
case LB_RESETCONTENT:
for (i=plb->nItems-1; i >= 0; i--)
if (lbDeleteItem (plb, i))
InvalidateRect (hwnd, NULL, TRUE);
break;
case LB_ADDSTRING:
i = plb->nItems++;
plb->lData[i] = lParam;
lbDrawItem (plb, NULL, i, ODA_DRAWENTIRE);
return (LONG)i;
case LB_SETCURSEL:
if ((int)wParam < 0 || (int)wParam >= plb->nItems)
return 0L;
if ((int)wParam != plb->iCurSel)
{
i = plb->iCurSel;
plb->iCurSel = wParam;
lbDrawItem (plb, NULL, i, ODA_SELECT);
lbDrawItem (plb, NULL, plb->iCurSel, ODA_SELECT);
////////////////lbShowItem (plb, plb->iCurSel);
lbCmdNotify (plb, LBN_SELCHANGE);
}
break;
case LB_GETCURSEL:
return plb->iCurSel;
break;
case LB_GETCOUNT:
return plb->nItems;
break;
case LB_SETCOLUMNWIDTH:
plb->dx = wParam;
lbSize (plb);
break;
case LB_GETITEMDATA:
return plb->lData[wParam];
break;
case LB_SETITEMDATA:
plb->lData[wParam] = lParam;
break;
case WM_SETREDRAW:
break;
}
return DefWindowProc (hwnd, msg, wParam, lParam);
}