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.
1015 lines
30 KiB
1015 lines
30 KiB
/* Copyright (c) 1995, Microsoft Corporation, all rights reserved
|
|
**
|
|
** lvx.c
|
|
** Listview extension routines
|
|
** Listed alphabetically
|
|
**
|
|
** 11/25/95 Steve Cobb
|
|
** Some adapted from \\ftp\data\softlib\mslfiles\odlistvw.exe sample code.
|
|
*/
|
|
|
|
#include <windows.h> // Win32 root
|
|
#include <windowsx.h> // Win32 macro extensions
|
|
#include <commctrl.h> // Win32 common controls
|
|
#include <debug.h> // Trace and assert
|
|
#include <uiutil.h> // Our public header
|
|
#include <lvx.rch> // Our resource constants
|
|
|
|
|
|
/* List view of check boxes state indices.
|
|
*/
|
|
#define SI_Unchecked 1
|
|
#define SI_Checked 2
|
|
#define SI_DisabledUnchecked 3
|
|
#define SI_DisabledChecked 4
|
|
|
|
/* Text indents within a column in pixels. If you mess with the dx, you're
|
|
** asking for misalignment problems with the header labels. BTW, the first
|
|
** column doesn't line up with it's header if there are no icons. Regular
|
|
** list view has this problem, too. If you try to fix this you'll wind up
|
|
** duplicating the AUTOSIZE_USEHEADER option of ListView_SetColumnWidth.
|
|
** Should be able to change the dy without causing problems.
|
|
*/
|
|
#define LVX_dxColText 4
|
|
#define LVX_dyColText 1
|
|
|
|
/* Guaranteed vertical space between icons. Should be able to mess with this
|
|
** without causing problems.
|
|
*/
|
|
#define LVX_dyIconSpacing 1
|
|
|
|
/* The atom identifying our context property suitable for use by the Windows
|
|
** XxxProp APIs. A Prop is used to associate context information (the address
|
|
** of the WNDPROC we subclassed) with a "list view of check boxes" window.
|
|
*/
|
|
static LPCWSTR g_lvxcbContextId = NULL;
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Local prototypes
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
LRESULT APIENTRY
|
|
LvxcbProc(
|
|
IN HWND hwnd,
|
|
IN UINT unMsg,
|
|
IN WPARAM wparam,
|
|
IN LPARAM lparam );
|
|
|
|
BOOL
|
|
LvxDrawItem(
|
|
IN DRAWITEMSTRUCT* pdis,
|
|
IN PLVXCALLBACK pLvxCallback );
|
|
|
|
BOOL
|
|
LvxMeasureItem(
|
|
IN HWND hwnd,
|
|
IN OUT MEASUREITEMSTRUCT* pmis );
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** ListView of check boxes
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
BOOL
|
|
ListView_GetCheck(
|
|
IN HWND hwndLv,
|
|
IN INT iItem )
|
|
|
|
/* Returns true if the check box of item 'iItem' of listview of checkboxes
|
|
** 'hwndLv' is checked, false otherwise. This function works on disabled
|
|
** check boxes as well as enabled ones.
|
|
*/
|
|
{
|
|
UINT unState;
|
|
|
|
unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
|
|
return !!((unState == INDEXTOSTATEIMAGEMASK( SI_Checked )) ||
|
|
(unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )));
|
|
}
|
|
|
|
BOOL
|
|
ListView_IsCheckDisabled (
|
|
IN HWND hwndLv,
|
|
IN INT iItem)
|
|
|
|
/* Returns true if the check box of item 'iItem' of listview of checkboxes
|
|
** 'hwndLv' is disabled, false otherwise.
|
|
*/
|
|
{
|
|
UINT unState;
|
|
unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
|
|
|
|
if ((unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )) ||
|
|
(unState == INDEXTOSTATEIMAGEMASK( SI_DisabledUnchecked )))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
ListView_DisableCheck (
|
|
IN HWND hwndLv,
|
|
IN INT iItem)
|
|
|
|
/* Disables a check box of item 'iItem' of listview of checkboxes. Once
|
|
** disabled, ListView_SetCheck will have no effect on the item until
|
|
** ListView_EnableCheck(...) is called for this item. Likewise, there is no
|
|
** way through the UI to change the check of this item until it is enabled.
|
|
** Calling this function on a disabled check has no effect.
|
|
*/
|
|
{
|
|
BOOL fCheck;
|
|
|
|
fCheck = ListView_GetCheck(hwndLv, iItem);
|
|
|
|
ListView_SetItemState( hwndLv, iItem,
|
|
INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_DisabledChecked : SI_DisabledUnchecked),
|
|
LVIS_STATEIMAGEMASK );
|
|
}
|
|
|
|
VOID
|
|
ListView_EnableCheck (
|
|
IN HWND hwndLv,
|
|
IN INT iItem)
|
|
|
|
/* Reverses the effect of ListView_DisableCheck.
|
|
*/
|
|
{
|
|
BOOL fCheck;
|
|
|
|
fCheck = ListView_GetCheck(hwndLv, iItem);
|
|
|
|
ListView_SetItemState( hwndLv, iItem,
|
|
INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ),
|
|
LVIS_STATEIMAGEMASK );
|
|
}
|
|
|
|
|
|
UINT
|
|
ListView_GetCheckedCount(
|
|
IN HWND hwndLv )
|
|
|
|
/* Returns the number of checked items in 'hwndLv' regardless of whether
|
|
** they are disabled.
|
|
*/
|
|
{
|
|
UINT c = 0;
|
|
INT i = -1;
|
|
|
|
while ((i = ListView_GetNextItem( hwndLv, i, LVNI_ALL )) >= 0)
|
|
{
|
|
if (ListView_GetCheck( hwndLv, i ))
|
|
++c;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ListView_InstallChecks(
|
|
IN HWND hwndLv,
|
|
IN HINSTANCE hinst )
|
|
|
|
/* Initialize "list of checkbox" handling for listview 'hwndLv'. 'Hinst'
|
|
** is the module instance containing the two checkbox icons. See LVX.RC.
|
|
**
|
|
** Returns true if successful, false otherwise. Caller must eventually
|
|
** call 'ListView_UninstallChecks', typically in WM_DESTROY processing.
|
|
*/
|
|
{
|
|
HICON hIcon;
|
|
HIMAGELIST himl;
|
|
WNDPROC pOldProc;
|
|
//Add this for RTL(right to left, mirrored windows version)
|
|
//whistler bug 41349 gangz
|
|
//
|
|
BOOL fMirrored=FALSE;
|
|
DWORD dwLayout;
|
|
|
|
|
|
// pmay: 397395
|
|
//
|
|
// Prevent endless loops resulting from accidentally calling this
|
|
// api twice.
|
|
//
|
|
pOldProc = (WNDPROC)GetWindowLongPtr(hwndLv, GWLP_WNDPROC);
|
|
if (pOldProc == LvxcbProc)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//get current application's layout (RTL or normal) gangz
|
|
// for whistler bug 41349
|
|
//There are two ways:
|
|
//(1) use GetWindowLong() with GWL_EXSTYLE for WS_EX_LAYOUTRTL style if
|
|
// you have a window handler available
|
|
//(2) use GetProcessDefaultLayout() to get the layout for the current
|
|
// process, and compare that against LAYOUT_RTL
|
|
//
|
|
dwLayout = GetWindowLong(hwndLv, GWL_EXSTYLE);
|
|
if ( WS_EX_LAYOUTRTL & dwLayout )
|
|
{
|
|
fMirrored = TRUE;
|
|
}
|
|
|
|
/* Build checkbox image lists.
|
|
*/
|
|
himl = ImageList_Create(
|
|
GetSystemMetrics( SM_CXSMICON ),
|
|
GetSystemMetrics( SM_CYSMICON ),
|
|
ILC_MASK, 2, 2 );
|
|
|
|
/* The order these are added is significant since it implicitly
|
|
** establishes the state indices matching SI_Unchecked and SI_Checked.
|
|
*/
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Unchecked ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_AddIcon( himl, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( fMirrored?IID_CheckedRTL : IID_Checked ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_AddIcon( himl, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledUnchecked ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_AddIcon( himl, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( fMirrored?IID_DisabledCheckedRTL : IID_DisabledChecked ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_AddIcon( himl, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
ListView_SetImageList( hwndLv, himl, LVSIL_STATE );
|
|
|
|
/* Register atom for use in the Windows XxxProp calls which are used to
|
|
** associate the old WNDPROC with the listview window handle.
|
|
*/
|
|
if (!g_lvxcbContextId)
|
|
g_lvxcbContextId = (LPCWSTR )GlobalAddAtom( L"RASLVXCB" );
|
|
if (!g_lvxcbContextId)
|
|
return FALSE;
|
|
|
|
/* Subclass the current window procedure.
|
|
*/
|
|
pOldProc = (WNDPROC)SetWindowLongPtr(
|
|
hwndLv, GWLP_WNDPROC, (ULONG_PTR)LvxcbProc );
|
|
|
|
return SetProp( hwndLv, g_lvxcbContextId, (HANDLE )pOldProc );
|
|
}
|
|
|
|
|
|
VOID
|
|
ListView_SetCheck(
|
|
IN HWND hwndLv,
|
|
IN INT iItem,
|
|
IN BOOL fCheck )
|
|
|
|
/* Sets the check mark on item 'iItem' of listview of checkboxes 'hwndLv'
|
|
** to checked if 'fCheck' is true or unchecked if false.
|
|
*/
|
|
{
|
|
NM_LISTVIEW nmlv;
|
|
|
|
if (ListView_IsCheckDisabled(hwndLv, iItem))
|
|
return;
|
|
|
|
ListView_SetItemState( hwndLv, iItem,
|
|
INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ),
|
|
LVIS_STATEIMAGEMASK );
|
|
|
|
nmlv.hdr.code = LVXN_SETCHECK;
|
|
nmlv.hdr.hwndFrom = hwndLv;
|
|
nmlv.iItem = iItem;
|
|
|
|
FORWARD_WM_NOTIFY(
|
|
GetParent(hwndLv), GetDlgCtrlID(hwndLv), &nmlv, SendMessage
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
ListView_UninstallChecks(
|
|
IN HWND hwndLv )
|
|
|
|
/* Uninstalls "listview of check boxes" handling from list view 'hwndLv'.
|
|
*/
|
|
{
|
|
WNDPROC pOldProc;
|
|
|
|
pOldProc = (WNDPROC)GetProp( hwndLv, g_lvxcbContextId );
|
|
if (pOldProc)
|
|
{
|
|
/* Un-subclass so it can terminate without access to the context.
|
|
*/
|
|
SetWindowLongPtr( hwndLv, GWLP_WNDPROC, (ULONG_PTR)pOldProc );
|
|
}
|
|
|
|
RemoveProp( hwndLv, g_lvxcbContextId );
|
|
}
|
|
|
|
|
|
LRESULT APIENTRY
|
|
LvxcbProc(
|
|
IN HWND hwnd,
|
|
IN UINT unMsg,
|
|
IN WPARAM wparam,
|
|
IN LPARAM lparam )
|
|
|
|
/* List view subclass window procedure to trap toggle-check events.
|
|
*/
|
|
{
|
|
WNDPROC pOldProc;
|
|
INT iItem;
|
|
BOOL fSet;
|
|
BOOL fClear;
|
|
BOOL fToggle;
|
|
|
|
iItem = -1;
|
|
fSet = fClear = fToggle = FALSE;
|
|
|
|
if (unMsg == WM_LBUTTONDOWN)
|
|
{
|
|
LV_HITTESTINFO info;
|
|
|
|
/* Left mouse button pressed over checkbox icon toggles state.
|
|
** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
|
|
** want to work with our cool owner-drawn list view extensions in
|
|
** which case the control doesn't know where the icon is on the item,
|
|
** so it returns a hit anywhere on the item anyway.
|
|
*/
|
|
ZeroMemory( &info, sizeof(info) );
|
|
info.pt.x = LOWORD( lparam );
|
|
info.pt.y = HIWORD( lparam );
|
|
info.flags = LVHT_ONITEM;
|
|
iItem = ListView_HitTest( hwnd, &info );
|
|
|
|
if (iItem >= 0)
|
|
{
|
|
/* OK, it's over item 'iItem'. Now figure out if it's over the
|
|
** checkbox. Note this currently doesn't account for use of the
|
|
** "indent" feature on an owner-drawn item.
|
|
*/
|
|
if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON ))
|
|
iItem = -1;
|
|
else
|
|
fToggle = TRUE;
|
|
}
|
|
}
|
|
else if (unMsg == WM_LBUTTONDBLCLK)
|
|
{
|
|
LV_HITTESTINFO info;
|
|
|
|
/* Left mouse button double clicked over any area toggles state.
|
|
** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
|
|
** want to work with our cool owner-drawn list view extensions in
|
|
** which case the control doesn't know where the icon is on the item,
|
|
** so it returns a hit anywhere on the item anyway.
|
|
*/
|
|
ZeroMemory( &info, sizeof(info) );
|
|
info.pt.x = LOWORD( lparam );
|
|
info.pt.y = HIWORD( lparam );
|
|
info.flags = LVHT_ONITEM;
|
|
iItem = ListView_HitTest( hwnd, &info );
|
|
|
|
if (iItem >= 0)
|
|
{
|
|
/* OK, it's over item 'iItem'. If the click does not occur
|
|
* over a checkbox, inform the parent of the double click.
|
|
*/
|
|
if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON )) {
|
|
NM_LISTVIEW nmlv;
|
|
nmlv.hdr.code = LVXN_DBLCLK;
|
|
nmlv.hdr.hwndFrom = hwnd;
|
|
nmlv.iItem = iItem;
|
|
|
|
FORWARD_WM_NOTIFY(
|
|
GetParent(hwnd), GetDlgCtrlID(hwnd), &nmlv, SendMessage);
|
|
|
|
iItem = -1;
|
|
}
|
|
|
|
/*
|
|
* Otherwise, toggle the state.
|
|
*/
|
|
else
|
|
fToggle = TRUE;
|
|
}
|
|
}
|
|
else if (unMsg == WM_CHAR)
|
|
{
|
|
/* Space bar pressed with item selected toggles check.
|
|
** Plus or Equals keys set check.
|
|
** Minus key clears check.
|
|
*/
|
|
switch (wparam)
|
|
{
|
|
case TEXT(' '):
|
|
fToggle = TRUE;
|
|
break;
|
|
|
|
case TEXT('+'):
|
|
case TEXT('='):
|
|
fSet = TRUE;
|
|
break;
|
|
|
|
case TEXT('-'):
|
|
fClear = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fToggle || fSet || fClear)
|
|
iItem = ListView_GetNextItem( hwnd, -1, LVNI_SELECTED );
|
|
}
|
|
else if (unMsg == WM_KEYDOWN)
|
|
{
|
|
/* Left arrow becomes up arrow and right arrow becomes down arrow so
|
|
** the list of checkboxes behaves just like a static group of
|
|
** checkboxes.
|
|
*/
|
|
if (wparam == VK_LEFT)
|
|
wparam = VK_UP;
|
|
else if (wparam == VK_RIGHT)
|
|
wparam = VK_DOWN;
|
|
}
|
|
|
|
if (iItem >= 0)
|
|
{
|
|
|
|
/* If we are handling the spacebar, plus, minus, or equals,
|
|
** the change we make applies to all the selected items;
|
|
** hence the do {} while(WM_CHAR).
|
|
*/
|
|
|
|
do {
|
|
|
|
if (fToggle)
|
|
{
|
|
UINT unOldState;
|
|
BOOL fCheck;
|
|
|
|
fCheck = ListView_GetCheck( hwnd, iItem );
|
|
ListView_SetCheck( hwnd, iItem, !fCheck );
|
|
}
|
|
else if (fSet)
|
|
{
|
|
if (!ListView_GetCheck( hwnd, iItem ))
|
|
ListView_SetCheck( hwnd, iItem, TRUE );
|
|
}
|
|
else if (fClear)
|
|
{
|
|
if (ListView_GetCheck( hwnd, iItem ))
|
|
ListView_SetCheck( hwnd, iItem, FALSE );
|
|
}
|
|
|
|
iItem = ListView_GetNextItem(hwnd, iItem, LVNI_SELECTED);
|
|
|
|
} while(iItem >= 0 && unMsg == WM_CHAR);
|
|
|
|
if (fSet || fClear) {
|
|
|
|
/* Don't pass to listview to avoid beep.
|
|
*/
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
pOldProc = (WNDPROC )GetProp( hwnd, g_lvxcbContextId );
|
|
if (pOldProc)
|
|
return CallWindowProc( pOldProc, hwnd, unMsg, wparam, lparam );
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Enhanced ListView
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
BOOL
|
|
ListView_OwnerHandler(
|
|
IN HWND hwnd,
|
|
IN UINT unMsg,
|
|
IN WPARAM wparam,
|
|
IN LPARAM lparam,
|
|
IN PLVXCALLBACK pLvxCallback )
|
|
|
|
/* Handler that, when installed, turns a regular report-view-only list
|
|
** view (but with style LVS_OWNERDRAWFIXED) into an enhanced list view
|
|
** with full width selection bar and other custom column display options.
|
|
** It should appear in list view owner's dialog proc as follows:
|
|
**
|
|
** BOOL
|
|
** MyDlgProc(
|
|
** IN HWND hwnd,
|
|
** IN UINT unMsg,
|
|
** IN WPARAM wparam,
|
|
** IN LPARAM lparam )
|
|
** {
|
|
** if (ListView_OwnerHandler(
|
|
** hwnd, unMsg, wParam, lParam, MyLvxCallback ))
|
|
** return TRUE;
|
|
**
|
|
** <the rest of your stuff here>
|
|
** }
|
|
**
|
|
** 'PLvxCallback' is caller's callback routine that provides information
|
|
** about drawing columns and other options.
|
|
**
|
|
** Returns true if processed message, false otherwise.
|
|
*/
|
|
{
|
|
/* This routine executes on EVERY message thru the dialog so keep it
|
|
** efficient, please.
|
|
*/
|
|
switch (unMsg)
|
|
{
|
|
case WM_DRAWITEM:
|
|
return LvxDrawItem( (DRAWITEMSTRUCT* )lparam, pLvxCallback );
|
|
|
|
case WM_MEASUREITEM:
|
|
return LvxMeasureItem( hwnd, (MEASUREITEMSTRUCT* )lparam );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LvxDrawItem(
|
|
IN DRAWITEMSTRUCT* pdis,
|
|
IN PLVXCALLBACK pLvxCallback )
|
|
|
|
/* Respond to WM_DRAWITEM by drawing the list view item. 'Pdis' is the
|
|
** information sent by the system. 'PLvxCallback' is caller's callback to
|
|
** get information about drawing the control.
|
|
**
|
|
** Returns true is processed the message, false otherwise.
|
|
*/
|
|
{
|
|
LV_ITEM item;
|
|
INT i;
|
|
INT dxState;
|
|
INT dyState;
|
|
INT dxSmall;
|
|
INT dySmall;
|
|
INT dxIndent;
|
|
UINT uiStyleState;
|
|
UINT uiStyleSmall;
|
|
HIMAGELIST himlState;
|
|
HIMAGELIST himlSmall;
|
|
LVXDRAWINFO* pDrawInfo;
|
|
RECT rc;
|
|
RECT rcClient;
|
|
BOOL fEnabled;
|
|
BOOL fSelected;
|
|
HDC hdc;
|
|
HFONT hfont;
|
|
|
|
|
|
TRACE3("LvxDrawItem,i=%d,a=$%X,s=$%X",
|
|
pdis->itemID,pdis->itemAction,pdis->itemState);
|
|
|
|
/* Make sure this is something we want to handle.
|
|
*/
|
|
if (pdis->CtlType != ODT_LISTVIEW)
|
|
return FALSE;
|
|
|
|
if (pdis->itemAction != ODA_DRAWENTIRE
|
|
&& pdis->itemAction != ODA_SELECT
|
|
&& pdis->itemAction != ODA_FOCUS)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Get item information from the list view.
|
|
*/
|
|
ZeroMemory( &item, sizeof(item) );
|
|
item.mask = LVIF_IMAGE + LVIF_STATE;
|
|
item.iItem = pdis->itemID;
|
|
item.stateMask = LVIS_STATEIMAGEMASK;
|
|
if (!ListView_GetItem( pdis->hwndItem, &item ))
|
|
{
|
|
TRACE("LvxDrawItem GetItem failed");
|
|
return TRUE;
|
|
}
|
|
|
|
/* Stash some useful stuff for reference later.
|
|
*/
|
|
fEnabled = IsWindowEnabled( pdis->hwndItem )
|
|
&& !(pdis->itemState & ODS_DISABLED);
|
|
fSelected = (pdis->itemState & ODS_SELECTED);
|
|
GetClientRect( pdis->hwndItem, &rcClient );
|
|
|
|
/* Callback owner to get drawing information.
|
|
*/
|
|
ASSERT(pLvxCallback);
|
|
pDrawInfo = pLvxCallback( pdis->hwndItem, pdis->itemID );
|
|
ASSERT(pDrawInfo);
|
|
|
|
/* Get image list icon sizes now, though we draw them last because their
|
|
** background is set up during first column text output.
|
|
*/
|
|
dxState = dyState = 0;
|
|
himlState = ListView_GetImageList( pdis->hwndItem, LVSIL_STATE );
|
|
if (himlState)
|
|
ImageList_GetIconSize( himlState, &dxState, &dyState );
|
|
|
|
dxSmall = dySmall = 0;
|
|
himlSmall = ListView_GetImageList( pdis->hwndItem, LVSIL_SMALL );
|
|
if (himlSmall)
|
|
ImageList_GetIconSize( himlSmall, &dxSmall, &dySmall );
|
|
|
|
uiStyleState = uiStyleSmall = ILD_TRANSPARENT;
|
|
|
|
/* Figure out the number of pixels to indent the item, if any.
|
|
*/
|
|
if (pDrawInfo->dxIndent >= 0)
|
|
dxIndent = pDrawInfo->dxIndent;
|
|
else
|
|
{
|
|
if (dxSmall > 0)
|
|
dxIndent = dxSmall;
|
|
else
|
|
dxIndent = GetSystemMetrics( SM_CXSMICON );
|
|
}
|
|
|
|
/* Get a device context for the window and set it up with the font the
|
|
** control says it's using. (Can't use the one that comes in the
|
|
** DRAWITEMSTRUCT because sometimes it has the wrong rectangle, see bug
|
|
** 13106)
|
|
*/
|
|
hdc = GetDC( pdis->hwndItem );
|
|
|
|
if(NULL == hdc)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hfont = (HFONT )SendMessage( pdis->hwndItem, WM_GETFONT, 0, 0 );
|
|
if (hfont)
|
|
SelectObject( hdc, hfont );
|
|
|
|
/* Set things up as if we'd just got done processing a column that ends
|
|
** after the icons, then loop thru each column from left to right.
|
|
*/
|
|
rc.right = pdis->rcItem.left + dxIndent + dxState + dxSmall;
|
|
rc.top = pdis->rcItem.top;
|
|
rc.bottom = pdis->rcItem.bottom;
|
|
|
|
for (i = 0; i < pDrawInfo->cCols; ++i)
|
|
{
|
|
TCHAR szText[ LVX_MaxColTchars + 1 ];
|
|
TCHAR* pszText;
|
|
INT dxCol;
|
|
|
|
/* Get the column width, adding any index and icon width to the first
|
|
** column.
|
|
*/
|
|
// For whistler bug 458513 39081
|
|
//
|
|
ZeroMemory(szText,sizeof(szText));
|
|
dxCol = ListView_GetColumnWidth( pdis->hwndItem, i );
|
|
if (i == 0)
|
|
dxCol -= dxIndent + dxState + dxSmall;
|
|
|
|
szText[ 0 ] = TEXT('\0');
|
|
ListView_GetItemText( pdis->hwndItem, pdis->itemID, i, szText,
|
|
LVX_MaxColTchars + 1 );
|
|
|
|
/* Update rectangle to enclose just this one item's column 'i'.
|
|
*/
|
|
rc.left = rc.right;
|
|
rc.right = rc.left + dxCol;
|
|
|
|
if ((pDrawInfo->dwFlags & LVXDI_DxFill)
|
|
&& i == pDrawInfo->cCols - 1)
|
|
{
|
|
INT dxWnd = pdis->rcItem.left + rcClient.right;
|
|
|
|
if (rc.right < dxWnd)
|
|
{
|
|
/* When the last column does not fill out a full controls
|
|
** width of space, extend it to the right so it does. Note
|
|
** this does not mean the user can't scroll off to the right
|
|
** if they want.
|
|
** (Abolade-Gbadegesin 03-27-96)
|
|
** Don't subtrace rc.left when there is only one column;
|
|
** this accounts for the space needed for icons.
|
|
*/
|
|
rc.right = pdis->rcItem.right = dxWnd;
|
|
if (i == 0) {
|
|
ListView_SetColumnWidth(pdis->hwndItem, i, rc.right);
|
|
}
|
|
else {
|
|
ListView_SetColumnWidth(
|
|
pdis->hwndItem, i, rc.right - rc.left );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Lop the text and append "..." if it won't fit in the column.
|
|
*/
|
|
pszText = Ellipsisize( hdc, szText, rc.right - rc.left, LVX_dxColText );
|
|
if (!pszText)
|
|
continue;
|
|
|
|
/* Figure out the appropriate text and background colors for the
|
|
** current item state.
|
|
*/
|
|
if (fEnabled)
|
|
{
|
|
if (fSelected)
|
|
{
|
|
SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
|
|
if (pDrawInfo->dwFlags & LVXDI_Blend50Sel)
|
|
uiStyleSmall |= ILD_BLEND50;
|
|
}
|
|
else
|
|
{
|
|
if (pDrawInfo->adwFlags[ i ] & LVXDIA_3dFace)
|
|
{
|
|
SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
|
|
}
|
|
else
|
|
{
|
|
SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pDrawInfo->adwFlags[ i ] & LVXDIA_Static)
|
|
{
|
|
SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
|
|
}
|
|
else
|
|
{
|
|
SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
|
|
}
|
|
|
|
if (pDrawInfo->dwFlags & LVXDI_Blend50Dis)
|
|
uiStyleSmall |= ILD_BLEND50;
|
|
}
|
|
|
|
/* Draw the column text. In the first column the background of any
|
|
** indent and icons is erased to the text background color.
|
|
*/
|
|
{
|
|
RECT rcBg = rc;
|
|
|
|
if (i == 0)
|
|
rcBg.left -= dxIndent + dxState + dxSmall;
|
|
|
|
ExtTextOut( hdc, rc.left + LVX_dxColText,
|
|
rc.top + LVX_dyColText, ETO_CLIPPED + ETO_OPAQUE,
|
|
&rcBg, pszText, lstrlen( pszText ), NULL );
|
|
}
|
|
|
|
Free( pszText );
|
|
}
|
|
|
|
/* Finally, draw the icons, if caller specified any.
|
|
*/
|
|
if (himlState)
|
|
{
|
|
ImageList_Draw( himlState, (item.state >> 12) - 1, hdc,
|
|
pdis->rcItem.left + dxIndent, pdis->rcItem.top, uiStyleState );
|
|
}
|
|
|
|
if (himlSmall)
|
|
{
|
|
ImageList_Draw( himlSmall, item.iImage, hdc,
|
|
pdis->rcItem.left + dxIndent + dxState,
|
|
pdis->rcItem.top, uiStyleSmall );
|
|
}
|
|
|
|
/* Draw the dotted focus rectangle around the whole item, if indicated.
|
|
*/
|
|
//comment for bug 52688 whistler
|
|
// if ((pdis->itemState & ODS_FOCUS) && GetFocus() == pdis->hwndItem)
|
|
// DrawFocusRect( hdc, &pdis->rcItem );
|
|
//
|
|
|
|
ReleaseDC( pdis->hwndItem, hdc );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
LvxMeasureItem(
|
|
IN HWND hwnd,
|
|
IN OUT MEASUREITEMSTRUCT* pmis )
|
|
|
|
/* Respond to WM_MEASUREITEM message, i.e. fill in the height of an item
|
|
** in the ListView. 'Hwnd' is the owner window. 'Pmis' is the structure
|
|
** provided from Windows.
|
|
**
|
|
** Returns true is processed the message, false otherwise.
|
|
*/
|
|
{
|
|
HDC hdc;
|
|
HWND hwndLv;
|
|
HFONT hfont;
|
|
TEXTMETRIC tm;
|
|
UINT dySmIcon;
|
|
RECT rc;
|
|
|
|
TRACE("LvxMeasureItem");
|
|
|
|
if (pmis->CtlType != ODT_LISTVIEW)
|
|
return FALSE;
|
|
|
|
hwndLv = GetDlgItem( hwnd, pmis->CtlID );
|
|
ASSERT(hwndLv);
|
|
|
|
/* Get a device context for the list view control and set up the font the
|
|
** control says it's using. MSDN claims the final font may not be
|
|
** available at this point, but it sure seems to be.
|
|
*/
|
|
hdc = GetDC( hwndLv );
|
|
hfont = (HFONT )SendMessage( hwndLv, WM_GETFONT, 0, 0 );
|
|
if (hfont)
|
|
SelectObject( hdc, hfont );
|
|
|
|
if (GetTextMetrics( hdc, &tm ))
|
|
pmis->itemHeight = tm.tmHeight + 1;
|
|
else
|
|
pmis->itemHeight = 0;
|
|
|
|
/* Make sure it's tall enough for a standard small icon.
|
|
*/
|
|
dySmIcon = (UINT )GetSystemMetrics( SM_CYSMICON );
|
|
if (pmis->itemHeight < dySmIcon + LVX_dyIconSpacing)
|
|
pmis->itemHeight = dySmIcon + LVX_dyIconSpacing;
|
|
|
|
/* Set the width since the docs say to, though I don't think it's used by
|
|
** list view.
|
|
*/
|
|
GetClientRect( hwndLv, &rc );
|
|
pmis->itemWidth = rc.right - rc.left - 1;
|
|
|
|
ReleaseDC( hwndLv, hdc );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** ListView utilities
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
VOID
|
|
ListView_SetDeviceImageList(
|
|
IN HWND hwndLv,
|
|
IN HINSTANCE hinst )
|
|
|
|
/* Set the "small icon" image list view 'hwndLv' to be a list of DI_*
|
|
** images. 'Hinst' is the module instance containing the icons IID_Modem
|
|
** and IID_Adapter. For example, see RASDLG.DLL.
|
|
*/
|
|
{
|
|
HICON hIcon;
|
|
HIMAGELIST himl;
|
|
|
|
himl = ImageList_Create(
|
|
GetSystemMetrics( SM_CXSMICON ),
|
|
GetSystemMetrics( SM_CYSMICON ),
|
|
ILC_MASK, 2, 2 );
|
|
|
|
/* The order these are added is significant since it implicitly
|
|
** establishes the state indices matching SI_Unchecked and SI_Checked.
|
|
*/
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Modem ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Adapter ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Direct_Connect ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Connections_Modem ) );
|
|
if ( NULL != hIcon )
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
|
|
}
|
|
|
|
VOID
|
|
ListView_SetUserImageList(
|
|
IN HWND hwndLv,
|
|
IN HINSTANCE hinst )
|
|
|
|
/* Set the "small icon" image list view 'hwndLv' to be a list of DI_*
|
|
** images. 'Hinst' is the module instance containing the icons IID_Modem
|
|
** and IID_Adapter. For example, see RASDLG.DLL.
|
|
*/
|
|
{
|
|
HICON hIcon;
|
|
HIMAGELIST himl;
|
|
|
|
himl = ImageList_Create(
|
|
GetSystemMetrics( SM_CXSMICON ),
|
|
GetSystemMetrics( SM_CYSMICON ),
|
|
ILC_MASK, 2, 2 );
|
|
|
|
/* The order these are added is significant since it implicitly
|
|
** establishes the state indices matching SI_Unchecked and SI_Checked.
|
|
*/
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Connections_User ) );
|
|
|
|
if(NULL != hIcon)
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
|
|
}
|
|
|
|
|
|
VOID
|
|
ListView_SetNetworkComponentImageList(
|
|
IN HWND hwndLv,
|
|
IN HINSTANCE hinst )
|
|
|
|
/* Set the "small icon" image list view 'hwndLv' to be a list of DI_*
|
|
** images. 'Hinst' is the module instance containing the icons IID_Modem
|
|
** and IID_Adapter. For example, see RASDLG.DLL.
|
|
*/
|
|
{
|
|
HICON hIcon;
|
|
HIMAGELIST himl;
|
|
|
|
himl = ImageList_Create(
|
|
GetSystemMetrics( SM_CXSMICON ),
|
|
GetSystemMetrics( SM_CYSMICON ),
|
|
ILC_MASK, 2, 2 );
|
|
|
|
/* The order these are added is significant since it implicitly
|
|
** establishes the state indices matching SI_Unchecked and SI_Checked.
|
|
*/
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Protocol ) );
|
|
|
|
if(NULL != hIcon)
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Service ) );
|
|
|
|
if(NULL != hIcon)
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Client ) );
|
|
|
|
if(NULL != hIcon)
|
|
{
|
|
ImageList_ReplaceIcon( himl, -1, hIcon );
|
|
DeleteObject( hIcon );
|
|
}
|
|
|
|
ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
|
|
}
|
|
|