Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
This is a no-op patch; its purpose is to keep the next patch smaller and
focused only on implementing the resizing grip, because IMO it was a bit
large before I split it. Note that to avoid more pointless changes in the
next patch, names with "grip" have been used for the scrollbar, I hope
that's not a problem.
Some of the things are done purposefully to keep the next patch smaller, while
they may not make sense by themselves. For example, the WM_WINDOWPOSCHANGED
is also useful to that end.
dlls/shell32/autocomplete.c | 132 ++++++++++++++++++++++++++++++++++--
1 file changed, 127 insertions(+), 5 deletions(-)
diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index f0777ff..38ca8ca 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -65,9 +65,11 @@ typedef struct
HWND hwndEdit;
HWND hwndListBox;
HWND hwndListBoxOwner;
+ HWND hwndListBoxGrip;
WNDPROC wpOrigEditProc;
WNDPROC wpOrigLBoxProc;
WNDPROC wpOrigLBoxOwnerProc;
+ WNDPROC wpOrigLBoxGripProc;
WCHAR *txtbackup;
WCHAR *quickComplete;
IEnumString *enumstr;
@@ -284,6 +286,41 @@ 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, grip_height;
+ SCROLLINFO info;
+
+ 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)
+ {
+ grip_height = 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->hwndListBoxGrip, SB_VERT, &info, FALSE);
+
+ listbox_width -= grip_sz;
+ }
+ else
+ grip_height = 0;
+
+ SetWindowPos(ac->hwndListBoxGrip, NULL, width - grip_sz, 0, grip_sz, grip_height,
+ 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 +341,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 +905,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->hwndListBoxGrip, SB_VERT, &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->hwndListBoxGrip, SB_VERT, &info, TRUE);
+ return ret;
+ }
}
return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam);
}
@@ -879,16 +951,55 @@ 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_WINDOWPOSCHANGED:
+ {
+ const WINDOWPOS *wp = (const WINDOWPOS*)lParam;
+
+ if (!(wp->flags & SWP_NOSIZE))
+ {
+ /* Only proceed with the update if the user resized it */
+ if (wp->flags & SWP_NOSENDCHANGING) break;
+
+ update_listbox_size(This, wp->cx, wp->cy);
+ }
break;
+ }
}
return CallWindowProcW(This->wpOrigLBoxOwnerProc, hwnd, uMsg, wParam, lParam);
}
+static LRESULT APIENTRY ACLBoxGripSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ IAutoCompleteImpl *This = (IAutoCompleteImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+
+ switch (uMsg)
+ {
+ case WM_MOUSEACTIVATE:
+ return MA_NOACTIVATE;
+ case WM_VSCROLL:
+ return SendMessageW(This->hwndListBox, uMsg, wParam, lParam);
+ case WM_NCCALCSIZE:
+ {
+ NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS*)lParam;
+ if (wParam == FALSE) return 0;
+
+ p->rgrc[0].right = p->rgrc[0].left;
+
+ return 0;
+ }
+ case WM_NCHITTEST:
+ return HTVSCROLL;
+ case WM_NCLBUTTONDOWN:
+ case WM_NCLBUTTONDBLCLK:
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ }
+ return CallWindowProcW(This->wpOrigLBoxGripProc, hwnd, uMsg, wParam, lParam);
+}
+
static void create_listbox(IAutoCompleteImpl *This)
{
+ UINT grip_sz = GetSystemMetrics(SM_CXVSCROLL);
+
This->hwndListBoxOwner = CreateWindowExW(WS_EX_NOACTIVATE, WC_STATICW, NULL,
WS_BORDER | WS_POPUP | WS_CLIPCHILDREN,
0, 0, 0, 0, NULL, NULL, shell32_hInstance, NULL);
@@ -899,8 +1010,15 @@ static void create_listbox(IAutoCompleteImpl *This)
}
/* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */
+ This->hwndListBoxGrip = CreateWindowExW(WS_EX_NOACTIVATE, WC_STATICW, NULL,
+ WS_CHILD | WS_VISIBLE, 0, 0, grip_sz, grip_sz,
+ This->hwndListBoxOwner, NULL, shell32_hInstance, NULL);
+ if (!This->hwndListBoxGrip) 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) {
@@ -912,6 +1030,9 @@ static void create_listbox(IAutoCompleteImpl *This)
This->wpOrigLBoxOwnerProc = (WNDPROC)SetWindowLongPtrW(This->hwndListBoxOwner, GWLP_WNDPROC, (LONG_PTR)ACLBoxOwnerSubclassProc);
SetWindowLongPtrW(This->hwndListBoxOwner, GWLP_USERDATA, (LONG_PTR)This);
+ This->wpOrigLBoxGripProc = (WNDPROC)SetWindowLongPtrW(This->hwndListBoxGrip, GWLP_WNDPROC, (LONG_PTR)ACLBoxGripSubclassProc);
+ SetWindowLongPtrW(This->hwndListBoxGrip, GWLP_USERDATA, (LONG_PTR)This);
+
/* Use the same font as the edit control, as it gets destroyed before it anyway */
edit_font = (HFONT)SendMessageW(This->hwndEdit, WM_GETFONT, 0, 0);
if (edit_font)
@@ -919,6 +1040,7 @@ static void create_listbox(IAutoCompleteImpl *This)
return;
}
+fail:
DestroyWindow(This->hwndListBoxOwner);
This->hwndListBoxOwner = NULL;
This->options &= ~ACO_AUTOSUGGEST;
--
2.20.1