Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Note that we can't rely on the sizing grip's resize because of the triangle shape which must still act as a square when clicking.
dlls/shell32/autocomplete.c | 113 +++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 7 deletions(-)
diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c index b9029eb..24aa895 100644 --- a/dlls/shell32/autocomplete.c +++ b/dlls/shell32/autocomplete.c @@ -62,13 +62,17 @@ typedef struct UINT enum_strs_num; WCHAR **enum_strs; WCHAR **listbox_strs; + UINT listbox_width; + UINT listbox_height; HWND hwndEdit; HWND hwndListBox; HWND hwndListBoxOwner; + HWND hwndListBoxGrip; HWND hwndListBoxScroll; WNDPROC wpOrigEditProc; WNDPROC wpOrigLBoxProc; WNDPROC wpOrigLBoxOwnerProc; + WNDPROC wpOrigLBoxGripProc; WCHAR *txtbackup; WCHAR *quickComplete; IEnumString *enumstr; @@ -303,23 +307,42 @@ static void update_listbox_size(IAutoCompleteImpl *ac, UINT width, UINT height)
/* Set the scrollbar info if it's visible */ listbox_width = width; - if (info.nMax >= info.nPage) + if (info.nMax >= info.nPage && height > grip_sz) { - scroll_h = height; + scroll_h = height - grip_sz; 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);
+ if (!prev_scroll_h) SetWindowRgn(ac->hwndListBoxGrip, NULL, TRUE); listbox_width -= grip_sz; } else + { scroll_h = 0;
+ if (prev_scroll_h) + { + /* The grip is a triangle when the scrollbar is not visible */ + HRGN hrgn; + POINT pt[3]; + pt[0].x = pt[1].y = pt[2].x = pt[2].y = grip_sz; + pt[0].y = pt[1].x = 0; + + hrgn = CreatePolygonRgn(pt, ARRAY_SIZE(pt), WINDING); + if (hrgn && !SetWindowRgn(ac->hwndListBoxGrip, hrgn, FALSE)) + DeleteObject(hrgn); + } + } + SetWindowPos(ac->hwndListBoxScroll, NULL, width - grip_sz, 0, grip_sz, scroll_h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_DEFERERASE);
+ SetWindowPos(ac->hwndListBoxGrip, NULL, width - grip_sz, height - grip_sz, 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | 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); } @@ -338,10 +361,19 @@ static void show_listbox(IAutoCompleteImpl *ac)
GetWindowRect(ac->hwndEdit, &r);
- /* Windows XP displays 7 lines at most, then it uses a scroll bar */ - cnt = SendMessageW(ac->hwndListBox, LB_GETCOUNT, 0, 0); - height = SendMessageW(ac->hwndListBox, LB_GETITEMHEIGHT, 0, 0) * min(cnt + 1, 7); - width = r.right - r.left; + /* See if the listbox has been resized by the user */ + if (ac->listbox_width) + { + width = ac->listbox_width; + height = ac->listbox_height; + } + else + { + /* Windows XP displays 7 lines at most, then it uses a scroll bar */ + cnt = SendMessageW(ac->hwndListBox, LB_GETCOUNT, 0, 0); + height = SendMessageW(ac->hwndListBox, LB_GETITEMHEIGHT, 0, 0) * min(cnt + 1, 7); + width = r.right - r.left; + }
SetWindowPos(ac->hwndListBoxOwner, HWND_TOP, r.left, r.bottom + 1, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE); @@ -406,6 +438,15 @@ static BOOL draw_listbox_item(IAutoCompleteImpl *ac, DRAWITEMSTRUCT *info, UINT return TRUE; }
+static inline BOOL hit_test_listbox_grip(IAutoCompleteImpl *ac, LPARAM lParam) +{ + POINT pt = { (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) }; + RECT r; + + GetWindowRect(ac->hwndListBoxGrip, &r); + return PtInRect(&r, pt); +} + static size_t format_quick_complete(WCHAR *dst, const WCHAR *qc, const WCHAR *str, size_t str_len) { /* Replace the first %s directly without using snprintf, to avoid @@ -938,6 +979,10 @@ static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, SetScrollInfo(This->hwndListBoxScroll, SB_CTL, &info, TRUE); return ret; } + case WM_NCHITTEST: + if (hit_test_listbox_grip(This, lParam)) + return HTTRANSPARENT; + break; } return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam); } @@ -956,24 +1001,71 @@ static LRESULT APIENTRY ACLBoxOwnerSubclassProc(HWND hwnd, UINT uMsg, WPARAM wPa break; case WM_VSCROLL: return SendMessageW(This->hwndListBox, uMsg, wParam, lParam); + case WM_GETMINMAXINFO: + { + /* Prevent shrinking the dropdown below the grip's size */ + UINT grip_sz = GetSystemMetrics(SM_CXVSCROLL); + ((MINMAXINFO*)lParam)->ptMinTrackSize.x = grip_sz + GetSystemMetrics(SM_CXBORDER) * 2; + ((MINMAXINFO*)lParam)->ptMinTrackSize.y = grip_sz + GetSystemMetrics(SM_CYBORDER) * 2; + return 0; + } + case WM_WINDOWPOSCHANGING: + /* Fix a bug when resizing against the taskbar */ + ((WINDOWPOS*)lParam)->flags |= SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_DEFERERASE; + ((WINDOWPOS*)lParam)->hwndInsertAfter = HWND_TOP; + break; 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;
+ This->listbox_width = wp->cx; + This->listbox_height = wp->cy; update_listbox_size(This, wp->cx, wp->cy); } break; } + case WM_NCHITTEST: + if (hit_test_listbox_grip(This, lParam)) + return HTBOTTOMRIGHT; + break; + case WM_NCLBUTTONDBLCLK: + if (hit_test_listbox_grip(This, lParam)) + { + /* For convenience, double-click on the grip reverts to auto sizing */ + This->listbox_width = 0; + show_listbox(This); + return 0; + } + /* fall through */ + case WM_NCLBUTTONDOWN: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); } 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_NCHITTEST: + return HTTRANSPARENT; + } + 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); @@ -983,12 +1075,16 @@ static void create_listbox(IAutoCompleteImpl *This) return; }
- /* 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;
+ This->hwndListBoxGrip = CreateWindowExW(WS_EX_NOACTIVATE, WC_SCROLLBARW, NULL, + WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP, 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_CLIPSIBLINGS | @@ -1004,6 +1100,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)