|
|
// ==================================================================================================
// COPYRIGHT 1992,1993 MICROSOFT CORP ALL RIGHTS RESERVED
// ==================================================================================================
//
// - Custom control to display Columns/Titles above a list box
//
// TERMINOLOGY:
// PHYSICAL COLUMNS: The index of the original columns in their original order
// VIRtUAL COLUMNS: The index of the column as the display is currently showing it based on
// the current order.
//
// History:
// -------
// RickD 04/10/92 created TitleListBox
// Tom Laird-McConnell 12/30/92 Ported to Win32, added to BH project
// Tom Laird-McConnell 05/01/93 gutted titlelist and used as base for complete rewrite as ColumnLB
// Tom Laird-McConnell 08/18/93 Added tabbed-delimited string support
// Arth 03/24/94 Added Unicode support
// ==================================================================================================
#define STRICT 1
#include "switches.h"
#include <windows.h>
#include <windowsx.h>
#include <string.h>
#include <stdlib.h>
// #include <dprintf.h>
#include "columnlb.h"
#include "vlist.h"
#include "utils.h"
#include "debug.h"
#include "mem.h"
//#define DEBUG_HSCROLL 1
#define WHITESPACE 8
#define IDL_COLUMNLISTBOX (CLB_BASE + 1)
#define IDL_COLUMNTITLELISTBOX (CLB_BASE + 2)
#define LB16_ADDSTRING (WM_USER+1)
#define LB16_INSERTSTRING (WM_USER+2)
typedef struct _COLRECORD { DWORD_PTR itemData; LPTSTR pString[]; } COLRECORD; typedef COLRECORD *LPCOLRECORD;
// -------------------------------------------------------------------------------------
//
// window procs
//
LRESULT CALLBACK ColumnLBClass_ListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK ColumnLBClass_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
//
// system message handlers
//
BOOL ColumnLBClass_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct); void ColumnLBClass_OnNCDestroy(HWND hwnd); void ColumnLBClass_OnDestroy(HWND hwnd); void ColumnLBClass_OnPaint(HWND hwnd); void ColumnLBClass_OnSize(HWND hwnd, UINT state, int cx, int cy); void ColumnLBClass_OnSetFont(HWND hwnd, HFONT hfont, BOOL fRedraw); LRESULT ColumnLBClass_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos); void ColumnLBClass_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem); void ColumnLBClass_OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpMeasureItem); void ColumnLBClass_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT *lpDeleteItem); int ColumnLBClass_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret);
//
// WM_USER message handlers
//
BYTE ColumnLBClass_OnNumberCols(HWND hwnd, BYTE NewNumberCols, BOOL fSetColumns); int ColumnLBClass_OnColWidth(HWND hwnd, BYTE Column, int NewWidth, BOOL fSetWidth); LPTSTR ColumnLBClass_OnColTitle(HWND hwnd, BYTE Column, LPTSTR lpTitle, BOOL fSetTitle); BYTE ColumnLBClass_OnSortCol(HWND hwnd, BYTE NewSortCol, BOOL fSetSortCol); LPBYTE ColumnLBClass_OnColOrder(HWND hwnd, LPBYTE NewColOrder, BOOL fSetOrder); LPINT ColumnLBClass_OnColOffsets(HWND hwnd, LPINT NewOffsetTable, BOOL fSetOffsets); LRESULT ColumnLBClass_OnAutoWidth(HWND hwnd, BYTE ColumnToCompute);
//
// mouse movement messages
//
void ColumnLBClass_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags); void ColumnLBClass_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); void ColumnLBClass_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags); void ColumnLBClass_OnRButtonDown (HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
// helper functions
int ColumnLBClass_ComputeOffsets(HWND hwnd);
// -------------------------------------------------------------------------------------
//
// Locals
//
BOOL fWIN32s; // flag for whether win32s (instead of win32/NT)
// -----------------------------------------------------------------
//
// ColumnLBClass_Register()
//
// This function is used to register the Column LB class with the system
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
BOOL ColumnLBClass_Register(HINSTANCE hInstance) { WNDCLASS WndClass;
fWIN32s = ((DWORD)GetVersion() & 0x80000000) ? TRUE : FALSE;
//
// Create the COLUMNLISTBOX class
//
WndClass.style = CS_PARENTDC | CS_DBLCLKS; // CS_GLOBALCLASS;
WndClass.lpfnWndProc = ColumnLBClass_WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = sizeof(LPCOLUMNLBSTRUCT); // we store a pointer as instance data
WndClass.hInstance = hInstance; WndClass.hIcon = 0; WndClass.hCursor = LoadCursor(0, IDC_ARROW); WndClass.hbrBackground = 0; WndClass.lpszMenuName = 0; WndClass.lpszClassName = COLUMNLBCLASS_CLASSNAME;
/* Register the normal title list box control */ return RegisterClass((LPWNDCLASS)&WndClass); }
// -----------------------------------------------------------------
//
// ColumnVLBClass_Register()
//
// This function is used to register the Column VLIST LB class with the system
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
BOOL ColumnVLBClass_Register(HINSTANCE hInstance) { WNDCLASS WndClass;
fWIN32s = ((DWORD)GetVersion() & 0x80000000) ? TRUE : FALSE;
//
// Create the COLUMNVLISTBOX class
//
WndClass.style = CS_PARENTDC | CS_DBLCLKS; // CS_GLOBALCLASS;
WndClass.lpfnWndProc = ColumnLBClass_WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = sizeof(LPCOLUMNLBSTRUCT); // we store a pointer as instance data
WndClass.hInstance = hInstance; WndClass.hIcon = 0; WndClass.hCursor = LoadCursor(0, IDC_ARROW); WndClass.hbrBackground = 0; WndClass.lpszMenuName = 0; WndClass.lpszClassName = COLUMNVLBCLASS_CLASSNAME; // NOTE: this is a different name
/* Register the new control */ return(RegisterClass((LPWNDCLASS)&WndClass)); }
// -----------------------------------------------------------------
//
// ColumnLBClass_Unregister()
//
// This function is used to deregister the Column LB class with the system
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
BOOL ColumnLBClass_Unregister(HINSTANCE hInstance) { return(UnregisterClass(COLUMNLBCLASS_CLASSNAME, hInstance)); }
// -----------------------------------------------------------------
//
// ColumnVLBClass_Unregister()
//
// This function is used to deregister the Column VLIST LB class with the system
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
BOOL ColumnVLBClass_Unregister(HINSTANCE hInstance) { return(UnregisterClass(COLUMNVLBCLASS_CLASSNAME, hInstance)); }
// -----------------------------------------------------------------
// ColumnLBClass_ListBoxWndProc
//
// Window proc used in sub-classing the internal listbox to catch
// internal scroll events to keep title in sync with it...
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
LRESULT CALLBACK ColumnLBClass_ListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT result; LPCOLUMNLBSTRUCT lpColumnLB;
// Everthing goes to normal listbox for processing
lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(GetParent(hwnd), (DWORD)0);
// preprocessing
switch (msg) {
case WM_HSCROLL: // do title hscroll first..
result = SendMessage(lpColumnLB->hwndTitleList, WM_HSCROLL, wParam, lParam); break;
case WM_SETFOCUS: lpColumnLB->fHasFocus = TRUE; //dprintf ("SetFocus to ColumnLB\n");
break;
case WM_KILLFOCUS: lpColumnLB->fHasFocus = FALSE; //dprintf ("KillFocus to ColumnLB\n");
break;
}
//
// call the original listbox window proc
//
result = CallWindowProc((WNDPROC)(lpColumnLB->OldListboxProc), hwnd, msg, (WPARAM) wParam, (LPARAM)lParam);
//
// or if our parent has CLBS_NOTIFYLMOUSE style, then foward LMOUSE buttons
// or if our parent has CLBS_NOTIFYRMOUSE style, then foward RMOUSE buttons
//
switch (msg) { case WM_HSCROLL: //
// if it is a Horizontal scrolls, then we foward to our parent so title can be moved
// in sync with listbox....
//
SendMessage(GetParent(hwnd), CLB_HSCROLL, wParam, lParam ); break;
case VLB_RESETCONTENT: case LB_RESETCONTENT: //
// if it is a LB_RESETCONTENT, or VLB_RESETCONTENT, then reset x position
//
SendMessage(GetParent(hwnd), CLB_HSCROLL, (WPARAM)SB_TOP, (LPARAM)NULL); break;
case WM_LBUTTONDOWN : case WM_LBUTTONUP : case WM_LBUTTONDBLCLK : //
// forward message to parent
//
if (GetWindowLong(GetParent(hwnd), GWL_EXSTYLE) & CLBS_NOTIFYLMOUSE) SendMessage(GetParent(hwnd), msg, wParam, lParam); break;
case WM_RBUTTONDOWN : // case WM_RBUTTONUP :
case WM_RBUTTONDBLCLK :
//
// forward message to parent
//
// if (GetWindowLong(GetParent(hwnd), GWL_EXSTYLE) & CLBS_NOTIFYRMOUSE)
SendMessage(GetParent(hwnd), msg, wParam, lParam); break;
default: break; }
return(result); }
// -----------------------------------------------------------------
// ColumnLBClass_TitleListBoxWndProc
//
// Window proc used in sub-classing the internal Title listbox to catch
// internal mouse click events...
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
LRESULT CALLBACK ColumnLBClass_TitleListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT result; LPCOLUMNLBSTRUCT lpColumnLB;
// Everthing goes to normal listbox for processing
lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(GetParent(hwnd), (DWORD)0);
//
// call the original listbox window proc
//
result = CallWindowProc((WNDPROC)(lpColumnLB->OldTitleListboxProc) , hwnd, msg, (WPARAM) wParam, (LPARAM)lParam);
//
// foward LMOUSE buttons, foward RMOUSE buttons
//
switch (msg) { #ifdef DEBUG_HSCROLL
case WM_HSCROLL: dprintf(TEXT("ColumnLBClass_TitleListBoxProc: CallWindowProc(OldListboxProc) returned %ld to hwnd=%lx, wParam=%u, lParam=%u\n"), hwnd, wParam, lParam); break; #endif
case WM_MOUSEMOVE: case WM_LBUTTONDOWN : case WM_LBUTTONUP : case WM_LBUTTONDBLCLK : case WM_RBUTTONDOWN : case WM_RBUTTONUP : case WM_RBUTTONDBLCLK : SendMessage(GetParent(hwnd), msg, wParam, lParam); break;
case WM_SETFOCUS: // we don't ever want the focus, so give it back to the parent...
SendMessage(GetParent(hwnd), msg, wParam, lParam); break;
case WM_SIZE: // we need to reset our idea of what our current scroll position is...
break; }
return(result); }
// -----------------------------------------------------------------
// ColumnLBClass_WndProc
//
// Main window proc for handling messages for both the ColumnLB and
// ColumnVLB classes...
//
// HISTORY:
// Tom Laird-McConnell 4/17/93 Created
//
// -----------------------------------------------------------------
LRESULT CALLBACK ColumnLBClass_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); LPCOLRECORD lpRecord; LRESULT result;
//
// check for ListBox message coming from application
// and forward them onto the listbox itself...
//
if ( ((fWIN32s == TRUE) && (msg >= WM_USER && msg < (WM_USER + LB_MSGMAX - LB_ADDSTRING + 1)) ) || // WIN32s version BUGBUG
((fWIN32s == FALSE) && (msg >= LB_ADDSTRING && msg < LB_MSGMAX)) || // NT version BUGBUG
((msg >= VLB_TOVLIST_MSGMIN) && (msg <= VLB_TOVLIST_MSGMAX)) // vlb sepcific APP->VLIST messages should be fowarded...
) { //
// OWNERDRAW parent, so just send it to the hwnd list child
//
return(SendMessage(lpColumnLB->hwndList, msg, wParam, lParam)); }
//
// check to see if message is a TO APPLCATION message from the child listbox
// which should be forwarded to application parent window
//
if ((msg >= VLB_TOAPP_MSGMIN) && (msg <= VLB_TOAPP_MSGMAX)) return(SendMessage(GetParent(hwnd), msg, wParam, lParam)); // forward to parent...
//
// since it's not a message passing through, then process this message
// as our own...
//
switch (msg) { HANDLE_MSG(hwnd, WM_NCCREATE, ColumnLBClass_OnNCCreate); HANDLE_MSG(hwnd, WM_NCDESTROY, ColumnLBClass_OnNCDestroy); HANDLE_MSG(hwnd, WM_DESTROY, ColumnLBClass_OnDestroy); HANDLE_MSG(hwnd, WM_PAINT, ColumnLBClass_OnPaint); HANDLE_MSG(hwnd, WM_SIZE, ColumnLBClass_OnSize); HANDLE_MSG(hwnd, WM_DRAWITEM, ColumnLBClass_OnDrawItem); HANDLE_MSG(hwnd, WM_MEASUREITEM, ColumnLBClass_OnMeasureItem); HANDLE_MSG(hwnd, WM_DELETEITEM, ColumnLBClass_OnDeleteItem);
HANDLE_MSG(hwnd, WM_LBUTTONDOWN, ColumnLBClass_OnLButtonDown); HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, ColumnLBClass_OnLButtonDown); HANDLE_MSG(hwnd, WM_LBUTTONUP, ColumnLBClass_OnLButtonUp); HANDLE_MSG(hwnd, WM_MOUSEMOVE, ColumnLBClass_OnMouseMove);
case WM_RBUTTONDOWN: // figure out what item we are on and tell our parent.
HANDLE_WM_RBUTTONDOWN ( hwnd, wParam, lParam, ColumnLBClass_OnRButtonDown ); break;
case WM_CREATE: { LPCREATESTRUCT lpCreate = (LPCREATESTRUCT) lParam;
ColumnLBClass_OnSize(hwnd, SIZE_RESTORED, lpCreate->cx, lpCreate->cy); } break;
// -------------------------------------------------------------------
// put System messages here which explicitly need to be passed to LISTBOX
//
case WM_SETFONT: HANDLE_WM_SETFONT(hwnd, wParam, lParam, ColumnLBClass_OnSetFont); break;
// put the focus on the list box if we get it
case WM_SETFOCUS: lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); SetFocus(lpColumnLB->hwndList); break;
case SBM_SETPOS : case SBM_SETRANGE : case SBM_SETRANGEREDRAW : //
// need to foward SBM messages to both listboxes...
//
SendMessage(lpColumnLB->hwndTitleList, msg, wParam, lParam); return(SendMessage(lpColumnLB->hwndList, msg, wParam, lParam));
case SBM_GETPOS : case SBM_GETRANGE : case SBM_ENABLE_ARROWS : return(SendMessage(lpColumnLB->hwndList, msg, wParam, lParam));
// ------------------------------------------------------------------------------
//
// LB_XXXXXXX Messages (disguised as CLB_XXXXXX messages)
// to pass on to child listbox, if the parent didn't want us to
// be owner draw, then we implement ownerddraw default behavior ourself
//
// ------------------------------------------------------------------------------
case CLB_ADDSTRING: case CLB_INSERTSTRING: //
// if the parent is NOT handling OWNERDRAW, then we need to handle
//
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { LPTSTR lpColStart,lpTab; LPTSTR lpStringBuffer; int i;
lpRecord = (LPCOLRECORD)GlobalAllocPtr(GPTR, sizeof(COLRECORD) + sizeof(LPTSTR) * lpColumnLB->nColumns); lpStringBuffer = (LPTSTR) GlobalAllocPtr(GPTR, (lstrlen((LPTSTR)lParam) * sizeof(TCHAR)) + sizeof(TCHAR));
if ((lpRecord) && (lpStringBuffer)) { // now parse the tab-deliminated string and put into each pointer
lstrcpy(lpStringBuffer, (LPTSTR)lParam); lpColStart = lpStringBuffer; lpTab = lstrchr(lpStringBuffer, TEXT('\t'));
// fill in pointer table
for (i=0; i < lpColumnLB->nColumns; i++) { if (lpTab) *lpTab = '\0'; else { // there was an error, not enough tabs!
GlobalFreePtr(lpRecord); GlobalFreePtr(lpStringBuffer); return(LB_ERR); } // store this pointer.
lpRecord->pString[i] = lpColStart; // advance to next column text
lpColStart = lpTab + 1; lpTab = lstrchr(lpColStart, TEXT('\t')); } lpRecord->itemData = 0;
// and now pass on our new lpRecord as the item being added to the listbox
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, (LPARAM)lpRecord)); } else // an error has occured, free up any memory and return failure
{ if (lpStringBuffer) GlobalFreePtr(lpStringBuffer); if (lpRecord) GlobalFreePtr(lpRecord); return(LB_ERR); } } else //
// Parent is owner draw, so send it to the hwnd list child,
// but translate the message first to real LB_ message
//
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
// and we also need to check for LB_GETTEXT to make it look like a string
case CLB_GETTEXT: //
// if the parent is NOT handling OWNERDRAW, then we need to handle
//
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { LPTSTR p = (LPTSTR)lParam; DWORD Length = 0; DWORD x; int i;
*p = '\0';
// and now pass on to get the text...
lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
if (lpRecord == (LPCOLRECORD)LB_ERR) return(LB_ERR);
for (i=0; i < lpColumnLB->nColumns ; i++ ) { lstrcpy(p, lpRecord->pString[lpColumnLB->ColumnOrderTable[i]]); lstrcat(p, TEXT("\t")); x = lstrlen(p); Length += x + sizeof(TCHAR); p += x; } return(Length); } else //
// Parent is owner draw, so send it to the hwnd list child,
// but translate the message first to real LB_ message
//
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
case CLB_GETTEXTPTRS:
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
if (lpRecord == (LPCOLRECORD)LB_ERR) return(LB_ERR);
return (LRESULT)lpRecord->pString; } else return (LRESULT)NULL;
// we need to handle LB_GETTEXTLEN to return full tabbed length...
case CLB_GETTEXTLEN: //
// if the parent is NOT handling OWNERDRAW, then we need to handle
//
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { LPTSTR p = (LPTSTR)lParam; DWORD Length = 0; int i;
// and now pass on to get the text...
lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
if (lpRecord == (LPCOLRECORD)LB_ERR) return(LB_ERR);
for (i=0; i < lpColumnLB->nColumns ; i++ ) { Length += lstrlen(lpRecord->pString[lpColumnLB->ColumnOrderTable[i]]) + sizeof(TCHAR); } return(Length); } else //
// Parent is owner draw, so send it to the hwnd list child,
// but translate the message first to real LB_ message
//
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
case CLB_GETITEMDATA: //
// if the parent is NOT handling OWNERDRAW, then we need to handle
//
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0); if (lpRecord != (LPCOLRECORD)LB_ERR) return(lpRecord->itemData); else return(LB_ERR); } else //
// Parent is owner draw, so send it to the hwnd list child,
// but translate the message first to real LB_ message
//
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
case CLB_SETITEMDATA: //
// if the parent is NOT handling OWNERDRAW, then we need to handle
//
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
if (lpRecord != (LPCOLRECORD)LB_ERR) return (LRESULT)(lpRecord->itemData = lParam); else return(LB_ERR); } else //
// Parent is owner draw, so send it to the hwnd list child,
// but translate the message first to real LB_ message
//
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
//
// if it is a HORIZONTAL exntent message, then we need to massage...
//
case CLB_SETHORIZONTALEXTENT : //
// send the message to the title listbox as well
//
SendMessage(lpColumnLB->hwndTitleList, LB_SETHORIZONTALEXTENT, wParam, lParam);
//
// pass it on to the child listbox, using VLB_SETHOR if appropriate...
//
return(SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, wParam, lParam));
//
// we need to massage the GETITEMRECT to handle the incorrect rect returned due to titlelistbox.
//
case CLB_GETITEMRECT: { LRESULT retcode; int height; LPRECT lpRect = (LPRECT)lParam;
//
// send it to the hwnd list child, but translate the message first to real LB_ message
//
retcode = SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam); height = lpRect->bottom-lpRect->top; lpRect->top = lpRect->bottom + 1; lpRect->bottom = lpRect->top + height; return(retcode); } break;
case CLB_DELETESTRING : case CLB_SELITEMRANGEEX : case CLB_RESETCONTENT : case CLB_SETSEL : case CLB_SETCURSEL : case CLB_GETSEL : case CLB_GETCURSEL : case CLB_GETCOUNT : case CLB_SELECTSTRING : case CLB_DIR : case CLB_GETTOPINDEX : case CLB_FINDSTRING : case CLB_GETSELCOUNT : case CLB_GETSELITEMS : case CLB_SETTABSTOPS : case CLB_GETHORIZONTALEXTENT : case CLB_SETCOLUMNWIDTH : case CLB_ADDFILE : case CLB_SETTOPINDEX : case CLB_SELITEMRANGE : case CLB_SETANCHORINDEX : case CLB_GETANCHORINDEX : case CLB_SETCARETINDEX : case CLB_GETCARETINDEX : case CLB_SETITEMHEIGHT : case CLB_GETITEMHEIGHT : case CLB_FINDSTRINGEXACT : case CLB_SETLOCALE : case CLB_GETLOCALE : case CLB_SETCOUNT : //
// Simply send it to the hwnd list child, but translate the message first to real LB_ message
//
return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
// -------------------------------------------------------------------
// put messages here which explicitly need to be passed to our PARENT
//
case WM_COMMAND: /* if this is a notification message from our child translate */ /* it to look like it is from us and pass on to our parent */
if (LOWORD(wParam) == IDL_COLUMNLISTBOX) return(SendMessage( GetParent(hwnd), msg, MAKELONG( GetDlgCtrlID(hwnd) ,HIWORD(wParam)), (LPARAM)hwnd )); // make it look like we were the ones sending the message...
else return(SendMessage(GetParent(hwnd), msg, wParam, (LPARAM)hwnd));
case WM_VKEYTOITEM: // pass on to our parent but using our hwnd...
if (lpColumnLB->Style & (LBS_WANTKEYBOARDINPUT | VLBS_WANTKEYBOARDINPUT) ) return(SendMessage(GetParent(hwnd), msg, wParam, (LPARAM)hwnd)); else return(-1); // perform default action...
case WM_CHARTOITEM: if (lpColumnLB->Style & (LBS_WANTKEYBOARDINPUT | VLBS_WANTKEYBOARDINPUT) ) if ((result = SendMessage(GetParent(hwnd), msg, wParam, (LPARAM)hwnd)) != -1) return(result);
return HANDLE_WM_CHARTOITEM(hwnd, wParam, lParam, ColumnLBClass_OnCharToItem);
case WM_COMPAREITEM: { LPCOMPAREITEMSTRUCT lpCompareItem = (LPCOMPAREITEMSTRUCT)lParam; LRESULT result;
if ((lpColumnLB->Style & LBS_OWNERDRAWFIXED) || (lpColumnLB->Style & VLBS_OWNERDRAWFIXED)) { //
// substitute our values in the COMPAREITEMSTRUCT...
//
lpCompareItem->CtlID = GetDlgCtrlID(hwnd); lpCompareItem->hwndItem = hwnd;
//
// then pass to our parent as our WM_COMPAREITEM, with the current physcial sort column as wParam
//
result = (int)SendMessage(GetParent(hwnd), WM_COMPAREITEM, (WPARAM)lpColumnLB->SortColumn, (LPARAM)lpCompareItem); return(result); } else { LPTSTR lpString1; LPTSTR lpString2; LPCOLRECORD lpColRecord1; LPCOLRECORD lpColRecord2;
// handle ourselves assuming item data is pointer to array of LPTSTR's
lpColRecord1 = (LPCOLRECORD)lpCompareItem->itemData1; lpColRecord2 = (LPCOLRECORD)lpCompareItem->itemData2; lpString1 = lpColRecord1->pString[lpColumnLB->SortColumn]; lpString2 = lpColRecord2->pString[lpColumnLB->SortColumn]; if (lpString1 && lpString2) return(lstrcmpi(lpString1, lpString2)); else return(0); } } break;
// ---------------------------------------------------------
// handle our own messages
// ---------------------------------------------------------
//
// NUMBER COLUMNS
//
case CLB_GETNUMBERCOLS : // get the number of columns (ret=NumCols)
return ColumnLBClass_OnNumberCols(hwnd, 0, FALSE);
case CLB_SETNUMBERCOLS : // set the number of columns (wparam=NumCols)
return ColumnLBClass_OnNumberCols(hwnd, (BYTE)wParam, TRUE);
// ----------------------------------------------------------------
// Following messages use physical column numbers
// ----------------------------------------------------------------
//
// COLUMN WIDTH
//
case CLB_GETCOLWIDTH : // get a column width (wParm=Physical Column ret=ColWidth in LU's)
return ColumnLBClass_OnColWidth(hwnd, (BYTE)wParam, (int)0, FALSE);
case CLB_SETCOLWIDTH : // set a column width (wParm=Physical Column lParam=Width)
return ColumnLBClass_OnColWidth(hwnd, (BYTE)wParam, (int)lParam, TRUE);
case CLB_AUTOWIDTH : // auto-matically set column widths using titles... (wParam = Physical Column to auto width)
return ColumnLBClass_OnAutoWidth(hwnd, (BYTE)wParam);
//
// COLUMN TITLE
//
case CLB_GETCOLTITLE : // get a column's title (wParm=Physical Column, ret=Title)
return (LRESULT)ColumnLBClass_OnColTitle(hwnd, (BYTE)wParam, (LPTSTR)NULL, FALSE);
case CLB_SETCOLTITLE : // set a column's title (wParm=Physical Col, lParm=Title)
return (LRESULT)ColumnLBClass_OnColTitle(hwnd, (BYTE)wParam, (LPTSTR)lParam, TRUE);
case CLB_GETROWCOLTEXT: //
// if the parent is NOT handling OWNERDRAW, then we need to handle
//
if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { INT WhichCol = (INT)(wParam); INT WhichRow = (INT)(lParam);
// and now pass on to get the text...
lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, WhichRow, 0);
if (lpRecord == (LPCOLRECORD)LB_ERR) return((LRESULT)NULL);
return (LRESULT)lpRecord->pString[WhichCol]; } return((LRESULT)NULL); // owner draw, the owner has to figure this out themselves
//
// SORT COLUMN
//
case CLB_GETSORTCOL : // get the physical sort column (ret=Physical Col)
return (LRESULT)ColumnLBClass_OnSortCol(hwnd, 0, FALSE);
case CLB_SETSORTCOL : // set the physical sort column (wParm=Physical Col)
return (LRESULT)ColumnLBClass_OnSortCol(hwnd, (BYTE)wParam, TRUE);
//
// COLUMN ORDER
//
case CLB_GETCOLORDER : // get the virtual order of physical columns (ret = LPDWORD order table)
return (LRESULT)ColumnLBClass_OnColOrder(hwnd, (LPBYTE)0, FALSE);
case CLB_SETCOLORDER : // get the virtual order of physical columns (wParam = LPDWORD order table)
return (LRESULT)ColumnLBClass_OnColOrder(hwnd, (LPBYTE)lParam, TRUE);
case CLB_CHECKFOCUS: // does the listbox have the focus?
// if (lpColumnLB->fUseVlist) // then we have to ask vlist the info
// return
// else
return lpColumnLB->fHasFocus;
// ----------------------------------------------------------------
// Following messages use virtual column numbers
// ----------------------------------------------------------------
//
// COLUMN OFFSETS
//
case CLB_GETCOLOFFSETS : // gets the incremental virtual col offsets (ret=LPDWORD)
return (LRESULT)ColumnLBClass_OnColOffsets(hwnd, (LPINT)wParam, FALSE);
// case CLB_SETCOLOFFSETS : // gets the incremental virtual col offsets (ret=LPDWORD)
// return (LRESULT)ColumnLBClass_OnColOffsets(hwnd, (LPDWORD)wParam, TRUE);
// =================================================================
// INTERNAL
//
case CLB_HSCROLL : // a hscroll event (INTERNAL)
return ColumnLBClass_OnHScroll(hwnd, (HWND)(lParam), (int)LOWORD(wParam), (int)HIWORD(wParam));
//
// GET FOCUS
//
case CLB_GETFOCUS : // get the handle for the window of CLB with the key focus
if ( lpColumnLB->fUseVlist ) // we must ask the column list box below us for the information.
return SendMessage ( lpColumnLB->hwndList, VLB_GETFOCUSHWND, 0,0 ); return (LRESULT) lpColumnLB->hwndList;
default: return(DefWindowProc(hwnd, msg, wParam, lParam)); }
return(TRUE); }
// ------------------------------------------------------------------
// ColumnLBClass_OnNCCreate()
//
// Handles WM_NCCCREATE message
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
BOOL ColumnLBClass_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) { LPCOLUMNLBSTRUCT lpColumnLB; HWND hwndList; HWND hwndTitleList; BOOL fUseVlist; HDC hdc; TEXTMETRIC tm; RECT rect; WORD ncxBorder; WORD ncyBorder; WORD yTitle;
ncxBorder = (WORD) GetSystemMetrics(SM_CXBORDER); ncyBorder = (WORD) GetSystemMetrics(SM_CYBORDER);
//
// if the classname is for ColumnVLB class, then they want the Column Virtual list box...
//
if (lstrcmpi(lpCreateStruct->lpszClass, COLUMNVLBCLASS_CLASSNAME) == 0) fUseVlist = TRUE; else fUseVlist = FALSE;
hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc);
yTitle = (WORD)(tm.tmHeight + 2*ncyBorder);
GetClientRect(hwnd, &rect);
//
// create the title list box window...
//
hwndTitleList = CreateWindow( (LPTSTR) TEXT("LISTBOX"), (LPTSTR) TEXT(""), (lpCreateStruct->style & ~WS_BORDER) | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | WS_VISIBLE | WS_CHILD, ncxBorder, ncyBorder, lpCreateStruct->cx - (2*ncxBorder) - GetSystemMetrics(SM_CXVSCROLL), yTitle, hwnd, (HMENU)IDL_COLUMNTITLELISTBOX, lpCreateStruct->hInstance, NULL);
if (fUseVlist == TRUE) //
// create a Vlist window...
//
hwndList = CreateWindow((LPTSTR)VLIST_CLASSNAME, (LPTSTR) TEXT(""), (lpCreateStruct->style & ~(WS_BORDER | VLBS_HASSTRINGS)) | // NOTE: This can _never_ be hasstrings
VLBS_NOTIFY | VLBS_USETABSTOPS | VLBS_NOINTEGRALHEIGHT | VLBS_OWNERDRAWFIXED | // we always force this as either we will owner draw, or our parent will
WS_HSCROLL | WS_VSCROLL | VLBS_DISABLENOSCROLL | WS_VISIBLE | WS_CHILD, ncxBorder, yTitle + ncyBorder, lpCreateStruct->cx - ncxBorder, // -(2*ncxBorder)
lpCreateStruct->cy - yTitle - ncyBorder, hwnd, (HMENU)IDL_COLUMNLISTBOX, lpCreateStruct->hInstance, NULL); else //
// create a list box window...
//
#ifdef H_SCROLL
hwndList = CreateWindow((LPTSTR) TEXT("LISTBOX"), (LPTSTR) TEXT(""), (lpCreateStruct->style & ~(WS_BORDER | LBS_HASSTRINGS)) | // NOTE: This can _never_ be hasstrings
LBS_NOTIFY | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | // we always force this as either we will owner draw, or our parent will
WS_HSCROLL | WS_VSCROLL | LBS_DISABLENOSCROLL | WS_VISIBLE | WS_CHILD, ncxBorder, yTitle + ncyBorder, lpCreateStruct->cx - ncxBorder, // -(2*ncxBorder)
lpCreateStruct->cy - yTitle - ncyBorder, hwnd, (HMENU)IDL_COLUMNLISTBOX, lpCreateStruct->hInstance, NULL); #else
hwndList = CreateWindow((LPTSTR) TEXT("LISTBOX"), (LPTSTR) TEXT(""), (lpCreateStruct->style & ~(WS_BORDER | LBS_HASSTRINGS)) | // NOTE: This can _never_ be hasstrings
LBS_NOTIFY | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | // we always force this as either we will owner draw, or our parent will
WS_VSCROLL | LBS_DISABLENOSCROLL | WS_VISIBLE | WS_CHILD, ncxBorder, yTitle + ncyBorder, lpCreateStruct->cx - ncxBorder, // -(2*ncxBorder)
lpCreateStruct->cy - yTitle - ncyBorder, hwnd, (HMENU)IDL_COLUMNLISTBOX, lpCreateStruct->hInstance, NULL); #endif
//
// if we succeeded...
//
if (hwndList) { //
// create a ColumnLB struct to keep track of all of the pertinent instance
// info for this instance of a ColumnLB window
//
lpColumnLB = (LPCOLUMNLBSTRUCT)GlobalAllocPtr(GPTR, sizeof(COLUMNLBSTRUCT));
if (lpColumnLB) { BYTE i;
//
// store it in the window data for this window
//
SetWindowLongPtr(hwnd, 0, (LONG_PTR) lpColumnLB);
memset(lpColumnLB, '\0', sizeof(COLUMNLBSTRUCT));
//
// fill in pertinent info
//
lpColumnLB->Style = lpCreateStruct->style;
lpColumnLB->hInstance = (HINSTANCE)GetWindowLong(hwnd, GWLP_HINSTANCE);
lpColumnLB->fUseVlist = (UCHAR) fUseVlist; lpColumnLB->fSorting = FALSE; lpColumnLB->fMouseState = 0;
lpColumnLB->hwndList = hwndList; lpColumnLB->OldListboxProc = (FARPROC)GetWindowLong(hwndList, GWLP_WNDPROC); lpColumnLB->NewListboxProc = MakeProcInstance((FARPROC)ColumnLBClass_ListBoxWndProc, hInst);
lpColumnLB->hwndTitleList = hwndTitleList; lpColumnLB->OldTitleListboxProc = (FARPROC)GetWindowLong(hwndTitleList, GWLP_WNDPROC); lpColumnLB->NewTitleListboxProc = MakeProcInstance((FARPROC)ColumnLBClass_TitleListBoxWndProc, hInst);
lpColumnLB->nColumns=1;
lpColumnLB->yTitle = yTitle;
//
// init sort order
//
for (i=0; i < MAX_COLUMNS ; i++ ) lpColumnLB->ColumnOrderTable[i] = i;
//
// sub-class the listbox window by substituting our window proc for the
// normal one...
//
SetWindowLongPtr(hwndList, GWLP_WNDPROC,(DWORD_PTR)lpColumnLB->NewListboxProc);
//
// sub-class the title listbox window by substituting our window proc for the
// normal one...
//
SetWindowLongPtr(hwndTitleList, GWLP_WNDPROC,(DWORD_PTR)lpColumnLB->NewTitleListboxProc);
//
// add the lpColumnLB struct as the only item in the title listbox
//
ListBox_AddString(lpColumnLB->hwndTitleList, (DWORD_PTR)lpColumnLB);
//
// pass this on to the default window proc
//
return(FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, DefWindowProc)); } else { return(FALSE); } } else return(FALSE); }
// ------------------------------------------------------------------
// ColumnLBClass_OnDestroy()
//
// Handles WM_DESTROY message
//
// HISTORY:
// Tom Laird-McConnell 7/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnDestroy(HWND hwnd) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
DestroyWindow(lpColumnLB->hwndTitleList); DestroyWindow(lpColumnLB->hwndList); }
// ------------------------------------------------------------------
// ColumnLBClass_OnNCDestroy()
//
// Handles WM_NCDESTROY
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnNCDestroy(HWND hwnd) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); FreeProcInstance(lpColumnLB->NewListboxProc);
GlobalFreePtr(lpColumnLB); }
// ------------------------------------------------------------------
// ColumnLBClass_OnPaint()
//
// Handles WM_PAINT message, draws column titles as appropriate...
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnPaint(HWND hwnd) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); PAINTSTRUCT ps; HBRUSH hFrameBrush, hGreyBrush; RECT rect; HDC hdc; int ncxBorder = GetSystemMetrics(SM_CXBORDER); int ncyBorder = GetSystemMetrics(SM_CYBORDER);
BeginPaint(hwnd, (LPPAINTSTRUCT)&ps);
// Draw border around title and listbox
GetClientRect(hwnd, (LPRECT)&rect);
hdc = ps.hdc;
hFrameBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME)); FrameRect(hdc, (LPRECT)&rect, hFrameBrush);
// make bottom the height of a HSCROLL bar
// make left side the width of a VSCROLL bar
rect.top += ncyBorder; rect.right -= ncxBorder; rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL); rect.bottom = lpColumnLB->yTitle+ncyBorder;
hGreyBrush = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR)); FillRect(hdc, &rect, hGreyBrush);
rect.right = rect.left+1; FillRect(hdc, &rect, hFrameBrush);
// destroy brushes...
DeleteBrush(hFrameBrush); DeleteBrush(hGreyBrush);
EndPaint(hwnd, (LPPAINTSTRUCT)&ps); }
// ------------------------------------------------------------------
// ColumnLBClass_OnSize()
//
// Handles WM_SIZE message
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnSize(HWND hwnd, UINT state, int cx, int cy) { WORD ncxBorder; WORD ncyBorder; RECT rect; DWORD cxExtent;
LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
if (lpColumnLB->hwndList != (HWND)NULL) { ncxBorder = (WORD)GetSystemMetrics(SM_CXBORDER); ncyBorder = (WORD)GetSystemMetrics(SM_CYBORDER);
// position title listbox at top
MoveWindow(lpColumnLB->hwndTitleList, ncxBorder, ncyBorder, cx-(2*ncxBorder) - GetSystemMetrics(SM_CXVSCROLL), lpColumnLB->yTitle, TRUE);
// position list box below title listbox
MoveWindow(lpColumnLB->hwndList, ncxBorder, lpColumnLB->yTitle + ncyBorder, cx - ncxBorder, // -(2*ncxBorder)
cy-lpColumnLB->yTitle - ncyBorder, TRUE);
cxExtent = ColumnLBClass_ComputeOffsets(hwnd);
GetClientRect(hwnd, &rect);
//
// if the new extent is smaller then the space available, move the position
//
if ((DWORD)rect.right > cxExtent) { // #ifdef DEBUG
// dprintf(TEXT("Reset HSCROLL pos to far left\n"));
// #endif
// move position to far left
SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0);
// do the same for the title list
SendMessage(lpColumnLB->hwndTitleList, WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0); }
InvalidateRect(lpColumnLB->hwndList, NULL, TRUE); InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE); } InvalidateRect(lpColumnLB->hwndTitleList, 0, TRUE); InvalidateRect(lpColumnLB->hwndList, 0, TRUE); }
// ------------------------------------------------------------------
// ColumnLBClass_OnSetFont()
//
// Handles WM_SETFONT message
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnSetFont(HWND hwnd, HFONT hFont, BOOL fRedraw) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); HDC hdc; TEXTMETRIC tm; RECT rect;
lpColumnLB->hFont = hFont;
hdc = GetDC(hwnd); SelectFont(hdc, (HFONT)hFont); GetTextMetrics(hdc, &tm);
//
// forward on to listbox window
//
if (lpColumnLB->hwndList != (HWND)NULL) FORWARD_WM_SETFONT(lpColumnLB->hwndList, hFont, fRedraw, SendMessage);
if (lpColumnLB->hwndTitleList != (HWND)NULL) FORWARD_WM_SETFONT(lpColumnLB->hwndTitleList, hFont, fRedraw, SendMessage);
//
// store text height...
//
lpColumnLB->yTitle = tm.tmHeight + 2*GetSystemMetrics(SM_CYBORDER);
//
// change height appropriately
//
ListBox_SetItemHeight(lpColumnLB->hwndTitleList, 0, lpColumnLB->yTitle);
SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_SETITEMHEIGHT : LB_SETITEMHEIGHT, 0, tm.tmHeight);
//
// since we changed the font size, forze a WM_SIZE to recalc the size of the window
//
GetClientRect(hwnd, &rect); ColumnLBClass_OnSize(hwnd, SIZE_RESTORED, rect.right-rect.left, rect.bottom-rect.top);
ReleaseDC(hwnd, hdc); }
// ------------------------------------------------------------------
// ColumnLBClass_OnHScroll()
//
//
// Handles OnHScroll messages to keep title bar in ssync with listbox...
//
// HISTORY:
// Tom Laird-McConnell 5/1/93 Created
// ------------------------------------------------------------------
LRESULT ColumnLBClass_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
long lPos; WORD nPos; RECT rect; int cxExtent;
switch (code) { case SB_THUMBPOSITION: case SB_THUMBTRACK: nPos = (WORD) pos; break;
case SB_LINEUP: case SB_LINEDOWN: case SB_PAGEUP: case SB_PAGEDOWN: case SB_TOP: case SB_BOTTOM: case SB_ENDSCROLL: if (lpColumnLB->fUseVlist) nPos = (WORD)SendMessage(lpColumnLB->hwndList, VLB_GETSCROLLPOS, 0, 0); else nPos = (WORD) GetScrollPos((hwndCtl) ? hwndCtl : lpColumnLB->hwndList, SB_HORZ); // nPos = GetScrollPos(lpColumnLB->hwndList, SB_HORZ);
break;
default: return(TRUE); }
GetClientRect(lpColumnLB->hwndList, (LPRECT)&rect);
//... if it is a VLIST, then there is an error in the client calculation when it has VSCROLL bars, so
// we need to adjust ourselves by width of VSCROLL bar...
if (lpColumnLB->fUseVlist) rect.right -= GetSystemMetrics(SM_CXVSCROLL);
cxExtent = (DWORD)SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_GETHORIZONTALEXTENT : LB_GETHORIZONTALEXTENT, 0, 0L); if (cxExtent >= rect.right) { // then the listbox size is > then client's display size
// so we need to calculate how much is not on the client display
cxExtent -= rect.right; } else // else set the amount left over to 0 to nullify (technical term) the
// effects of this calculation...
cxExtent = 0;
lPos = -(((LONG)nPos*(LONG)cxExtent)/100); if (lPos > 0) lpColumnLB->xPos = 0; else if (lPos < -cxExtent) lpColumnLB->xPos = -cxExtent; else lpColumnLB->xPos = (int)lPos;
return(TRUE);
}
// ------------------------------------------------------------------
// ColumnLBClass_OnMeasureItem()
//
//
// Handles telling the parent how to draw each column accordingly...
//
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpMeasureItem) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); TEXTMETRIC tm; HDC hdc;
if (lpMeasureItem->CtlID == IDL_COLUMNTITLELISTBOX) { if (lpColumnLB) lpMeasureItem->itemHeight = lpColumnLB->yTitle; else { hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc);
lpMeasureItem->itemHeight = tm.tmHeight; } } else //
// it should be passed to parent
//
FORWARD_WM_MEASUREITEM(GetParent(hwnd), lpMeasureItem, SendMessage); }
// ------------------------------------------------------------------
// ColumnLBClass_OnDeleteItem()
//
//
// Handles deleting items if necessary...
//
//
// HISTORY:
// Tom Laird-McConnell 08/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT *lpDeleteItem) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); LPCOLRECORD lpRecord;
// don't actually do the delete if we are sorting...
if (lpColumnLB->fSorting == TRUE) return;
if (lpDeleteItem->CtlID == IDL_COLUMNLISTBOX) { // if the style is that the owner is handling the owner draw stuff
// then we need to pass to the parent ELSE free our memory...
if ((lpColumnLB) && (lpColumnLB->Style & LBS_OWNERDRAWFIXED)) //
// it should be passed to parent
//
FORWARD_WM_DELETEITEM(GetParent(hwnd), lpDeleteItem, SendMessage); else // this is our item data, so we need to free it
if (lpDeleteItem->itemData) { lpRecord = (LPCOLRECORD)lpDeleteItem->itemData; // NOTE that the first pointer is actually the string buffer...
if (lpRecord->pString[0]) GlobalFreePtr(lpRecord->pString[0]); GlobalFreePtr(lpRecord); } } }
// ------------------------------------------------------------------
// ColumnLBClass_OnDrawItem()
//
//
// Handles telling the parent to draw each column accordingly...
//
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); HWND hwndParent = GetParent(hwnd); BYTE i; BYTE PhysCol; CLBDRAWITEMSTRUCT CLBDrawItemStruct; RECT rect; int ncxBorder = GetSystemMetrics(SM_CXBORDER); int ncyBorder = GetSystemMetrics(SM_CYBORDER); HPEN hFramePen; HPEN hShadowPen; HPEN hHighlightPen; HPEN hOldPen; HBRUSH hBackgroundBrush; DWORD Col; DWORD cyChar; TEXTMETRIC tm; BYTE PhysColumn; RECT ClientRect;
GetClientRect(lpDrawItem->hwndItem, &ClientRect);
//
// figure out which window sent us the DrawItem
//
switch (lpDrawItem->CtlID) { //
// handle drawing the title listbox
//
case IDL_COLUMNTITLELISTBOX: {
LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
if (lpDrawItem->itemAction == ODA_DRAWENTIRE) { GetTextMetrics(lpDrawItem->hDC, &tm);
cyChar = tm.tmHeight;
//
// create all of our pens for our drawing
//
hHighlightPen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_BTNHIGHLIGHT)); hShadowPen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_BTNSHADOW)); hFramePen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_WINDOWFRAME));
hBackgroundBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
//
// get the window rect we are going to work with
//
CopyRect(&rect, &lpDrawItem->rcItem); FillRect(lpDrawItem->hDC, &rect, hBackgroundBrush);
//
// Draw frame color line below title section of property window
//
hOldPen = SelectObject(lpDrawItem->hDC, hFramePen); MoveToEx(lpDrawItem->hDC, rect.left, rect.bottom, NULL); LineTo(lpDrawItem->hDC, rect.right, rect.bottom);
//
// we start at the current left
//
rect.top += 2*ncyBorder;
SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_BTNTEXT)); SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_BTNFACE));
SetBkMode(lpDrawItem->hDC, TRANSPARENT);
for (Col=0; Col < lpColumnLB->nColumns; Col++) { //
// get the index number of the current column
//
PhysColumn = lpColumnLB->ColumnOrderTable[Col];
//
// adjust right side to be left side plus width of current column
//
rect.right = rect.left + lpColumnLB->ColumnInfoTable[PhysColumn].Width;
//
// if the button is dpressed, then draw it that way
//
if (lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed) { //
// pick the shadow pen and draw the top-left depressed
//
SelectObject(lpDrawItem->hDC, hShadowPen); MoveToEx(lpDrawItem->hDC, rect.left, rect.bottom, NULL); LineTo(lpDrawItem->hDC, rect.left, rect.top-2*ncyBorder); // bottom-left --> top-left
LineTo(lpDrawItem->hDC, rect.right, rect.top-2*ncyBorder); // top-left --> top-right
//
// pick the Frame pen and draw the Column seperater
//
SelectObject(lpDrawItem->hDC, hFramePen); MoveToEx(lpDrawItem->hDC, rect.right+ncxBorder, rect.top-2*ncyBorder, NULL); LineTo(lpDrawItem->hDC, rect.right+ncxBorder, rect.bottom); // bottom-left --> top-left
//
// move the cursor for whitespace to draw text
//
rect.left += WHITESPACE/2;
// draw the title of the column in the current slot
DrawText(lpDrawItem->hDC, lpColumnLB->ColumnInfoTable[PhysColumn].lpTitle, -1, (LPRECT)&rect, DT_SINGLELINE | DT_LEFT | DT_TOP); rect.left -= WHITESPACE/2; // restore the left position...
} else { // it is not depressed, draw it normal
//
// pick the white pen and draw the top-left highlight
//
SelectObject(lpDrawItem->hDC, hHighlightPen); MoveToEx(lpDrawItem->hDC, rect.left, rect.bottom-ncyBorder, NULL); LineTo(lpDrawItem->hDC, rect.left, rect.top-2*ncyBorder); // bottom-left --> top-left
LineTo(lpDrawItem->hDC, rect.right, rect.top-2*ncyBorder); // top-left --> top-right
//
// pick the shadow pen and draw the bottom-right dark shadow
//
SelectObject(lpDrawItem->hDC, hShadowPen); LineTo(lpDrawItem->hDC, rect.right, rect.bottom-ncyBorder); // top-right --> bottom-right
LineTo(lpDrawItem->hDC, rect.left, rect.bottom-ncyBorder); // bottom-right --> bottom-left
//
// pick the Frame pen and draw the Column seperater
//
SelectObject(lpDrawItem->hDC, hFramePen); MoveToEx(lpDrawItem->hDC, rect.right+ncxBorder, rect.top-2*ncyBorder, NULL); LineTo(lpDrawItem->hDC, rect.right+ncxBorder, rect.bottom); // bottom-left --> top-left
//
// move the cursor for whitespace to draw text
//
rect.left += WHITESPACE/4;
rect.top -= ncyBorder;
// draw the title of the column in the current slot
DrawText(lpDrawItem->hDC, lpColumnLB->ColumnInfoTable[PhysColumn].lpTitle, -1, (LPRECT)&rect, DT_SINGLELINE | DT_LEFT | DT_TOP);
rect.top += ncyBorder; }
//
// adjust the left side of the rect for the width of this column
//
rect.left = rect.right+2*ncxBorder; }
// select the original brush
SelectObject(lpDrawItem->hDC, hOldPen);
// delete my pens
DeletePen(hFramePen); DeletePen(hHighlightPen); DeletePen(hShadowPen);
DeleteBrush(hBackgroundBrush); } } break;
//
// handle sending CLB_DRAWITEM MESSAGES to parent
//
case IDL_COLUMNLISTBOX: { //
// make a copy of the drawitem portion of the struct
//
memcpy(&CLBDrawItemStruct.DrawItemStruct, lpDrawItem, sizeof(DRAWITEMSTRUCT));
//
// fake parent window into thinking our id is the listbox
//
CLBDrawItemStruct.DrawItemStruct.CtlID = GetDlgCtrlID(hwnd); CLBDrawItemStruct.lpColOrder = lpColumnLB->ColumnOrderTable; CLBDrawItemStruct.nColumns = lpColumnLB->nColumns;
CopyRect(&rect, &lpDrawItem->rcItem);
//
// move the cursor for whitespace to draw text
//
rect.left += WHITESPACE/4;
//
// tell the parent to draw each physical column in the appropriate rectangle
//
for (i=0; i < lpColumnLB->nColumns ;i++ ) { //
// get physical column number
//
PhysCol = lpColumnLB->ColumnOrderTable[i];
//
// massage the rect's right to be the left plus the width of the column
//
rect.right = rect.left + lpColumnLB->ColumnInfoTable[PhysCol].Width - WHITESPACE/4;
//
// copy it
//
CopyRect(&CLBDrawItemStruct.rect[i], &rect);
//
// massage the rect's left to be the right + 1
//
rect.left = rect.right + WHITESPACE/4 + 2*ncxBorder ; }
if ((lpColumnLB->Style & LBS_OWNERDRAWFIXED) || (lpColumnLB->Style & VLBS_OWNERDRAWFIXED) ) //
// send a draw message with the physical column order list
// to the parent as they want to draw it
//
SendMessage(hwndParent, CLBN_DRAWITEM, (WPARAM)0, (WPARAM)&CLBDrawItemStruct); else { //
// we want to draw it ourselves...
// NOTE: This assumes that we are LBS_HASSTRINGS and NOT LBS_OWNERDRAWFIXED
//
switch(lpDrawItem->itemAction) { case ODA_FOCUS: DrawFocusRect(lpDrawItem->hDC,(LPRECT)&(lpDrawItem->rcItem)); break;
case ODA_DRAWENTIRE: case ODA_SELECT: // only if we have data...
if (lpDrawItem->itemData) { LPCOLRECORD lpColRecord = (LPCOLRECORD)lpDrawItem->itemData;
if ((lpColRecord == NULL) || (lpColRecord == (LPCOLRECORD)LB_ERR)) break; // bogus data
// Are we highlighted? (highlit?)
if (lpDrawItem->itemState & ODS_SELECTED) { hBackgroundBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHT)); SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { hBackgroundBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_WINDOW)); SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_WINDOWTEXT)); } // FillRect(lpDrawItem->hDC,(LPRECT)&(lpDrawItem->rcItem), hBackgroundBrush);
//
// either way, draw column borders now...
//
hFramePen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_WINDOWFRAME));
hOldPen = SelectObject(lpDrawItem->hDC, hFramePen);
//
// now draw each column in the approved order...
//
for (i=0; i < CLBDrawItemStruct.nColumns ; i++) { //
// draw line of text...
//
ExtTextOut( lpDrawItem->hDC, CLBDrawItemStruct.rect[i].left, CLBDrawItemStruct.rect[i].top, ETO_CLIPPED | ETO_OPAQUE, &CLBDrawItemStruct.rect[i], lpColRecord->pString[CLBDrawItemStruct.lpColOrder[i]], // pointer to string
lstrlen(lpColRecord->pString[CLBDrawItemStruct.lpColOrder[i]]), // length
(LPINT)NULL);
// draw column seperator
ColumnLB_DrawColumnBorder( lpDrawItem->hDC, &CLBDrawItemStruct.rect[i], ClientRect.bottom, hBackgroundBrush); }
// restore old pen
SelectObject(lpDrawItem->hDC, hOldPen);
// destroy pen
DeletePen(hFramePen);
DeleteBrush(hBackgroundBrush); } break; } // end of switch on drawitem action
}
} break; } }
// ------------------------------------------------------------------
// ColumnLBClass_OnCharToItem()
//
// Handles converting keystrokes to items
//
// HISTORY:
// Tom Laird-McConnell 10/18/93 Created
// ------------------------------------------------------------------
int ColumnLBClass_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); LPCOLRECORD lpColRecord; int nCount; int nCurSel; int nNewSel; TCHAR cKey; TCHAR cLBText;
if (hwndListbox != lpColumnLB->hwndTitleList) { RECT ClientRect; GetClientRect(hwnd, &ClientRect);
//
// if the parent is NOT ownerdraw, then we are doing it ourselves, and
// so need to translate the WM_CHAR --> the correct item based on the
// current sort column...
//
if (! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) ) { nCurSel = ListBox_GetCurSel(lpColumnLB->hwndList); if (IsCharAlphaNumeric((TCHAR)ch)) { nNewSel = nCurSel + 1; nCount = ListBox_GetCount(lpColumnLB->hwndList); cKey = (TCHAR) toupper( (TCHAR)ch );
// loop thru items starting with the one just after
// the current selection, until we are too far along,
// then wrap around to the beginning and
// keep going until we hit our original selection.
for (; nNewSel != nCurSel ; nNewSel++ ) { // make sure that we do't try to compare at location -1
if( nNewSel == -1) continue;
lpColRecord = (LPCOLRECORD)ListBox_GetItemData(lpColumnLB->hwndList, nNewSel);
// if this comes back as LB_ERR then we are off the end of the list
if( lpColRecord == (LPCOLRECORD)LB_ERR ) { nNewSel = -1; // increment will move to 0
continue; }
cLBText = (TCHAR) toupper( *lpColRecord->pString[ lpColumnLB->ColumnOrderTable[ lpColumnLB->SortColumn ]] );
if ( cLBText == cKey ) { // we found it ...
// change the current selection
if( lpColumnLB->Style & LBS_MULTIPLESEL ) { // multiple selection LB, just move fuzzy rect
ListBox_SetCaretIndex(lpColumnLB->hwndList, nNewSel);
// BUGBUG change of caret does not have a notification?
} else { // single sel LB, change the sel
ListBox_SetCurSel(lpColumnLB->hwndList, nNewSel);
// notify our parent if we need to
if( lpColumnLB->Style & LBS_NOTIFY ) { SendMessage( GetParent( hwnd ), WM_COMMAND, MAKEWPARAM( GetDlgCtrlID( hwnd), LBN_SELCHANGE), (LPARAM)hwnd); // NOTE: substitute ourselves
// as the source of the message
} }
return(-1); // we handled it...
} else if (nNewSel == nCount-1) { // we have gone beyond it
// or are at the end of the list...
// we need to wrap to the beginning
// (this will get incremented above prior to use)
nNewSel = -1; continue; } }
// we did not find our target
return(nCurSel); } else // not an alphanumeric, just return the current selection
return(nCurSel); } else //
// pass on to parent as a WM_CHARTOITEM, but with the HIWORD(wParam) == SORT COLUMN
//
return((int)SendMessage( GetParent(hwnd), CLBN_CHARTOITEM, MAKEWPARAM(ch, lpColumnLB->SortColumn), (LPARAM)hwnd)); } else {
return 0; } }
// ------------------------------------------------------------------
// ColumnLBClass_OnNumberCols()
//
// case CLB_GETNUMBERCOLS : // get the number of columns (ret=NumCols)
// case CLB_SETNUMBERCOLS : // set the number of columns (wparam=NumCols)
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
BYTE ColumnLBClass_OnNumberCols(HWND hwnd, BYTE NewNumberCols, BOOL fSetColumns) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
//
// if we are modifying it
//
if (fSetColumns) { //
// if the value is a new value
//
if (lpColumnLB->nColumns != NewNumberCols) { lpColumnLB->nColumns = NewNumberCols;
// force a redraw of the entire columnlb...
InvalidateRect(hwnd, NULL, TRUE); } } return lpColumnLB->nColumns; }
// ------------------------------------------------------------------
// ColumnLBClass_OnColWidth()
//
// case CLB_GETCOLWIDTH : // get a column width (wParm=Physical Column ret=ColWidth in DU's)
// case CLB_SETCOLWIDTH : // set a column width (wParm=Physical Column lParam=Width)
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
int ColumnLBClass_OnColWidth(HWND hwnd, BYTE Column, int NewWidth, BOOL fSetWidth) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); int cxExtent; RECT rect;
//
// if we are modifying it
//
if (fSetWidth) { //
// if the value is a new value
//
if (lpColumnLB->ColumnInfoTable[Column].Width != NewWidth) { lpColumnLB->ColumnInfoTable[Column].Width = NewWidth;
cxExtent = ColumnLBClass_ComputeOffsets(hwnd);
GetClientRect(hwnd, &rect);
//
// send the message to the title listbox as well
//
SendMessage(lpColumnLB->hwndTitleList, LB_SETHORIZONTALEXTENT, cxExtent, 0L);
//
// pass it on to the child listbox, using VLB_SETHOR if appropriate...
//
SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, cxExtent, 0L);
//
// if the new extent is smaller then the space available, move the position
//
if (rect.right > cxExtent) { // #ifdef DEBUG
// dprintf(TEXT("Reset HSCROLL pos to far left\n"));
// #endif
// move position to far left
SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0);
// do the same for the title list
SendMessage(lpColumnLB->hwndTitleList, WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0); }
InvalidateRect(lpColumnLB->hwndList, NULL, TRUE); InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE); } } return (DWORD)lpColumnLB->ColumnInfoTable[Column].Width; }
// ------------------------------------------------------------------
// ColumnLBClass_OnColTitle()
//
// case CLB_GETCOLTITLE : // get a column's title (wParm=Physical Column, ret=Title)
// case CLB_SETCOLTITLE : // set a column's title (wParm=Physical Col, lParm=Title)
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
LPTSTR ColumnLBClass_OnColTitle(HWND hwnd, BYTE Column, LPTSTR lpTitle, BOOL fSetTitle) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
//
// if we are modifying it
//
if (fSetTitle) { //
// if the value is a new value
//
if (lpColumnLB->ColumnInfoTable[Column].lpTitle != lpTitle) { //
// BUGBUG, is there more to do here?
//
lpColumnLB->ColumnInfoTable[Column].lpTitle = lpTitle;
//
// invalidate the title
//
InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE); } } return (LPTSTR)lpColumnLB->ColumnInfoTable[Column].lpTitle; }
// ------------------------------------------------------------------
// ColumnLBClass_OnSortCol()
//
// case CLB_GETSORTCOL : // get the sort column (ret=Physical Col)
// case CLB_SETSORTCOL : // set the sort column (wParm=Physical Col)
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
BYTE ColumnLBClass_OnSortCol(HWND hwnd, BYTE NewSortCol, BOOL fSetSortCol) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); DWORD nCount; PDWORD_PTR lpListboxContents; DWORD i; int nCurSel; DWORD_PTR ItemData; HCURSOR hCursor;
//
// if we are modifying it
//
if (fSetSortCol) { hCursor = SetCursor(LoadCursor(0, IDC_WAIT));
// set new sort value
lpColumnLB->SortColumn = NewSortCol;
// need to resort listbox
nCount = ListBox_GetCount(lpColumnLB->hwndList);
// need to get current select
nCurSel = ListBox_GetCurSel(lpColumnLB->hwndList);
// and it's item data
ItemData = ListBox_GetItemData(lpColumnLB->hwndList, nCurSel);
SetWindowRedraw(lpColumnLB->hwndList, FALSE);
//
// allocate space for the listbox contents
//
lpListboxContents = (PDWORD_PTR) GlobalAllocPtr(GPTR, sizeof(DWORD_PTR) * nCount);
//
// retrieve all of the data values
//
for (i=0; i<nCount; i++) lpListboxContents[i] = ListBox_GetItemData(lpColumnLB->hwndList, i);
//
// reset the listbox contents
//
lpColumnLB->fSorting = TRUE; // disable deleting while sorting...
SendMessage(lpColumnLB->hwndList, LB_RESETCONTENT, 0, 0); lpColumnLB->fSorting = FALSE; // reenable it...
//
// now re-add all of the items, with the new sort column
//
for (i=0; i<nCount ; i++ ) { nCurSel = ListBox_AddString(lpColumnLB->hwndList, lpListboxContents[i]); }
// reselect selected item...
for (i=0; i < nCount ; i++) { if (ItemData == (DWORD)ListBox_GetItemData(lpColumnLB->hwndList, i)) // then select it
ListBox_SetCurSel(lpColumnLB->hwndList, i); }
GlobalFreePtr(lpListboxContents);
SetWindowRedraw(lpColumnLB->hwndList, TRUE);
InvalidateRect(lpColumnLB->hwndList, NULL, TRUE);
SetCursor(hCursor); } return lpColumnLB->SortColumn; }
// ------------------------------------------------------------------
// ColumnLBClass_OnColOrder()
//
// case CLB_GETCOLORDER : // get the virtual order of the physical columns (ret=LPDWORD order table)
// case CLB_SETCOLORDER : // set the virtual order of the physical columns (ret=LPDWORD order table, wParamn=LPDWORD new order)
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
LPBYTE ColumnLBClass_OnColOrder(HWND hwnd, LPBYTE NewColOrder, BOOL fSetOrder) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
//
// if we are modifying it
//
if (fSetOrder) { //
// copy the new order over the old order
//
memcpy(lpColumnLB->ColumnOrderTable, NewColOrder, lpColumnLB->nColumns);
ColumnLBClass_ComputeOffsets(hwnd);
//
// cause listbox to be redrawn
//
InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE); InvalidateRect(lpColumnLB->hwndList, NULL, TRUE); }
return lpColumnLB->ColumnOrderTable; }
// ------------------------------------------------------------------
// ColumnLBClass_OnColOffsets()
//
// case CLB_GETCOLOFFSETS : // gets the incremental col offsets (ret=LPDWORD)
// case CLB_SETCOLOFFSETS : // sets the incremental col offsets (wParam = LPDWORD)
//
// HISTORY:
// Tom Laird-McConnell 4/18/93 Created
// ------------------------------------------------------------------
LPINT ColumnLBClass_OnColOffsets(HWND hwnd, LPINT NewOffsetTable, BOOL fSetOffsets) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
//
// if we are modifying it
//
// if (fSetOffsets)
// {
// for (i=0; i < lpColumnLB->nColumns ; i++ )
// {
// lpColumnLB->ColumnOffsetTable[i] = NewOffsetTable[i];
// }
// }
return (lpColumnLB->ColumnOffsetTable); }
// ------------------------------------------------------------------
// ColumnLBClass_OnAutoWidths()
//
//
// Handles CLB_AUTOWIDTHS messages to calculate the width of each field, and
// to calculate the offsets automatically... (if column is -1 , then all columns)
// ColumnToCompute is in Physical Columns
//
// returns: The horiztonal extent of all of the columns...
//
// HISTORY:
// Tom Laird-McConnell 5/1/93 Created
// ------------------------------------------------------------------
LRESULT ColumnLBClass_OnAutoWidth(HWND hwnd, BYTE ColumnToCompute) { HDC hdc; BYTE nColumn; LONG cxExtent; SIZE Size; TEXTMETRIC tm; LPCOLUMNINFO lpColumnInfo, lpPrevColumnInfo;
LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0); HFONT hOldFont; DWORD_PTR OldStyle, NewStyle;
hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); hOldFont = SelectFont(hdc, lpColumnLB->hFont); lpPrevColumnInfo = NULL;
//
// based on column order, compute the widths and offsets of each column
// NOTE: nColumn is the physical column
//
lpColumnInfo = lpColumnLB->ColumnInfoTable; cxExtent = 0; for (nColumn=0; nColumn < lpColumnLB->nColumns; nColumn++, lpColumnInfo++) { // bail out if column title is not there...
if ((lpColumnInfo->lpTitle == NULL) || (lpColumnInfo->lpTitle[0] == '\0')) continue; // try next column
//
// only if it is a column we are supposed to change
//
if ((ColumnToCompute == (BYTE)-1) || (nColumn == ColumnToCompute)) { GetTextExtentPoint( hdc, (LPTSTR)lpColumnInfo->lpTitle, lstrlen(lpColumnInfo->lpTitle), &Size);
//
// the width is the text extent of the string plus some whitespace
//
lpColumnInfo->Width = (WHITESPACE/2) + Size.cx; } }
SelectFont(hdc, hOldFont); ReleaseDC(hwnd, hdc);
//
// now adjust the offsets to show new values
//
cxExtent = ColumnLBClass_ComputeOffsets(hwnd);
if (lpColumnLB->fUseVlist) OldStyle = SendMessage(lpColumnLB->hwndList, VLB_GETLISTBOXSTYLE, 0L, 0L); else OldStyle = GetWindowLongPtr(lpColumnLB->hwndList, GWL_STYLE);
//
// send the message to the title listbox as well
//
SendMessage(lpColumnLB->hwndTitleList, LB_SETHORIZONTALEXTENT, cxExtent, 0L);
SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, cxExtent, 0L);
if (lpColumnLB->fUseVlist) NewStyle = SendMessage(lpColumnLB->hwndList, VLB_GETLISTBOXSTYLE, 0L, 0L); else NewStyle = GetWindowLongPtr(lpColumnLB->hwndList, GWL_STYLE);
//
// if the horizontal scroll bar is gone, then reset hscroll position
//
if ((NewStyle & WS_HSCROLL) != (OldStyle & WS_HSCROLL)) { // move position to far left
SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0); }
InvalidateRect(lpColumnLB->hwndList, NULL, TRUE); InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE);
return(cxExtent); }
// ------------------------------------------------------------------
// ColumnLBClass_ComputeOffsets()
//
// returns text extent...
//
// HISTORY:
// Tom Laird-McConnell 5/3/93 Created
// ------------------------------------------------------------------
int ColumnLBClass_ComputeOffsets(HWND hwnd) { BYTE i; LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); LPINT lpOffset; LPBYTE lpOrder; LPCOLUMNINFO lpColumnInfo; BYTE PhysColumn; int ncxBorder = GetSystemMetrics(SM_CXBORDER);
//
// recalc the offsets table using the current virtual order
//
lpOffset = lpColumnLB->ColumnOffsetTable; lpOrder = lpColumnLB->ColumnOrderTable; lpColumnInfo = lpColumnLB->ColumnInfoTable; //
// first offset is always 0
//
lpOffset[0] = 0; for (i=1; i < lpColumnLB->nColumns + 1 ; i++ ) { PhysColumn = lpOrder[i-1];
//
// this offset is the previous offset plus the previous width
//
lpOffset[i] = lpOffset[i-1] + lpColumnInfo[PhysColumn].Width + 2 * ncxBorder; } //
// last offset is also new text extent...
return(lpOffset[lpColumnLB->nColumns]); }
// ------------------------------------------------------------------
// ColumnLBClass_OnLButtonDown()
//
// Handles WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages from the client
// area above the listbox
//
//
// HISTORY:
// Tom Laird-McConnell 5/3/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); BYTE i; int AdjustedX = x - lpColumnLB->xPos; HCURSOR hCursor; BYTE PhysColumn; BYTE VirtColumn; RECT rect; POINT point;
point.x = x; point.y = y; GetClientRect(lpColumnLB->hwndTitleList, &rect);
// only if this is a right mouse button from
if (PtInRect(&rect, point)) { //
// if this is a down-click, and it is on a column border, then go into resize mode
//
for(i=1; i < lpColumnLB->nColumns+1; i++) { //
// check to see if this is a column offset
//
if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i]-4) && (AdjustedX < lpColumnLB->ColumnOffsetTable[i]+4)) { VirtColumn = i-1; PhysColumn = lpColumnLB->ColumnOrderTable[VirtColumn];
//
// x is the right-side of the column i-1
//
lpColumnLB->fMouseState = MOUSE_COLUMNRESIZE; lpColumnLB->xPrevPos = 0; lpColumnLB->ColClickStart = VirtColumn; // virtual column
SetCapture(hwnd);
hCursor = LoadCursor(lpColumnLB->hInstance, TEXT("SizebarHCursor")); SetCursor(hCursor); return; } #ifdef DRAG
else //
// if this is a down-click, and it is on a column title,
//
if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i-1]) && (AdjustedX < lpColumnLB->ColumnOffsetTable[i])) { //
// whether it is a double-or single click, we need to draw down button state
//
VirtColumn = i-1; PhysColumn = lpColumnLB->ColumnOrderTable[VirtColumn];
lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = TRUE;
GetClientRect(lpColumnLB->hwndTitleList, &rect); rect.left = lpColumnLB->ColumnOffsetTable[VirtColumn] + lpColumnLB->xPos; rect.right = lpColumnLB->ColumnOffsetTable[VirtColumn+1] + lpColumnLB->xPos;
//
// if this is a double-click, AND we are in sort mode then handle this as a sort request on the
// column double-clicked on
//
if (fDoubleClick) { if (GetWindowLong(hwnd, GWL_STYLE) & LBS_SORT) { //
// then default to doing a sort
//
SendMessage(hwnd, CLB_SETSORTCOL, (WPARAM)PhysColumn, (LPARAM)0); } else { //
// tell parent that the user double-clicked on PhysColumn
//
SendMessage(GetParent(hwnd), CLBN_TITLEDBLCLK, (WPARAM)GetDlgCtrlID(hwnd), (LPARAM) PhysColumn); } //
// we are done with double-click, so redraw window
//
lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = FALSE;
InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
return; } else { // then go into single click mode/or column drag mode
//
// then x, y is in column i-1
//
lpColumnLB->fMouseState = MOUSE_COLUMNCLICK; lpColumnLB->ColClickStart = VirtColumn;
CopyRect(&lpColumnLB->ColClickRect, &rect);
// lpColumnLB->ColClickRect.left += (lpColumnLB->ColClickRect.right - lpColumnLB->ColClickRect.left)/3;
// lpColumnLB->ColClickRect.right -= (lpColumnLB->ColClickRect.right - lpColumnLB->ColClickRect.left)/3;
SetCapture(hwnd); InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
GetWindowRect(lpColumnLB->hwndTitleList, &rect); ClipCursor(&rect); return; } } #endif
} } }
// ------------------------------------------------------------------
// ColumnLBClass_OnMouseMove()
//
// Handles Mouse movement messages from the client
// area above the listbox
//
//
// HISTORY:
// Tom Laird-McConnell 5/3/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); RECT rect; HDC hdc; BYTE i; int AdjustedX = x - lpColumnLB->xPos; POINT Point; HCURSOR hCursor;
switch (lpColumnLB->fMouseState) { case 0 : // not in mouse mode at all, so just track changing cursor when over column border
for(i=1; i < lpColumnLB->nColumns + 1; i++) { //
// check to see if this is a column offset
//
if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i]-4) && (AdjustedX < lpColumnLB->ColumnOffsetTable[i]+4)) { //
// it is, so set the cursor and return
//
hCursor = LoadCursor(lpColumnLB->hInstance, TEXT("SizebarHCursor")); SetCursor(hCursor); return; } } SetCursor(LoadCursor(0,IDC_ARROW)); break;
case MOUSE_COLUMNRESIZE: GetClientRect(hwnd, &rect);
//
// as long as we haven't moved past the previous column, and we haven't moved out of the rect
//
if (AdjustedX < lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8) { x += (lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8)-AdjustedX; AdjustedX = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8; }
if (x < rect.right) { hdc = GetDC(hwnd);
// un invert previous postion
if (lpColumnLB->xPrevPos) { rect.left = lpColumnLB->xPrevPos; rect.right = rect.left+1; InvertRect(hdc, &rect); }
lpColumnLB->xPrevPos = x;
// invert new position
rect.left = x; rect.right = rect.left+1; InvertRect(hdc, &rect);
ReleaseDC(hwnd, hdc); } break;
case MOUSE_COLUMNDRAG: //
// if this is a column drag, we track the messages until the mouse has moved
// back INTO the original column rectangle, if it does this, then we switchback to
// COLUMNCLICK mode, until they let go, or move back out
//
Point.x = x; Point.y = y;
GetClientRect(lpColumnLB->hwndTitleList, &rect);
// if it is on far RIGHT generate WM_HSCROLL right message
if (x >= rect.right-2) { SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL); return; }
// if it is on far RIGHT generate WM_HSCROLL left message
if (x <= rect.left+2) { SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); return; }
// rect.right -= lpColumnLB->xPos;
//
// //
// // it if is out of the title area, or if it is in the original column
// //
// if ((PtInRect(&lpColumnLB->ColClickRect, Point) == TRUE) || // original column
// (PtInRect(&rect, Point) == FALSE) ) // title area
// {
// //
// // then it has moved back into the original column, switch to
// //COLUMNCLICK mode
// //
// lpColumnLB->fMouseState = MOUSE_COLUMNCLICK;
//
// SetCursor(LoadCursor(0, IDC_ARROW));
// return;
// }
break;
case MOUSE_COLUMNCLICK: //
// if this is a column click, we track the messages until the mouse has moved
// outside of the original column rectangle, if it does this, then we switch to
// COLUMNDRAG mode, until they let go, or until they move back to the original
// column.
//
Point.x = x; Point.y = y;
GetClientRect(lpColumnLB->hwndTitleList, &rect); rect.right -= lpColumnLB->xPos;
//
// if it is outside of the original column, and inside title area, then swtich to
// DRAG mode
//
if ((PtInRect(&lpColumnLB->ColClickRect, Point) == FALSE) && //
(PtInRect(&rect, Point) == TRUE) ) // title area
{
//
// then it has moved outside of the column, switch to
//COLUMNDRAG mode
//
lpColumnLB->fMouseState = MOUSE_COLUMNDRAG;
hCursor = LoadCursor(lpColumnLB->hInstance, TEXT("ColDragCursor")); SetCursor(hCursor); } break; } }
// ------------------------------------------------------------------
// ColumnLBClass_OnLButtonUp()
//
// Handles WM_LBUTTONUp messages from the client
// area above the listbox
//
//
// HISTORY:
// Tom Laird-McConnell 5/3/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
BYTE PhysColumn = lpColumnLB->ColumnOrderTable[lpColumnLB->ColClickStart]; BYTE PhysSourceColumn;
int AdjustedX = x - lpColumnLB->xPos;
POINT Point;
BYTE NewOrderTable[MAX_COLUMNS];
LPBYTE lpNewOrderTable = NewOrderTable; LPBYTE lpOrderTable = lpColumnLB->ColumnOrderTable;
BYTE CurrentCol; BYTE DestCol; BYTE SourceCol; TCHAR Direction;
BYTE i; HDC hdc; RECT rect;
SetCursor(LoadCursor(0, IDC_ARROW)); // go back to arrow
switch (lpColumnLB->fMouseState) { case MOUSE_COLUMNRESIZE: //
// if we were in resize column mode, then resize the column to the left of the border
//
ReleaseCapture(); ClipCursor(NULL);
lpColumnLB->fMouseState = 0;
// clean up line
GetClientRect(hwnd, &rect); hdc = GetDC(hwnd);
// massage the value to make sure it's in the right range...
if (AdjustedX < lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8) AdjustedX = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8;
// un invert previous postion
if (lpColumnLB->xPrevPos) { rect.left = lpColumnLB->xPrevPos; rect.right = rect.left+1; InvertRect(hdc, &rect); }
ReleaseDC(hwnd, hdc);
//
// set the physical column width to be the current x position - the current virtual column offset
//
SendMessage(hwnd, CLB_SETCOLWIDTH, (WPARAM)PhysColumn, (LPARAM)AdjustedX - lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]); break;
case MOUSE_COLUMNDRAG:
lpColumnLB->fMouseState = 0;
ReleaseCapture(); ClipCursor(NULL);
lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = FALSE;
//
// we need to figure out what column we ended up on
//
for(i=1; i < lpColumnLB->nColumns+1; i++) { //
// if it fits in this columns area, then this is the destination column
//
if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i-1]) && (AdjustedX < lpColumnLB->ColumnOffsetTable[i])) { //
// make duplicate of the table
//
memcpy(NewOrderTable, lpOrderTable, sizeof(BYTE)*lpColumnLB->nColumns);
//
// i-1 is the destination column! (virtual)
//
SourceCol = lpColumnLB->ColClickStart; // virtual
DestCol = i-1; // virtual
PhysSourceColumn = lpColumnLB->ColumnOrderTable[SourceCol]; // physical
Direction = (SourceCol > DestCol) ? -1 : 1;
CurrentCol = SourceCol; while (CurrentCol != DestCol) { NewOrderTable[CurrentCol] = NewOrderTable[CurrentCol + Direction]; CurrentCol += Direction; }
//
// ok, it's equal to destination, so let's put the source Physical value into the destination
//
NewOrderTable[CurrentCol] = PhysSourceColumn;
//
// ok, so now set the order to the new order
//
SendMessage(hwnd, CLB_SETCOLORDER, (WPARAM)0, (LPARAM)NewOrderTable); } }
GetClientRect(lpColumnLB->hwndTitleList, &rect); rect.left = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart] + lpColumnLB->xPos; rect.right = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart+1] + lpColumnLB->xPos; InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
break;
case MOUSE_COLUMNCLICK: //
// if this is a column click, we track the messages until the mouse has moved
//
lpColumnLB->fMouseState = 0;
ReleaseCapture(); ClipCursor(NULL);
lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = FALSE;
GetClientRect(lpColumnLB->hwndTitleList, &rect); rect.left = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart] + lpColumnLB->xPos; rect.right = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart+1] + lpColumnLB->xPos; InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
//
// now send a CLBN_SINGLECLICK message to the parent, only if the mousebutton was let up in the original
// column
//
Point.x = AdjustedX; Point.y = y; if (PtInRect(&lpColumnLB->ColClickRect, Point) == TRUE) SendMessage(GetParent(hwnd), CLBN_TITLESINGLECLK, (WPARAM)GetDlgCtrlID(hwnd), (LPARAM)PhysColumn); return; } }
// ------------------------------------------------------------------
// ColumnLBClass_OnRButtonDown()
//
// Handles WM_RBUTTON_DOWN messages
// alg:
//
// figure out where we are
// determine listbox item
// find height of rows
// translate mouse Y into a row number
// are we VLIST?
// Yes, Get TopIndex
// are we Owner Draw?
// Yes
// Send message to VLIST to get the data for row number
// No
// item number + TopIndex is the info the parent needs.
// No
// item number is the info the parent needs
// determine column
// calc which column taking into account scrolling
// send message to parent with info
// The parent will receive the column in wParam and the item in lParam. lParam
// needs to be the item because it might be the owner draw data.
//
//
//
// HISTORY:
// Steve Hiskey 10/19/93 Created
// ------------------------------------------------------------------
void ColumnLBClass_OnRButtonDown (HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L); // get the item height here and not when the OnFont message is
// processed. ?? we get different/wrong results otherwise.
int ItemHeight = (int)ListBox_GetItemHeight(hwnd,1); int Item = y / ItemHeight; BYTE i; int AdjustedX = x - lpColumnLB->xPos; BYTE VirtColumn; DWORD TopIndex; CLBRBUTTONSTRUCT RButtonStruct; BOOL GotOne = FALSE; BOOL fTemp;
RButtonStruct.x = x; RButtonStruct.y = y + lpColumnLB->yTitle; RButtonStruct.hwndChild = hwnd;
//
// we already have the item (non VList), figure out which column
//
for(i=1; i < lpColumnLB->nColumns+1; i++) { if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i-1]) && (AdjustedX < lpColumnLB->ColumnOffsetTable[i])) { //
// we have our column. Get the Physical Column. The parent of this column
// list box know what columns are interesting... and how the physical columns
// map to the virtual columns.
//
VirtColumn = i-1; RButtonStruct.PhysColumn = lpColumnLB->ColumnOrderTable[VirtColumn]; GotOne = TRUE; break; } } if ( !GotOne) return;
// are we VLIST?
if ( lpColumnLB->fUseVlist ) { DWORD Style;
// are we owner draw? If so, then we don't care about TopIndex, we just want
// the instance data
Style = (DWORD)SendMessage(lpColumnLB->hwndList, VLB_GETVLISTSTYLE, 0, 0L); if ( Style && VLBS_USEDATAVALUES ) { // we are use data values. This means that we must ask the VList for the
// data and this is the data is the identifier of the row. ie, the data the
// VList stores is the structure needed to identify and display the line.
RButtonStruct.Index = ListBox_GetItemData(lpColumnLB->hwndList, Item );
} else { // we are a normal vlist box. Get the top index and add our offset
// from top of listbox to it.
TopIndex = (DWORD)SendMessage(lpColumnLB->hwndList, LB_GETTOPINDEX, 0, 0L); RButtonStruct.Index = TopIndex + Item; }
} else { // we are a normal list box. We need to know what item we are looking at.
// ask the listbox for the top index.
TopIndex = (DWORD)SendMessage(lpColumnLB->hwndList, LB_GETTOPINDEX, 0, 0L); RButtonStruct.Index = TopIndex + Item; }
// if they have hit rButton, we should set the focus to this item (lButton)... since
// WE are providing the CLB_SETCURSEL, we must tell the parent... some weird rule about
// if the user does a set cur sel, then the parent is notified, but if the parent does
// the set cur sel, the parent is not notified... since we are neither the parent or the
// user, we have to do both.
// if VLIST, we need to send just the item, top TopIndex + Item...
if ( lpColumnLB->fUseVlist ) fTemp = ListBox_SetCurSel(lpColumnLB->hwndList, Item); else fTemp = ListBox_SetCurSel(lpColumnLB->hwndList, RButtonStruct.Index);
if ( fTemp ) SendMessage(GetParent(hwnd), WM_COMMAND, GetDlgCtrlID( lpColumnLB->hwndList), MAKELPARAM(lpColumnLB->hwndList, LBN_SELCHANGE));
// we are ready to send which column and which row to the parent.
SendMessage ( GetParent (hwnd), CLBN_RBUTTONDOWN, (WORD)0, (LPARAM) &RButtonStruct );
}
// ------------------------------------------------------------------
// ColumnLBClass_DrawColumnBorder()
//
//
// HISTORY:
// Tom Laird-McConnell 3/15/94 created
// ------------------------------------------------------------------
void ColumnLB_DrawColumnBorder(HDC hDC, RECT *lpRect, int Bottom, HBRUSH hBackgroundBrush) { int ncxBorder = GetSystemMetrics(SM_CXBORDER); RECT rect;
CopyRect(&rect, lpRect);
// fill in left side of rect
rect.right = rect.left; rect.left -= (WHITESPACE/4); FillRect(hDC, &rect, hBackgroundBrush);
// fill in right side of rect
rect.left = lpRect->right; rect.right = lpRect->right + ncxBorder; FillRect(hDC, &rect, hBackgroundBrush);
// draw the line itself
MoveToEx( hDC, rect.right, rect.top, NULL); LineTo( hDC, rect.right, Bottom); }
|