[PATCH v2 1/4] shell32/autocomplete: Implement the listbox scrollbar manually
Gabriel Ivăncescu
gabrielopcode at gmail.com
Tue May 28 07:21:40 CDT 2019
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
v2: Use a separate scrollbar control and sizing grip.
This is a no-op patch; its purpose is to keep the next patch smaller and
focused only on implementing the resizing grip. Some of the things are done
that way purposefully, for example, the WM_WINDOWPOSCHANGED is also useful
to that end.
dlls/shell32/autocomplete.c | 103 ++++++++++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 5 deletions(-)
diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index f0777ff..b9029eb 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -65,6 +65,7 @@ typedef struct
HWND hwndEdit;
HWND hwndListBox;
HWND hwndListBoxOwner;
+ HWND hwndListBoxScroll;
WNDPROC wpOrigEditProc;
WNDPROC wpOrigLBoxProc;
WNDPROC wpOrigLBoxOwnerProc;
@@ -284,6 +285,45 @@ static void free_enum_strs(IAutoCompleteImpl *ac)
}
}
+static void update_listbox_size(IAutoCompleteImpl *ac, UINT width, UINT height)
+{
+ UINT item_height, listbox_width, grip_sz, scroll_h, prev_scroll_h;
+ SCROLLINFO info;
+ RECT r;
+
+ GetClientRect(ac->hwndListBoxScroll, &r);
+ prev_scroll_h = r.bottom - r.top;
+
+ info.nMax = SendMessageW(ac->hwndListBox, LB_GETCOUNT, 0, 0) - 1;
+ item_height = SendMessageW(ac->hwndListBox, LB_GETITEMHEIGHT, 0, 0);
+ grip_sz = GetSystemMetrics(SM_CXVSCROLL);
+ width -= GetSystemMetrics(SM_CXBORDER) * 2;
+ height -= GetSystemMetrics(SM_CYBORDER) * 2;
+ info.nPage = max(height / item_height, 1);
+
+ /* Set the scrollbar info if it's visible */
+ listbox_width = width;
+ if (info.nMax >= info.nPage)
+ {
+ scroll_h = height;
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ info.nMin = 0;
+ info.nPos = SendMessageW(ac->hwndListBox, LB_GETTOPINDEX, 0, 0);
+ SetScrollInfo(ac->hwndListBoxScroll, SB_CTL, &info, scroll_h == prev_scroll_h);
+
+ listbox_width -= grip_sz;
+ }
+ else
+ scroll_h = 0;
+
+ SetWindowPos(ac->hwndListBoxScroll, NULL, width - grip_sz, 0, grip_sz, scroll_h,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_DEFERERASE);
+
+ SetWindowPos(ac->hwndListBox, NULL, 0, 0, listbox_width, height,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_DEFERERASE);
+}
+
static void hide_listbox(IAutoCompleteImpl *ac, HWND hwnd, BOOL reset)
{
ShowWindow(ac->hwndListBoxOwner, SW_HIDE);
@@ -304,7 +344,12 @@ static void show_listbox(IAutoCompleteImpl *ac)
width = r.right - r.left;
SetWindowPos(ac->hwndListBoxOwner, HWND_TOP, r.left, r.bottom + 1, width, height,
- SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
+
+ /* Update the grip here (as we skip it during message processing), due
+ to the fact that the size itself might not always change, while the
+ count does and thus it possibly needs updating of the scrollbar */
+ update_listbox_size(ac, width, height);
}
static void set_listbox_font(IAutoCompleteImpl *ac, HFONT font)
@@ -863,6 +908,36 @@ static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
set_text_and_selection(This, This->hwndEdit, msg, 0, strlenW(msg));
hide_listbox(This, hwnd, TRUE);
return 0;
+ case WM_VSCROLL:
+ /* Handle thumb tracking manually as the listbox doesn't have WS_VSCROLL */
+ if (LOWORD(wParam) == SB_THUMBTRACK || LOWORD(wParam) == SB_THUMBPOSITION)
+ {
+ SCROLLINFO info;
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_TRACKPOS;
+ if (!GetScrollInfo(This->hwndListBoxScroll, SB_CTL, &info))
+ return 0;
+ uMsg = LB_SETTOPINDEX;
+ wParam = info.nTrackPos;
+ }
+ /* fall through */
+ case WM_MOUSEWHEEL:
+ case LB_SETCURSEL:
+ case LB_SETITEMHEIGHT:
+ case LB_SETTOPINDEX:
+ {
+ LRESULT ret = CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam);
+ SCROLLINFO info;
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ info.nMin = 0;
+ info.nMax = SendMessageW(hwnd, LB_GETCOUNT, 0, 0) - 1;
+ info.nPage = SendMessageW(hwnd, LB_GETLISTBOXINFO, 0, 0);
+ info.nPos = SendMessageW(hwnd, LB_GETTOPINDEX, 0, 0);
+
+ SetScrollInfo(This->hwndListBoxScroll, SB_CTL, &info, TRUE);
+ return ret;
+ }
}
return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam);
}
@@ -879,10 +954,20 @@ static LRESULT APIENTRY ACLBoxOwnerSubclassProc(HWND hwnd, UINT uMsg, WPARAM wPa
if (draw_listbox_item(This, (DRAWITEMSTRUCT*)lParam, wParam))
return TRUE;
break;
- case WM_SIZE:
- SetWindowPos(This->hwndListBox, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_DEFERERASE);
+ case WM_VSCROLL:
+ return SendMessageW(This->hwndListBox, uMsg, wParam, lParam);
+ case WM_WINDOWPOSCHANGED:
+ {
+ const WINDOWPOS *wp = (const WINDOWPOS*)lParam;
+
+ if (!(wp->flags & SWP_NOSIZE))
+ {
+ if (wp->flags & SWP_NOSENDCHANGING) break;
+
+ update_listbox_size(This, wp->cx, wp->cy);
+ }
break;
+ }
}
return CallWindowProcW(This->wpOrigLBoxOwnerProc, hwnd, uMsg, wParam, lParam);
}
@@ -899,8 +984,15 @@ static void create_listbox(IAutoCompleteImpl *This)
}
/* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */
+ This->hwndListBoxScroll = CreateWindowExW(WS_EX_NOACTIVATE, WC_SCROLLBARW, NULL,
+ WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 1,
+ This->hwndListBoxOwner, NULL, shell32_hInstance, NULL);
+ if (!This->hwndListBoxScroll) goto fail;
+
+ /* Create the listbox */
This->hwndListBox = CreateWindowExW(WS_EX_NOACTIVATE, WC_LISTBOXW, NULL,
- WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT,
+ WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
+ LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT,
0, 0, 0, 0, This->hwndListBoxOwner, NULL, shell32_hInstance, NULL);
if (This->hwndListBox) {
@@ -919,6 +1011,7 @@ static void create_listbox(IAutoCompleteImpl *This)
return;
}
+fail:
DestroyWindow(This->hwndListBoxOwner);
This->hwndListBoxOwner = NULL;
This->options &= ~ACO_AUTOSUGGEST;
--
2.21.0
More information about the wine-devel
mailing list