📄 listbox.c
字号:
*/
static void LISTBOX_InvalidateItems( LB_DESCR *descr, INT index )
{
RECT rect;
if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
{
if (descr->style & LBS_NOREDRAW)
{
descr->style |= LBS_DISPLAYCHANGED;
return;
}
rect.bottom = descr->height;
InvalidateRect( descr->self, &rect, TRUE );
if (descr->style & LBS_MULTICOLUMN)
{
/* Repaint the other columns */
rect.left = rect.right;
rect.right = descr->width;
rect.top = 0;
InvalidateRect( descr->self, &rect, TRUE );
}
}
}
static void LISTBOX_InvalidateItemRect( LB_DESCR *descr, INT index )
{
RECT rect;
if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
InvalidateRect( descr->self, &rect, TRUE );
}
/***********************************************************************
* LISTBOX_GetItemHeight
*/
static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
{
if (descr->style & LBS_OWNERDRAWVARIABLE)
{
if ((index < 0) || (index >= descr->nb_items))
{
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
return descr->items[index].height;
}
else return descr->item_height;
}
/***********************************************************************
* LISTBOX_SetItemHeight
*/
static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index,
INT height, BOOL repaint )
{
if (height > MAXBYTE)
return -1;
if (!height) height = 1;
if (descr->style & LBS_OWNERDRAWVARIABLE)
{
if ((index < 0) || (index >= descr->nb_items))
{
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
TRACE("[%p]: item %d height = %d\n", descr->self, index, height );
descr->items[index].height = height;
LISTBOX_UpdateScroll( descr );
if (repaint)
LISTBOX_InvalidateItems( descr, index );
}
else if (height != descr->item_height)
{
TRACE("[%p]: new height = %d\n", descr->self, height );
descr->item_height = height;
LISTBOX_UpdatePage( descr );
LISTBOX_UpdateScroll( descr );
if (repaint)
InvalidateRect( descr->self, 0, TRUE );
}
return LB_OKAY;
}
/***********************************************************************
* LISTBOX_SetHorizontalPos
*/
static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos )
{
INT diff;
if (pos > descr->horz_extent - descr->width)
pos = descr->horz_extent - descr->width;
if (pos < 0) pos = 0;
if (!(diff = descr->horz_pos - pos)) return;
TRACE("[%p]: new horz pos = %d\n", descr->self, pos );
descr->horz_pos = pos;
LISTBOX_UpdateScroll( descr );
if (abs(diff) < descr->width)
{
RECT rect;
/* Invalidate the focused item so it will be repainted correctly */
if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
InvalidateRect( descr->self, &rect, TRUE );
ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
}
else
InvalidateRect( descr->self, NULL, TRUE );
}
/***********************************************************************
* LISTBOX_SetHorizontalExtent
*/
static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr,
INT extent )
{
if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
return LB_OKAY;
if (extent <= 0) extent = 1;
if (extent == descr->horz_extent) return LB_OKAY;
TRACE("[%p]: new horz extent = %d\n", descr->self, extent );
descr->horz_extent = extent;
if (descr->horz_pos > extent - descr->width)
LISTBOX_SetHorizontalPos( descr, extent - descr->width );
else
LISTBOX_UpdateScroll( descr );
return LB_OKAY;
}
/***********************************************************************
* LISTBOX_SetColumnWidth
*/
static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT width)
{
if (width == descr->column_width) return LB_OKAY;
TRACE("[%p]: new column width = %d\n", descr->self, width );
descr->column_width = width;
LISTBOX_UpdatePage( descr );
return LB_OKAY;
}
/***********************************************************************
* LISTBOX_SetFont
*
* Returns the item height.
*/
static INT LISTBOX_SetFont( LB_DESCR *descr, HFONT font )
{
HDC hdc;
HFONT oldFont = 0;
const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
SIZE sz;
descr->font = font;
if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE )))
{
ERR("unable to get DC.\n" );
return 16;
}
if (font) oldFont = SelectObject( hdc, font );
GetTextExtentPointA( hdc, alphabet, 52, &sz);
if (oldFont) SelectObject( hdc, oldFont );
ReleaseDC( descr->self, hdc );
descr->avg_char_width = (sz.cx / 26 + 1) / 2;
if (!IS_OWNERDRAW(descr))
LISTBOX_SetItemHeight( descr, 0, sz.cy, FALSE );
return sz.cy;
}
/***********************************************************************
* LISTBOX_MakeItemVisible
*
* Make sure that a given item is partially or fully visible.
*/
static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index,
BOOL fully )
{
INT top;
if (index <= descr->top_item) top = index;
else if (descr->style & LBS_MULTICOLUMN)
{
INT cols = descr->width;
if (!fully) cols += descr->column_width - 1;
if (cols >= descr->column_width) cols /= descr->column_width;
else cols = 1;
if (index < descr->top_item + (descr->page_size * cols)) return;
top = index - descr->page_size * (cols - 1);
}
else if (descr->style & LBS_OWNERDRAWVARIABLE)
{
INT height = fully ? descr->items[index].height : 1;
for (top = index; top > descr->top_item; top--)
if ((height += descr->items[top-1].height) > descr->height) break;
}
else
{
if (index < descr->top_item + descr->page_size) return;
if (!fully && (index == descr->top_item + descr->page_size) &&
(descr->height > (descr->page_size * descr->item_height))) return;
top = index - descr->page_size + 1;
}
LISTBOX_SetTopItem( descr, top, TRUE );
}
/***********************************************************************
* LISTBOX_SetCaretIndex
*
* NOTES
* index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
*
*/
static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index,
BOOL fully_visible )
{
INT oldfocus = descr->focus_item;
if (descr->style & LBS_NOSEL) return LB_ERR;
if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
if (index == oldfocus) return LB_OKAY;
descr->focus_item = index;
if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
LISTBOX_MakeItemVisible( descr, index, fully_visible );
if (descr->caret_on && (descr->in_focus))
LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
return LB_OKAY;
}
/***********************************************************************
* LISTBOX_SelectItemRange
*
* Select a range of items. Should only be used on a MULTIPLESEL listbox.
*/
static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
INT last, BOOL on )
{
INT i;
/* A few sanity checks */
if (descr->style & LBS_NOSEL) return LB_ERR;
if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
if (!descr->nb_items) return LB_OKAY;
if (last == -1 || last >= descr->nb_items) last = descr->nb_items - 1;
if (first < 0) first = 0;
if (last < first) return LB_OKAY;
if (on) /* Turn selection on */
{
for (i = first; i <= last; i++)
{
if (descr->items[i].selected) continue;
descr->items[i].selected = TRUE;
LISTBOX_InvalidateItemRect(descr, i);
}
}
else /* Turn selection off */
{
for (i = first; i <= last; i++)
{
if (!descr->items[i].selected) continue;
descr->items[i].selected = FALSE;
LISTBOX_InvalidateItemRect(descr, i);
}
}
return LB_OKAY;
}
/***********************************************************************
* LISTBOX_SetSelection
*/
static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
BOOL on, BOOL send_notify )
{
TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
if (descr->style & LBS_NOSEL)
{
descr->selected_item = index;
return LB_ERR;
}
if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
if (descr->style & LBS_MULTIPLESEL)
{
if (index == -1) /* Select all items */
return LISTBOX_SelectItemRange( descr, 0, -1, on );
else /* Only one item */
return LISTBOX_SelectItemRange( descr, index, index, on );
}
else
{
INT oldsel = descr->selected_item;
if (index == oldsel) return LB_OKAY;
if (oldsel != -1) descr->items[oldsel].selected = FALSE;
if (index != -1) descr->items[index].selected = TRUE;
descr->selected_item = index;
if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
(index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
else
if( descr->lphc ) /* set selection change flag for parent combo */
descr->lphc->wState |= CBF_SELCHANGE;
}
return LB_OKAY;
}
/***********************************************************************
* LISTBOX_MoveCaret
*
* Change the caret position and extend the selection to the new caret.
*/
static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index,
BOOL fully_visible )
{
INT oldfocus = descr->focus_item;
if ((index < 0) || (index >= descr->nb_items))
return;
/* Important, repaint needs to be done in this order if
you want to mimic Windows behavior:
1. Remove the focus and paint the item
2. Remove the selection and paint the item(s)
3. Set the selection and repaint the item(s)
4. Set the focus to 'index' and repaint the item */
/* 1. remove the focus and repaint the item */
descr->focus_item = -1;
if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
/* 2. then turn off the previous selection */
/* 3. repaint the new selected item */
if (descr->style & LBS_EXTENDEDSEL)
{
if (descr->anchor_item != -1)
{
INT first = min( index, descr->anchor_item );
INT last = max( index, descr->anchor_item );
if (first > 0)
LISTBOX_SelectItemRange( descr, 0, first - 1, FALSE );
LISTBOX_SelectItemRange( descr, last + 1, -1, FALSE );
LISTBOX_SelectItemRange( descr, first, last, TRUE );
}
}
else if (!(descr->style & LBS_MULTIPLESEL))
{
/* Set selection to new caret item */
LISTBOX_SetSelection( descr, index, TRUE, FALSE );
}
/* 4. repaint the new item with the focus */
descr->focus_item = index;
LISTBOX_MakeItemVisible( descr, index, fully_visible );
if (descr->caret_on && (descr->in_focus))
LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
}
/***********************************************************************
* LISTBOX_InsertItem
*/
static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
LPWSTR str, DWORD data )
{
LB_ITEMDATA *item;
INT max_items;
INT oldfocus = descr->focus_item;
if (index == -1) index = descr->nb_items;
else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
if (!descr->items) max_items = 0;
else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
if (descr->nb_items == max_items)
{
/* We need to grow the array */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -