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.
844 lines
24 KiB
844 lines
24 KiB
/**************************** Module Header ********************************\
|
|
* Module Name: lboxrare.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Infrequently Used List Box Routines
|
|
*
|
|
* History:
|
|
* ??-???-???? ianja Ported from Win 3.0 sources
|
|
* 14-Feb-1991 mikeke Added Revalidation code
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
extern LOOKASIDE ListboxLookaside;
|
|
|
|
/***************************************************************************\
|
|
* LBSetCItemFullMax
|
|
*
|
|
* History:
|
|
* 03-04-92 JimA Ported from Win 3.1 sources.
|
|
\***************************************************************************/
|
|
|
|
void LBSetCItemFullMax(
|
|
PLBIV plb)
|
|
{
|
|
if (plb->OwnerDraw != OWNERDRAWVAR) {
|
|
plb->cItemFullMax = CItemInWindow(plb, FALSE);
|
|
} else if (plb->cMac < 2) {
|
|
plb->cItemFullMax = 1;
|
|
} else {
|
|
int height;
|
|
RECT rect;
|
|
int i;
|
|
int j = 0;
|
|
|
|
_GetClientRect(plb->spwnd, &rect);
|
|
height = rect.bottom;
|
|
|
|
plb->cItemFullMax = 0;
|
|
for (i = plb->cMac - 1; i >= 0; i--, j++) {
|
|
height -= LBGetVariableHeightItemHeight(plb, i);
|
|
|
|
if (height < 0) {
|
|
plb->cItemFullMax = j;
|
|
break;
|
|
}
|
|
}
|
|
if (!plb->cItemFullMax)
|
|
plb->cItemFullMax = j;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxCreateLBox
|
|
*
|
|
* History:
|
|
* 16-Apr-1992 beng Added LBS_NODATA
|
|
\***************************************************************************/
|
|
|
|
LONG xxxLBCreate(
|
|
PLBIV plb, PWND pwnd, LPCREATESTRUCT lpcs)
|
|
{
|
|
UINT style;
|
|
MEASUREITEMSTRUCT measureItemStruct;
|
|
TL tlpwndParent;
|
|
HDC hdc;
|
|
|
|
/*
|
|
* Once we make it here, nobody can change the ownerdraw style bits
|
|
* by calling SetWindowLong. The window style must match the flags in plb
|
|
*
|
|
*/
|
|
plb->fInitialized = TRUE;
|
|
|
|
style = pwnd->style;
|
|
|
|
/*
|
|
* Compatibility hack.
|
|
*/
|
|
if (pwnd->spwndParent == NULL)
|
|
Lock(&(plb->spwndParent), _GetDesktopWindow());
|
|
else
|
|
Lock(&(plb->spwndParent), REBASEPWND(pwnd, spwndParent));
|
|
|
|
/*
|
|
* Break out the style bits
|
|
*/
|
|
plb->fRedraw = ((style & LBS_NOREDRAW) == 0);
|
|
plb->fDeferUpdate = FALSE;
|
|
plb->fNotify = (UINT)((style & LBS_NOTIFY) != 0);
|
|
plb->fVertBar = ((style & WS_VSCROLL) != 0);
|
|
plb->fHorzBar = ((style & WS_HSCROLL) != 0);
|
|
|
|
if (!TestWF(pwnd, WFWIN40COMPAT)) {
|
|
// for 3.x apps, if either scroll bar was specified, the app got BOTH
|
|
if (plb->fVertBar || plb->fHorzBar)
|
|
plb->fVertBar = plb->fHorzBar = TRUE;
|
|
}
|
|
|
|
plb->fRtoLReading = (TestWF(pwnd, WEFRTLREADING) != 0);
|
|
plb->fRightAlign = (TestWF(pwnd, WEFRIGHT) != 0);
|
|
plb->fDisableNoScroll = ((style & LBS_DISABLENOSCROLL) != 0);
|
|
|
|
plb->fSmoothScroll = TRUE;
|
|
|
|
/*
|
|
* LBS_NOSEL gets priority over any other selection style. Next highest
|
|
* priority goes to LBS_EXTENDEDSEL. Then LBS_MULTIPLESEL.
|
|
*/
|
|
if (TestWF(pwnd, WFWIN40COMPAT) && (style & LBS_NOSEL)) {
|
|
plb->wMultiple = SINGLESEL;
|
|
plb->fNoSel = TRUE;
|
|
} else if (style & LBS_EXTENDEDSEL) {
|
|
plb->wMultiple = EXTENDEDSEL;
|
|
} else {
|
|
plb->wMultiple = (UINT)((style & LBS_MULTIPLESEL) ? MULTIPLESEL : SINGLESEL);
|
|
}
|
|
|
|
plb->fNoIntegralHeight = ((style & LBS_NOINTEGRALHEIGHT) != 0);
|
|
plb->fWantKeyboardInput = ((style & LBS_WANTKEYBOARDINPUT) != 0);
|
|
plb->fUseTabStops = ((style & LBS_USETABSTOPS) != 0);
|
|
if (plb->fUseTabStops) {
|
|
|
|
/*
|
|
* Set tab stops every <default> dialog units.
|
|
*/
|
|
LBSetTabStops(plb, 0, NULL);
|
|
}
|
|
plb->fMultiColumn = ((style & LBS_MULTICOLUMN) != 0);
|
|
plb->fHasStrings = TRUE;
|
|
plb->iLastSelection = -1;
|
|
plb->iMouseDown = -1; /* Anchor point for multi selection */
|
|
plb->iLastMouseMove = -1;
|
|
|
|
/*
|
|
* Get ownerdraw style bits
|
|
*/
|
|
if ((style & LBS_OWNERDRAWFIXED)) {
|
|
plb->OwnerDraw = OWNERDRAWFIXED;
|
|
} else if ((style & LBS_OWNERDRAWVARIABLE) && !plb->fMultiColumn) {
|
|
plb->OwnerDraw = OWNERDRAWVAR;
|
|
|
|
/*
|
|
* Integral height makes no sense with var height owner draw
|
|
*/
|
|
plb->fNoIntegralHeight = TRUE;
|
|
}
|
|
|
|
if (plb->OwnerDraw && !(style & LBS_HASSTRINGS)) {
|
|
|
|
/*
|
|
* If owner draw, do they want the listbox to maintain strings?
|
|
*/
|
|
plb->fHasStrings = FALSE;
|
|
}
|
|
|
|
/*
|
|
* If user specifies sort and not hasstrings, then we will send
|
|
* WM_COMPAREITEM messages to the parent.
|
|
*/
|
|
plb->fSort = ((style & LBS_SORT) != 0);
|
|
|
|
/*
|
|
* "No data" lazy-eval listbox mandates certain other style settings
|
|
*/
|
|
plb->fHasData = TRUE;
|
|
|
|
if (style & LBS_NODATA) {
|
|
if (plb->OwnerDraw != OWNERDRAWFIXED || plb->fSort || plb->fHasStrings) {
|
|
RIPERR0(ERROR_INVALID_FLAGS, RIP_WARNING,
|
|
"NODATA listbox must be OWNERDRAWFIXED, w/o SORT or HASSTRINGS");
|
|
} else {
|
|
plb->fHasData = FALSE;
|
|
}
|
|
}
|
|
|
|
plb->dwLocaleId = GetThreadLocale();
|
|
|
|
/*
|
|
* Check if this is part of a combo box
|
|
*/
|
|
if ((style & LBS_COMBOBOX) != 0) {
|
|
|
|
/*
|
|
* Get the pcbox structure contained in the parent window's extra data
|
|
* pointer. Check cbwndExtra to ensure compatibility with SQL windows.
|
|
*/
|
|
if (plb->spwndParent->cbwndExtra != 0)
|
|
plb->pcbox = ((PCOMBOWND)(plb->spwndParent))->pcbox;
|
|
}
|
|
|
|
/*
|
|
* No need to set these to 0 since that was done for us when we Alloced
|
|
* the PLBIV.
|
|
*/
|
|
|
|
/*
|
|
* plb->rgpch = (PBYTE)0;
|
|
*/
|
|
|
|
/*
|
|
* plb->iSelBase = plb->iTop = 0;
|
|
*/
|
|
|
|
/*
|
|
* plb->fMouseDown = FALSE;
|
|
*/
|
|
|
|
/*
|
|
* plb->fCaret = FALSE;
|
|
*/
|
|
|
|
/*
|
|
* plb->fCaretOn = FALSE;
|
|
*/
|
|
|
|
/*
|
|
* plb->maxWidth = 0;
|
|
*/
|
|
|
|
plb->iSel = -1;
|
|
|
|
plb->hdc = NULL;
|
|
|
|
/*
|
|
* Set the keyboard state so that when the user keyboard clicks he selects
|
|
* an item.
|
|
*/
|
|
plb->fNewItemState = TRUE;
|
|
|
|
InitHStrings(plb);
|
|
|
|
if (plb->fHasStrings && plb->hStrings == NULL) {
|
|
return -1L;
|
|
}
|
|
|
|
hdc = NtUserGetDC(HWq(pwnd));
|
|
plb->cxChar = GdiGetCharDimensions(hdc, NULL, &plb->cyChar);
|
|
NtUserReleaseDC(HWq(pwnd), hdc);
|
|
|
|
if (plb->cxChar == 0) {
|
|
RIPMSG0(RIP_WARNING, "xxxLBCreate: GdiGetCharDimensions failed");
|
|
plb->cxChar = gpsi->cxSysFontChar;
|
|
plb->cyChar = gpsi->cySysFontChar;
|
|
}
|
|
|
|
if (plb->OwnerDraw == OWNERDRAWFIXED) {
|
|
|
|
/*
|
|
* Query for item height only if we are fixed height owner draw. Note
|
|
* that we don't care about an item's width for listboxes.
|
|
*/
|
|
measureItemStruct.CtlType = ODT_LISTBOX;
|
|
measureItemStruct.CtlID = PtrToUlong(pwnd->spmenu);
|
|
|
|
/*
|
|
* System font height is default height
|
|
*/
|
|
measureItemStruct.itemHeight = plb->cyChar;
|
|
measureItemStruct.itemWidth = 0;
|
|
measureItemStruct.itemData = 0;
|
|
|
|
/*
|
|
* IanJa: #ifndef WIN16 (32-bit Windows), plb->id gets extended
|
|
* to LONG wParam automatically by the compiler
|
|
*/
|
|
ThreadLock(plb->spwndParent, &tlpwndParent);
|
|
SendMessage(HW(plb->spwndParent), WM_MEASUREITEM,
|
|
measureItemStruct.CtlID,
|
|
(LPARAM)&measureItemStruct);
|
|
ThreadUnlock(&tlpwndParent);
|
|
|
|
/*
|
|
* Use default height if given 0. This prevents any possible future
|
|
* div-by-zero errors.
|
|
*/
|
|
if (measureItemStruct.itemHeight)
|
|
plb->cyChar = measureItemStruct.itemHeight;
|
|
|
|
|
|
if (plb->fMultiColumn) {
|
|
|
|
/*
|
|
* Get default column width from measure items struct if we are a
|
|
* multicolumn listbox.
|
|
*/
|
|
plb->cxColumn = measureItemStruct.itemWidth;
|
|
}
|
|
} else if (plb->OwnerDraw == OWNERDRAWVAR)
|
|
plb->cyChar = 0;
|
|
|
|
|
|
if (plb->fMultiColumn) {
|
|
|
|
/*
|
|
* Set these default values till we get the WM_SIZE message and we
|
|
* calculate them properly. This is because some people create a
|
|
* 0 width/height listbox and size it later. We don't want to have
|
|
* problems with invalid values in these fields
|
|
*/
|
|
if (plb->cxColumn <= 0)
|
|
plb->cxColumn = 15 * plb->cxChar;
|
|
plb->numberOfColumns = plb->itemsPerColumn = 1;
|
|
}
|
|
|
|
LBSetCItemFullMax(plb);
|
|
|
|
// Don't do this for 4.0 apps. It'll make everyone's lives easier and
|
|
// fix the anomaly that a combo & list created the same width end up
|
|
// different when all is done.
|
|
// B#1520
|
|
|
|
if (!TestWF(pwnd, WFWIN40COMPAT)) {
|
|
plb->fIgnoreSizeMsg = TRUE;
|
|
NtUserMoveWindow(HWq(pwnd),
|
|
lpcs->x - SYSMET(CXBORDER),
|
|
lpcs->y - SYSMET(CYBORDER),
|
|
lpcs->cx + SYSMET(CXEDGE),
|
|
lpcs->cy + SYSMET(CYEDGE),
|
|
FALSE);
|
|
plb->fIgnoreSizeMsg = FALSE;
|
|
}
|
|
|
|
if (!plb->fNoIntegralHeight) {
|
|
|
|
/*
|
|
* Send a message to ourselves to resize the listbox to an integral
|
|
* height. We need to do it this way because at create time we are all
|
|
* mucked up with window rects etc...
|
|
* IanJa: #ifndef WIN16 (32-bit Windows), wParam 0 gets extended
|
|
* to wParam 0L automatically by the compiler.
|
|
*/
|
|
PostMessage(HWq(pwnd), WM_SIZE, 0, 0L);
|
|
}
|
|
|
|
return 1L;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxLBoxDoDeleteItems
|
|
*
|
|
* Send DELETEITEM message for all the items in the ownerdraw listbox.
|
|
*
|
|
* History:
|
|
* 16-Apr-1992 beng Nodata case
|
|
\***************************************************************************/
|
|
|
|
void xxxLBoxDoDeleteItems(
|
|
PLBIV plb)
|
|
{
|
|
INT sItem;
|
|
|
|
CheckLock(plb->spwnd);
|
|
|
|
/*
|
|
* Send WM_DELETEITEM message for ownerdraw listboxes which are
|
|
* being deleted. (NODATA listboxes don't send such, though.)
|
|
*/
|
|
if (plb->OwnerDraw && plb->cMac && plb->fHasData) {
|
|
for (sItem = plb->cMac - 1; sItem >= 0; sItem--) {
|
|
xxxLBoxDeleteItem(plb, sItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxDestroyLBox
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxDestroyLBox(
|
|
PLBIV pLBIV,
|
|
PWND pwnd)
|
|
{
|
|
PWND pwndParent;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
if (pLBIV != NULL) {
|
|
CheckLock(pLBIV->spwnd);
|
|
|
|
/*
|
|
* If ownerdraw, send deleteitem messages to parent
|
|
*/
|
|
xxxLBoxDoDeleteItems(pLBIV);
|
|
|
|
if (pLBIV->rgpch != NULL) {
|
|
UserLocalFree(pLBIV->rgpch);
|
|
pLBIV->rgpch = NULL;
|
|
}
|
|
|
|
if (pLBIV->hStrings != NULL) {
|
|
UserLocalFree(pLBIV->hStrings);
|
|
pLBIV->hStrings = NULL;
|
|
}
|
|
|
|
if (pLBIV->iTabPixelPositions != NULL) {
|
|
UserLocalFree((HANDLE)pLBIV->iTabPixelPositions);
|
|
pLBIV->iTabPixelPositions = NULL;
|
|
}
|
|
|
|
Unlock(&pLBIV->spwnd);
|
|
Unlock(&pLBIV->spwndParent);
|
|
|
|
if (pLBIV->pszTypeSearch) {
|
|
UserLocalFree(pLBIV->pszTypeSearch);
|
|
}
|
|
|
|
FreeLookasideEntry(&ListboxLookaside, pLBIV);
|
|
}
|
|
|
|
/*
|
|
* Set the window's fnid status so that we can ignore rogue messages
|
|
*/
|
|
NtUserSetWindowFNID(HWq(pwnd), FNID_CLEANEDUP_BIT);
|
|
|
|
/*
|
|
* If we're part of a combo box, let it know we're gone
|
|
*/
|
|
pwndParent = REBASEPWND(pwnd, spwndParent);
|
|
if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) {
|
|
ComboBoxWndProcWorker(pwndParent, WM_PARENTNOTIFY,
|
|
MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd), FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxLBSetFont
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxLBSetFont(
|
|
PLBIV plb,
|
|
HANDLE hFont,
|
|
BOOL fRedraw)
|
|
{
|
|
HDC hdc;
|
|
HANDLE hOldFont = NULL;
|
|
int iHeight;
|
|
|
|
CheckLock(plb->spwnd);
|
|
|
|
plb->hFont = hFont;
|
|
|
|
hdc = NtUserGetDC(HWq(plb->spwnd));
|
|
|
|
if (hFont) {
|
|
hOldFont = SelectObject(hdc, hFont);
|
|
if (!hOldFont) {
|
|
plb->hFont = NULL;
|
|
}
|
|
}
|
|
|
|
plb->cxChar = GdiGetCharDimensions(hdc, NULL, &iHeight);
|
|
if (plb->cxChar == 0) {
|
|
RIPMSG0(RIP_WARNING, "xxxLBSetFont: GdiGetCharDimensions failed");
|
|
plb->cxChar = gpsi->cxSysFontChar;
|
|
iHeight = gpsi->cySysFontChar;
|
|
}
|
|
|
|
|
|
if (!plb->OwnerDraw && (plb->cyChar != iHeight)) {
|
|
|
|
/*
|
|
* We don't want to mess up the cyChar height for owner draw listboxes
|
|
* so don't do this.
|
|
*/
|
|
plb->cyChar = iHeight;
|
|
|
|
/*
|
|
* Only resize the listbox for 4.0 dudes, or combo dropdowns.
|
|
* Macromedia Director 4.0 GP-faults otherwise.
|
|
*/
|
|
if (!plb->fNoIntegralHeight &&
|
|
(plb->pcbox || TestWF(plb->spwnd, WFWIN40COMPAT))) {
|
|
xxxLBSize(plb,
|
|
plb->spwnd->rcClient.right - plb->spwnd->rcClient.left,
|
|
plb->spwnd->rcClient.bottom - plb->spwnd->rcClient.top);
|
|
}
|
|
}
|
|
|
|
if (hOldFont) {
|
|
SelectObject(hdc, hOldFont);
|
|
}
|
|
|
|
/*
|
|
* IanJa: was ReleaseDC(hwnd, hdc);
|
|
*/
|
|
NtUserReleaseDC(HWq(plb->spwnd), hdc);
|
|
|
|
if (plb->fMultiColumn) {
|
|
LBCalcItemRowsAndColumns(plb);
|
|
}
|
|
|
|
LBSetCItemFullMax(plb);
|
|
|
|
if (fRedraw)
|
|
xxxCheckRedraw(plb, FALSE, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxLBSize
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxLBSize(
|
|
PLBIV plb,
|
|
INT cx,
|
|
INT cy)
|
|
{
|
|
RECT rc;
|
|
int iTopOld;
|
|
BOOL fSizedSave;
|
|
|
|
CheckLock(plb->spwnd);
|
|
|
|
if (!plb->fNoIntegralHeight) {
|
|
int cBdrs = GetWindowBorders(plb->spwnd->style, plb->spwnd->ExStyle, TRUE, TRUE);
|
|
|
|
CopyInflateRect(&rc, KPRECT_TO_PRECT(&plb->spwnd->rcWindow), 0, -cBdrs * SYSMET(CYBORDER));
|
|
|
|
// Size the listbox to fit an integral # of items in its client
|
|
if ((rc.bottom - rc.top) % plb->cyChar) {
|
|
int iItems = (rc.bottom - rc.top);
|
|
|
|
// B#2285 - If its a 3.1 app its SetWindowPos needs
|
|
// to be window based dimensions not Client !
|
|
// this crunches Money into using a scroll bar
|
|
|
|
if ( ! TestWF( plb->spwnd, WFWIN40COMPAT ) )
|
|
iItems += (cBdrs * SYSMET(CYEDGE)); // so add it back in
|
|
|
|
iItems /= plb->cyChar;
|
|
|
|
NtUserSetWindowPos(HWq(plb->spwnd), HWND_TOP, 0, 0, rc.right - rc.left,
|
|
iItems * plb->cyChar + (SYSMET(CYEDGE) * cBdrs),
|
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
|
|
|
/*
|
|
* Changing the size causes us to recurse. Upon return
|
|
* the state is where it should be and nothing further
|
|
* needs to be done.
|
|
*/
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (plb->fMultiColumn) {
|
|
|
|
/*
|
|
* Compute the number of DISPLAYABLE rows and columns in the listbox
|
|
*/
|
|
LBCalcItemRowsAndColumns(plb);
|
|
} else {
|
|
|
|
/*
|
|
* Adjust the current horizontal position to eliminate as much
|
|
* empty space as possible from the right side of the items.
|
|
*/
|
|
_GetClientRect(plb->spwnd, &rc);
|
|
if ((plb->maxWidth - plb->xOrigin) < (rc.right - rc.left))
|
|
plb->xOrigin = max(0, plb->maxWidth - (rc.right - rc.left));
|
|
}
|
|
|
|
LBSetCItemFullMax(plb);
|
|
|
|
/*
|
|
* Adjust the top item in the listbox to eliminate as much empty space
|
|
* after the last item as possible
|
|
* (fix for bugs #8490 & #3836)
|
|
*/
|
|
iTopOld = plb->iTop;
|
|
fSizedSave = plb->fSized;
|
|
plb->fSized = FALSE;
|
|
xxxNewITop(plb, plb->iTop);
|
|
|
|
/*
|
|
* If changing the top item index caused a resize, there is no
|
|
* more work to be done here.
|
|
*/
|
|
if (plb->fSized)
|
|
return;
|
|
plb->fSized = fSizedSave;
|
|
|
|
if (IsLBoxVisible(plb)) {
|
|
/*
|
|
* This code no longer blows because it's fixed right!!! We could
|
|
* optimize the fMultiColumn case with some more code to figure out
|
|
* if we really need to invalidate the whole thing but note that some
|
|
* 3.0 apps depend on this extra invalidation (AMIPRO 2.0, bug 14620)
|
|
*
|
|
* For 3.1 apps, we blow off the invalidaterect in the case where
|
|
* cx and cy are 0 because this happens during the processing of
|
|
* the posted WM_SIZE message when we are created which would otherwise
|
|
* cause us to flash.
|
|
*/
|
|
if ((plb->fMultiColumn && !(cx == 0 && cy == 0)) ||
|
|
plb->iTop != iTopOld)
|
|
NtUserInvalidateRect(HWq(plb->spwnd), NULL, TRUE);
|
|
else if (plb->iSelBase >= 0) {
|
|
|
|
/*
|
|
* Invalidate the item with the caret so that if the listbox
|
|
* grows horizontally, we redraw it properly.
|
|
*/
|
|
LBGetItemRect(plb, plb->iSelBase, &rc);
|
|
NtUserInvalidateRect(HWq(plb->spwnd), &rc, FALSE);
|
|
}
|
|
} else if (!plb->fRedraw)
|
|
plb->fDeferUpdate = TRUE;
|
|
|
|
/*
|
|
* Send "fake" scroll bar messages to update the scroll positions since we
|
|
* changed size.
|
|
*/
|
|
if (TestWF(plb->spwnd, WFVSCROLL)) {
|
|
xxxLBoxCtlScroll(plb, SB_ENDSCROLL, 0);
|
|
}
|
|
|
|
/*
|
|
* We count on this to call LBShowHideScrollBars except when plb->cMac == 0!
|
|
*/
|
|
xxxLBoxCtlHScroll(plb, SB_ENDSCROLL, 0);
|
|
|
|
/*
|
|
* Show/hide scroll bars depending on how much stuff is visible...
|
|
*
|
|
* Note: Now we only call this guy when cMac == 0, because it is
|
|
* called inside the LBoxCtlHScroll with SB_ENDSCROLL otherwise.
|
|
*/
|
|
if (plb->cMac == 0)
|
|
xxxLBShowHideScrollBars(plb);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* LBSetTabStops
|
|
*
|
|
* Sets the tab stops for this listbox. Returns TRUE if successful else FALSE.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
BOOL LBSetTabStops(
|
|
PLBIV plb,
|
|
INT count,
|
|
LPINT lptabstops)
|
|
{
|
|
PINT ptabs;
|
|
|
|
if (!plb->fUseTabStops) {
|
|
RIPERR0(ERROR_LB_WITHOUT_TABSTOPS, RIP_VERBOSE, "");
|
|
return FALSE;
|
|
}
|
|
|
|
if (count) {
|
|
/*
|
|
* Allocate memory for the tab stops. The first byte in the
|
|
* plb->iTabPixelPositions array will contain a count of the number
|
|
* of tab stop positions we have.
|
|
*/
|
|
ptabs = (LPINT)UserLocalAlloc(HEAP_ZERO_MEMORY, (count + 1) * sizeof(int));
|
|
if (ptabs == NULL)
|
|
return FALSE;
|
|
|
|
if (plb->iTabPixelPositions != NULL)
|
|
UserLocalFree(plb->iTabPixelPositions);
|
|
plb->iTabPixelPositions = ptabs;
|
|
|
|
/*
|
|
* Set the count of tab stops
|
|
*/
|
|
*ptabs++ = count;
|
|
|
|
for (; count > 0; count--) {
|
|
|
|
/*
|
|
* Convert the dialog unit tabstops into pixel position tab stops.
|
|
*/
|
|
*ptabs++ = MultDiv(*lptabstops, plb->cxChar, 4);
|
|
lptabstops++;
|
|
}
|
|
} else {
|
|
|
|
/*
|
|
* Set default 8 system font ave char width tabs. So free the memory
|
|
* associated with the tab stop list.
|
|
*/
|
|
if (plb->iTabPixelPositions != NULL) {
|
|
UserLocalFree((HANDLE)plb->iTabPixelPositions);
|
|
plb->iTabPixelPositions = NULL;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* InitHStrings
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void InitHStrings(
|
|
PLBIV plb)
|
|
{
|
|
if (plb->fHasStrings) {
|
|
plb->ichAlloc = 0;
|
|
plb->cchStrings = 0;
|
|
plb->hStrings = UserLocalAlloc(0, 0L);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* LBDropObjectHandler
|
|
*
|
|
* Handles a WM_DROPITEM message on this listbox
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void LBDropObjectHandler(
|
|
PLBIV plb,
|
|
PDROPSTRUCT pds)
|
|
{
|
|
LONG mouseSel;
|
|
|
|
if (ISelFromPt(plb, pds->ptDrop, &mouseSel)) {
|
|
|
|
/*
|
|
* User dropped in empty space at bottom of listbox
|
|
*/
|
|
pds->dwControlData = (DWORD)-1L;
|
|
} else {
|
|
pds->dwControlData = mouseSel;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* LBGetSetItemHeightHandler()
|
|
*
|
|
* Sets/Gets the height associated with each item. For non ownerdraw
|
|
* and fixed height ownerdraw, the item number is ignored.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
int LBGetSetItemHeightHandler(
|
|
PLBIV plb,
|
|
UINT message,
|
|
int item,
|
|
UINT height)
|
|
{
|
|
if (message == LB_GETITEMHEIGHT) {
|
|
/*
|
|
* All items are same height for non ownerdraw and for fixed height
|
|
* ownerdraw.
|
|
*/
|
|
if (plb->OwnerDraw != OWNERDRAWVAR)
|
|
return plb->cyChar;
|
|
|
|
if (plb->cMac && item >= plb->cMac) {
|
|
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
|
|
return LB_ERR;
|
|
}
|
|
|
|
return (int)LBGetVariableHeightItemHeight(plb, (INT)item);
|
|
}
|
|
|
|
if (!height || height > 255) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid parameter \"height\" (%ld) to LBGetSetItemHeightHandler",
|
|
height);
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
if (plb->OwnerDraw != OWNERDRAWVAR)
|
|
plb->cyChar = height;
|
|
else {
|
|
if (item < 0 || item >= plb->cMac) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Invalid parameter \"item\" (%ld) to LBGetSetItemHeightHandler",
|
|
item);
|
|
|
|
return LB_ERR;
|
|
}
|
|
|
|
LBSetVariableHeightItemHeight(plb, (INT)item, (INT)height);
|
|
}
|
|
|
|
if (plb->fMultiColumn)
|
|
LBCalcItemRowsAndColumns(plb);
|
|
|
|
LBSetCItemFullMax(plb);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
*
|
|
* LBEvent()
|
|
*
|
|
* This is for item focus & selection events in listboxes.
|
|
*
|
|
\*****************************************************************************/
|
|
void LBEvent(PLBIV plb, UINT uEvent, int iItem)
|
|
{
|
|
switch (uEvent) {
|
|
case EVENT_OBJECT_SELECTIONREMOVE:
|
|
if (plb->wMultiple != SINGLESEL) {
|
|
break;
|
|
}
|
|
iItem = -1;
|
|
//
|
|
// FALL THRU
|
|
//
|
|
|
|
case EVENT_OBJECT_SELECTIONADD:
|
|
if (plb->wMultiple == MULTIPLESEL) {
|
|
uEvent = EVENT_OBJECT_SELECTION;
|
|
}
|
|
break;
|
|
|
|
case EVENT_OBJECT_SELECTIONWITHIN:
|
|
iItem = -1;
|
|
break;
|
|
}
|
|
|
|
NotifyWinEvent(uEvent, HW(plb->spwnd), OBJID_CLIENT, iItem+1);
|
|
}
|