Signed-off-by: Gabriel Ivăncescu gabrielopcode@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;