2020-09-30 17:12:32 +02:00

234 lines
5.2 KiB
C

/**************************** Module Header ********************************\
* Module Name: lboxvar.c
* Copyright (c) 1985 - 1999, Microsoft Corporation
* List Box variable height owner draw routines
* History:
* ??-???-???? ianja Ported from Win 3.0 sources
* 14-Feb-1991 mikeke Added Revalidation code (None)
*/
#include "precomp.h"
#pragma hdrstop
/*
* LBGetVariableHeightItemHeight
* Returns the height of the given item number. Assumes variable
* height owner draw.
* History:
*/
INT LBGetVariableHeightItemHeight(
PLBIV plb,
INT itemNumber)
{
BYTE itemHeight;
int offsetHeight;
if (plb->cMac) {
if (plb->fHasStrings)
offsetHeight = plb->cMac * sizeof(LBItem);
else
offsetHeight = plb->cMac * sizeof(LBODItem);
if (plb->wMultiple)
offsetHeight += plb->cMac;
offsetHeight += itemNumber;
itemHeight = *(plb->rgpch+(UINT)offsetHeight);
return (INT)itemHeight;
}
/*
*Default, we return the height of the system font. This is so we can draw
* the focus rect even though there are no items in the listbox.
*/
return gpsi->cySysFontChar;
}
/*
* LBSetVariableHeightItemHeight
* Sets the height of the given item number. Assumes variable height
* owner draw, a valid item number and valid height.
* History:
*/
void LBSetVariableHeightItemHeight(
PLBIV plb,
INT itemNumber,
INT itemHeight)
{
int offsetHeight;
if (plb->fHasStrings)
offsetHeight = plb->cMac * sizeof(LBItem);
else
offsetHeight = plb->cMac * sizeof(LBODItem);
if (plb->wMultiple)
offsetHeight += plb->cMac;
offsetHeight += itemNumber;
*(plb->rgpch + (UINT)offsetHeight) = (BYTE)itemHeight;
}
/*
* CItemInWindowVarOwnerDraw
* Returns the number of items which can fit in a variable height OWNERDRAW
* list box. If fDirection, then we return the number of items which
* fit starting at sTop and going forward (for page down), otherwise, we are
* going backwards (for page up). (Assumes var height ownerdraw) If fPartial,
* then include the partially visible item at the bottom of the listbox.
* History:
*/
INT CItemInWindowVarOwnerDraw(
PLBIV plb,
BOOL fPartial)
{
RECT rect;
INT sItem;
INT clientbottom;
_GetClientRect(plb->spwnd, (LPRECT)&rect);
clientbottom = rect.bottom;
/*
* Find the number of var height ownerdraw items which are visible starting
* from plb->iTop.
*/
for (sItem = plb->iTop; sItem < plb->cMac; sItem++) {
/*
* Find out if the item is visible or not
*/
if (!LBGetItemRect(plb, sItem, (LPRECT)&rect)) {
/*
* This is the first item which is completely invisible, so return
* how many items are visible.
*/
return (sItem - plb->iTop);
}
if (!fPartial && rect.bottom > clientbottom) {
/*
* If we only want fully visible items, then if this item is
* visible, we check if the bottom of the item is below the client
* rect, so we return how many are fully visible.
*/
return (sItem - plb->iTop - 1);
}
}
/*
* All the items are visible
*/
return (plb->cMac - plb->iTop);
}
/*
* LBPage
* For variable height ownerdraw listboxes, calaculates the new iTop we must
* move to when paging (page up/down) through variable height listboxes.
* History:
*/
INT LBPage(
PLBIV plb,
INT startItem,
BOOL fPageForwardDirection)
{
INT i;
INT height;
RECT rc;
if (plb->cMac == 1)
return(0);
_GetClientRect(plb->spwnd, &rc);
height = rc.bottom;
i = startItem;
if (fPageForwardDirection) {
while ((height >= 0) && (i < plb->cMac))
height -= LBGetVariableHeightItemHeight(plb, i++);
return((height >= 0) ? plb->cMac - 1 : max(i - 2, startItem + 1));
} else {
while ((height >= 0) && (i >= 0))
height -= LBGetVariableHeightItemHeight(plb, i--);
return((height >= 0) ? 0 : min(i + 2, startItem - 1));
}
}
/*
* LBCalcVarITopScrollAmt
* Changing the top most item in the listbox from iTopOld to iTopNew we
* want to calculate the number of pixels to scroll so that we minimize the
* number of items we will redraw.
* History:
*/
INT LBCalcVarITopScrollAmt(
PLBIV plb,
INT iTopOld,
INT iTopNew)
{
RECT rc;
RECT rcClient;
_GetClientRect(plb->spwnd, (LPRECT)&rcClient);
/*
* Just optimize redrawing when move +/- 1 item. We will redraw all items
* if moving more than 1 item ahead or back. This is good enough for now.
*/
if (iTopOld + 1 == iTopNew) {
/*
* We are scrolling the current iTop up off the top off the listbox so
* return a negative number.
*/
LBGetItemRect(plb, iTopOld, (LPRECT)&rc);
return (rcClient.top - rc.bottom);
}
if (iTopOld - 1 == iTopNew) {
/*
* We are scrolling the current iTop down and the previous item is
* becoming the new iTop so return a positive number.
*/
LBGetItemRect(plb, iTopNew, (LPRECT)&rc);
return -rc.top;
}
return rcClient.bottom - rcClient.top;
}