📄 listbox.c
字号:
INT i;
LPINT16 p = (LPINT16)tabs;
TRACE("[%p]: settabstops ", hwnd );
for (i = 0; i < descr->nb_tabs; i++) {
descr->tabs[i] = *p++<<1; /* FIXME */
if (TRACE_ON(listbox)) TRACE("%hd ", descr->tabs[i]);
}
if (TRACE_ON(listbox)) TRACE("\n");
}
else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
#else
memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
#endif
/* convert into "dialog units"*/
for (i = 0; i < descr->nb_tabs; i++)
descr->tabs[i] = MulDiv(descr->tabs[i], descr->avg_char_width, 4);
return TRUE;
}
/***********************************************************************
* LISTBOX_GetText
*/
static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR buffer, BOOL unicode )
{
if ((index < 0) || (index >= descr->nb_items))
{
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
if (HAS_STRINGS(descr))
{
if (!buffer)
{
DWORD len = strlenW(descr->items[index].str);
if( unicode )
return len;
return WideCharToMultiByte( CP_ACP, 0, descr->items[index].str, len,
NULL, 0, NULL, NULL );
}
TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
if(unicode)
{
strcpyW( buffer, descr->items[index].str );
return strlenW(buffer);
}
else
{
return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, (LPSTR)buffer, 0x7FFFFFFF, NULL, NULL) - 1;
}
} else {
if (buffer)
*((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data);
return sizeof(DWORD);
}
}
static inline INT LISTBOX_lstrcmpiW( LCID lcid, LPCWSTR str1, LPCWSTR str2 )
{
INT ret = CompareStringW( lcid, NORM_IGNORECASE, str1, -1, str2, -1 );
if (ret == CSTR_LESS_THAN)
return -1;
if (ret == CSTR_EQUAL)
return 0;
if (ret == CSTR_GREATER_THAN)
return 1;
return -1;
}
/***********************************************************************
* LISTBOX_FindStringPos
*
* Find the nearest string located before a given string in sort order.
* If 'exact' is TRUE, return an error if we don't get an exact match.
*/
static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact )
{
INT index, min, max, res = -1;
if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
min = 0;
max = descr->nb_items;
while (min != max)
{
index = (min + max) / 2;
if (HAS_STRINGS(descr))
res = LISTBOX_lstrcmpiW( descr->locale, str, descr->items[index].str);
else
{
COMPAREITEMSTRUCT cis;
UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
cis.CtlType = ODT_LISTBOX;
cis.CtlID = id;
cis.hwndItem = descr->self;
/* note that some application (MetaStock) expects the second item
* to be in the listbox */
cis.itemID1 = -1;
cis.itemData1 = (DWORD)str;
cis.itemID2 = index;
cis.itemData2 = descr->items[index].data;
cis.dwLocaleId = descr->locale;
res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
}
if (!res) return index;
if (res < 0) max = index;
else min = index + 1;
}
return exact ? -1 : max;
}
/***********************************************************************
* LISTBOX_FindFileStrPos
*
* Find the nearest string located before a given string in directory
* sort order (i.e. first files, then directories, then drives).
*/
static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str )
{
INT min, max, res = -1;
if (!HAS_STRINGS(descr))
return LISTBOX_FindStringPos( descr, str, FALSE );
min = 0;
max = descr->nb_items;
while (min != max)
{
INT index = (min + max) / 2;
LPCWSTR p = descr->items[index].str;
if (*p == '[') /* drive or directory */
{
if (*str != '[') res = -1;
else if (p[1] == '-') /* drive */
{
if (str[1] == '-') res = str[2] - p[2];
else res = -1;
}
else /* directory */
{
if (str[1] == '-') res = 1;
else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
}
}
else /* filename */
{
if (*str == '[') res = 1;
else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
}
if (!res) return index;
if (res < 0) max = index;
else min = index + 1;
}
return max;
}
/***********************************************************************
* LISTBOX_FindString
*
* Find the item beginning with a given string.
*/
static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact )
{
INT i;
LB_ITEMDATA *item;
if (start >= descr->nb_items) start = -1;
item = descr->items + start + 1;
if (HAS_STRINGS(descr))
{
if (!str || ! str[0] ) return LB_ERR;
if (exact)
{
for (i = start + 1; i < descr->nb_items; i++, item++)
if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
for (i = 0, item = descr->items; i <= start; i++, item++)
if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
}
else
{
/* Special case for drives and directories: ignore prefix */
#define CHECK_DRIVE(item) \
if ((item)->str[0] == '[') \
{ \
if (!strncmpiW( str, (item)->str+1, len )) return i; \
if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
return i; \
}
INT len = strlenW(str);
for (i = start + 1; i < descr->nb_items; i++, item++)
{
if (!strncmpiW( str, item->str, len )) return i;
CHECK_DRIVE(item);
}
for (i = 0, item = descr->items; i <= start; i++, item++)
{
if (!strncmpiW( str, item->str, len )) return i;
CHECK_DRIVE(item);
}
#undef CHECK_DRIVE
}
}
else
{
if (exact && (descr->style & LBS_SORT))
/* If sorted, use a WM_COMPAREITEM binary search */
return LISTBOX_FindStringPos( descr, str, TRUE );
/* Otherwise use a linear search */
for (i = start + 1; i < descr->nb_items; i++, item++)
if (item->data == (ULONG_PTR)str) return i;
for (i = 0, item = descr->items; i <= start; i++, item++)
if (item->data == (ULONG_PTR)str) return i;
}
return LB_ERR;
}
/***********************************************************************
* LISTBOX_GetSelCount
*/
static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
{
INT i, count;
LB_ITEMDATA *item = descr->items;
if (!(descr->style & LBS_MULTIPLESEL) ||
(descr->style & LBS_NOSEL))
return LB_ERR;
for (i = count = 0; i < descr->nb_items; i++, item++)
if (item->selected) count++;
return count;
}
#ifndef __REACTOS__
/***********************************************************************
* LISTBOX_GetSelItems16
*/
static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
{
INT i, count;
LB_ITEMDATA *item = descr->items;
if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
if (item->selected) array[count++] = (INT16)i;
return count;
}
#endif
/***********************************************************************
* LISTBOX_GetSelItems
*/
static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
{
INT i, count;
LB_ITEMDATA *item = descr->items;
if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
if (item->selected) array[count++] = i;
return count;
}
/***********************************************************************
* LISTBOX_Paint
*/
static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc )
{
INT i, col_pos = descr->page_size - 1;
RECT rect;
RECT focusRect = {-1, -1, -1, -1};
HFONT oldFont = 0;
HBRUSH hbrush, oldBrush = 0;
if (descr->style & LBS_NOREDRAW) return 0;
SetRect( &rect, 0, 0, descr->width, descr->height );
if (descr->style & LBS_MULTICOLUMN)
rect.right = rect.left + descr->column_width;
else if (descr->horz_pos)
{
SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
rect.right += descr->horz_pos;
}
if (descr->font) oldFont = SelectObject( hdc, descr->font );
hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
(WPARAM)hdc, (LPARAM)descr->self );
if (hbrush) oldBrush = SelectObject( hdc, hbrush );
if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
(descr->in_focus))
{
/* Special case for empty listbox: paint focus rect */
rect.bottom = rect.top + descr->item_height;
ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
&rect, NULL, 0, NULL );
LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item,
ODA_FOCUS, FALSE );
rect.top = rect.bottom;
}
/* Paint all the item, regarding the selection
Focus state will be painted after */
for (i = descr->top_item; i < descr->nb_items; i++)
{
if (!(descr->style & LBS_OWNERDRAWVARIABLE))
rect.bottom = rect.top + descr->item_height;
else
rect.bottom = rect.top + descr->items[i].height;
if (i == descr->focus_item)
{
/* keep the focus rect, to paint the focus item after */
focusRect.left = rect.left;
focusRect.right = rect.right;
focusRect.top = rect.top;
focusRect.bottom = rect.bottom;
}
LISTBOX_PaintItem( descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
rect.top = rect.bottom;
if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
{
if (!IS_OWNERDRAW(descr))
{
/* Clear the bottom of the column */
if (rect.top < descr->height)
{
rect.bottom = descr->height;
ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
&rect, NULL, 0, NULL );
}
}
/* Go to the next column */
rect.left += descr->column_width;
rect.right += descr->column_width;
rect.top = 0;
col_pos = descr->page_size - 1;
}
else
{
col_pos--;
if (rect.top >= descr->height) break;
}
}
/* Paint the focus item now */
if (focusRect.top != focusRect.bottom &&
descr->caret_on && descr->in_focus)
LISTBOX_PaintItem( descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
if (!IS_OWNERDRAW(descr))
{
/* Clear the remainder of the client area */
if (rect.top < descr->height)
{
rect.bottom = descr->height;
ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
&rect, NULL, 0, NULL );
}
if (rect.right < descr->width)
{
rect.left = rect.right;
rect.right = descr->width;
rect.top = 0;
rect.bottom = descr->height;
ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
&rect, NULL, 0, NULL );
}
}
if (oldFont) SelectObject( hdc, oldFont );
if (oldBrush) SelectObject( hdc, oldBrush );
return 0;
}
/***********************************************************************
* LISTBOX_InvalidateItems
*
* Invalidate all items from a given item. If the specified item is not
* visible, nothing happens.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -