mirror of
https://github.com/reactos/reactos.git
synced 2024-07-02 10:45:24 +00:00
[BROWSEUI] Enable AutoAppend of auto-completion (#3552)
Fix and improve Auto-Append of auto-completion. CORE-9281 - Implement CAutoComplete::DoAutoAppend method.
This commit is contained in:
parent
6b04e46304
commit
91e591b3d5
|
@ -40,6 +40,35 @@
|
||||||
static HHOOK s_hMouseHook = NULL; // hook handle
|
static HHOOK s_hMouseHook = NULL; // hook handle
|
||||||
static HWND s_hWatchWnd = NULL; // the window handle to watch
|
static HWND s_hWatchWnd = NULL; // the window handle to watch
|
||||||
|
|
||||||
|
struct PREFIX_INFO
|
||||||
|
{
|
||||||
|
LPCWSTR psz;
|
||||||
|
INT cch;
|
||||||
|
};
|
||||||
|
static const PREFIX_INFO s_prefixes[] =
|
||||||
|
{
|
||||||
|
{ L"https://", 8 },
|
||||||
|
{ L"http://www.", 11 },
|
||||||
|
{ L"http://", 7 },
|
||||||
|
{ L"www.", 4 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline BOOL DropPrefix(const CStringW& str, CStringW& strBody)
|
||||||
|
{
|
||||||
|
for (size_t iPrefix = 0; iPrefix < _countof(s_prefixes); ++iPrefix)
|
||||||
|
{
|
||||||
|
LPCWSTR psz = s_prefixes[iPrefix].psz;
|
||||||
|
INT cch = s_prefixes[iPrefix].cch;
|
||||||
|
if (::StrCmpNIW(str, psz, cch) == 0)
|
||||||
|
{
|
||||||
|
strBody = str.Mid(cch);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strBody = str;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// mouse hook procedure to watch the mouse click
|
// mouse hook procedure to watch the mouse click
|
||||||
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644988(v=vs.85)
|
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644988(v=vs.85)
|
||||||
static LRESULT CALLBACK MouseProc(INT nCode, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK MouseProc(INT nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
@ -80,33 +109,41 @@ static LRESULT CALLBACK MouseProc(INT nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
typedef CSimpleArray<CStringW> list_t;
|
typedef CSimpleArray<CStringW> list_t;
|
||||||
|
|
||||||
static inline INT pivot(list_t& a, INT i, INT j)
|
static inline INT compare1(const CStringW& str1, const CStringW& str2)
|
||||||
|
{
|
||||||
|
CStringW s1, s2;
|
||||||
|
DropPrefix(str1, s1);
|
||||||
|
DropPrefix(str2, s2);
|
||||||
|
return s1.CompareNoCase(s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline INT pivot(list_t& list, INT i, INT j)
|
||||||
{
|
{
|
||||||
INT k = i + 1;
|
INT k = i + 1;
|
||||||
while (k <= j && a[i].CompareNoCase(a[k]) == 0)
|
while (k <= j && compare1(list[i], list[k]) == 0)
|
||||||
k++;
|
k++;
|
||||||
if (k > j)
|
if (k > j)
|
||||||
return -1;
|
return -1;
|
||||||
if (a[i].CompareNoCase(a[k]) >= 0)
|
if (compare1(list[i], list[k]) >= 0)
|
||||||
return i;
|
return i;
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline INT partition(list_t& a, INT i, INT j, const CStringW& x)
|
static inline INT partition(list_t& list, INT i, INT j, const CStringW& x)
|
||||||
{
|
{
|
||||||
INT left = i, right = j;
|
INT left = i, right = j;
|
||||||
while (left <= right)
|
while (left <= right)
|
||||||
{
|
{
|
||||||
while (left <= j && a[left].CompareNoCase(x) < 0)
|
while (left <= j && compare1(list[left], x) < 0)
|
||||||
left++;
|
left++;
|
||||||
while (right >= i && a[right].CompareNoCase(x) >= 0)
|
while (right >= i && compare1(list[right], x) >= 0)
|
||||||
right--;
|
right--;
|
||||||
if (left > right)
|
if (left > right)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
CStringW tmp = a[left];
|
CStringW tmp = list[left];
|
||||||
a[left] = a[right];
|
list[left] = list[right];
|
||||||
a[right] = tmp;
|
list[right] = tmp;
|
||||||
|
|
||||||
left++;
|
left++;
|
||||||
right--;
|
right--;
|
||||||
|
@ -114,16 +151,16 @@ static inline INT partition(list_t& a, INT i, INT j, const CStringW& x)
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quicksort(list_t& a, INT i, INT j)
|
static void quicksort(list_t& list, INT i, INT j)
|
||||||
{
|
{
|
||||||
if (i == j)
|
if (i == j)
|
||||||
return;
|
return;
|
||||||
INT p = pivot(a, i, j);
|
INT p = pivot(list, i, j);
|
||||||
if (p == -1)
|
if (p == -1)
|
||||||
return;
|
return;
|
||||||
INT k = partition(a, i, j, a[p]);
|
INT k = partition(list, i, j, list[p]);
|
||||||
quicksort(a, i, k - 1);
|
quicksort(list, i, k - 1);
|
||||||
quicksort(a, k, j);
|
quicksort(list, k, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void DoSort(list_t& list)
|
static inline void DoSort(list_t& list)
|
||||||
|
@ -142,7 +179,7 @@ static INT DoUnique(list_t& list)
|
||||||
INT result = first;
|
INT result = first;
|
||||||
while (++first != last)
|
while (++first != last)
|
||||||
{
|
{
|
||||||
if (list[result].CompareNoCase(list[first]) != 0)
|
if (compare1(list[result], list[first]) != 0)
|
||||||
list[++result] = list[first];
|
list[++result] = list[first];
|
||||||
}
|
}
|
||||||
return ++result;
|
return ++result;
|
||||||
|
@ -158,7 +195,6 @@ static inline void DoUniqueAndTrim(list_t& list)
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// CACEditCtrl
|
|
||||||
|
|
||||||
// range of WCHAR (inclusive)
|
// range of WCHAR (inclusive)
|
||||||
struct RANGE
|
struct RANGE
|
||||||
|
@ -217,113 +253,61 @@ EditWordBreakProcW(LPWSTR lpch, INT index, INT count, INT code)
|
||||||
{
|
{
|
||||||
case WB_ISDELIMITER:
|
case WB_ISDELIMITER:
|
||||||
return IsWordBreak(lpch[index]);
|
return IsWordBreak(lpch[index]);
|
||||||
|
|
||||||
case WB_LEFT:
|
case WB_LEFT:
|
||||||
|
{
|
||||||
if (index)
|
if (index)
|
||||||
--index;
|
--index;
|
||||||
while (index && !IsWordBreak(lpch[index]))
|
while (index && !IsWordBreak(lpch[index]))
|
||||||
--index;
|
--index;
|
||||||
return index;
|
return index;
|
||||||
|
}
|
||||||
case WB_RIGHT:
|
case WB_RIGHT:
|
||||||
|
{
|
||||||
if (!count)
|
if (!count)
|
||||||
break;
|
break;
|
||||||
while (index < count && lpch[index] && !IsWordBreak(lpch[index]))
|
while (index < count && lpch[index] && !IsWordBreak(lpch[index]))
|
||||||
++index;
|
++index;
|
||||||
return index;
|
return index;
|
||||||
|
}
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CACEditCtrl::CACEditCtrl() : m_pDropDown(NULL), m_fnOldWordBreakProc(NULL)
|
static LRESULT CALLBACK
|
||||||
|
EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
|
||||||
|
UINT_PTR uSubclassID, DWORD_PTR dwData)
|
||||||
{
|
{
|
||||||
|
CAutoComplete *pThis = reinterpret_cast<CAutoComplete *>(dwData);
|
||||||
|
return pThis->EditWndProc(hwnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CACEditCtrl::HookWordBreakProc(BOOL bHook)
|
LRESULT CAutoComplete::EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (bHook)
|
LRESULT ret;
|
||||||
|
HWND hwndGotFocus;
|
||||||
|
switch (uMsg)
|
||||||
{
|
{
|
||||||
m_fnOldWordBreakProc = reinterpret_cast<EDITWORDBREAKPROCW>(
|
case WM_CHAR:
|
||||||
SendMessageW(EM_SETWORDBREAKPROC, 0,
|
return OnEditChar(wParam, lParam);
|
||||||
reinterpret_cast<LPARAM>(EditWordBreakProcW)));
|
case WM_CUT: case WM_PASTE: case WM_CLEAR:
|
||||||
}
|
ret = ::DefSubclassProc(hwnd, uMsg, wParam, lParam); // do default
|
||||||
else
|
OnEditUpdate(TRUE);
|
||||||
{
|
|
||||||
SendMessageW(EM_SETWORDBREAKPROC, 0,
|
|
||||||
reinterpret_cast<LPARAM>(m_fnOldWordBreakProc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WM_CHAR
|
|
||||||
// This message is posted to the window with the keyboard focus when WM_KEYDOWN is translated.
|
|
||||||
LRESULT CACEditCtrl::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnChar(%p, %p)\n", this, wParam);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
return m_pDropDown->OnEditChar(wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WM_CUT / WM_PASTE / WM_CLEAR @implemented
|
|
||||||
LRESULT CACEditCtrl::OnCutPasteClear(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnCutPasteClear(%p)\n", this);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
LRESULT ret = DefWindowProcW(uMsg, wParam, lParam); // do default
|
|
||||||
m_pDropDown->OnEditUpdate(TRUE);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
case WM_GETDLGCODE:
|
||||||
|
ret = ::DefSubclassProc(hwnd, uMsg, wParam, lParam); // do default
|
||||||
// WM_DESTROY
|
|
||||||
// This message is sent when a window is being destroyed.
|
|
||||||
LRESULT CACEditCtrl::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnDestroy(%p)\n", this);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
CAutoComplete *pDropDown = m_pDropDown;
|
|
||||||
|
|
||||||
// unhook word break procedure
|
|
||||||
HookWordBreakProc(FALSE);
|
|
||||||
|
|
||||||
// unsubclass because we don't watch any more
|
|
||||||
HWND hwndEdit = UnsubclassWindow();
|
|
||||||
|
|
||||||
// close the drop-down window
|
|
||||||
if (pDropDown)
|
|
||||||
{
|
|
||||||
pDropDown->PostMessageW(WM_CLOSE, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ::DefWindowProcW(hwndEdit, uMsg, wParam, lParam); // do default
|
|
||||||
}
|
|
||||||
|
|
||||||
// WM_GETDLGCODE
|
|
||||||
// By responding to this message, an application can take control of a particular type of
|
|
||||||
// input and process the input itself.
|
|
||||||
LRESULT CACEditCtrl::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnGetDlgCode(%p)\n", this);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
|
|
||||||
LRESULT ret = DefWindowProcW(uMsg, wParam, lParam); // get default
|
|
||||||
|
|
||||||
if (m_pDropDown)
|
|
||||||
{
|
|
||||||
// some special keys need default processing. we handle them here
|
// some special keys need default processing. we handle them here
|
||||||
switch (wParam)
|
switch (wParam)
|
||||||
{
|
{
|
||||||
case VK_RETURN:
|
case VK_RETURN:
|
||||||
if (m_pDropDown->IsWindowVisible() || ::GetKeyState(VK_CONTROL) < 0)
|
if (IsWindowVisible() || ::GetKeyState(VK_CONTROL) < 0)
|
||||||
m_pDropDown->OnEditKeyDown(VK_RETURN, 0);
|
OnEditKeyDown(VK_RETURN, 0);
|
||||||
break;
|
break;
|
||||||
case VK_TAB:
|
case VK_TAB:
|
||||||
if (m_pDropDown->IsWindowVisible() && m_pDropDown->UseTab())
|
if (IsWindowVisible() && UseTab())
|
||||||
ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
|
ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
|
||||||
break;
|
break;
|
||||||
case VK_ESCAPE:
|
case VK_ESCAPE:
|
||||||
if (m_pDropDown->IsWindowVisible())
|
if (IsWindowVisible())
|
||||||
ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
|
ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -332,61 +316,40 @@ LRESULT CACEditCtrl::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
case WM_KEYDOWN:
|
||||||
|
if (OnEditKeyDown(wParam, lParam))
|
||||||
// WM_KEYDOWN
|
return TRUE; // eat
|
||||||
// This message is posted to the window with the keyboard focus when a non-system key is pressed.
|
break;
|
||||||
LRESULT CACEditCtrl::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
case WM_SETFOCUS:
|
||||||
{
|
break;
|
||||||
TRACE("CACEditCtrl::OnKeyDown(%p, %p)\n", this, wParam);
|
case WM_KILLFOCUS:
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
if (m_pDropDown->OnEditKeyDown(wParam, lParam))
|
|
||||||
return 1; // eat
|
|
||||||
bHandled = FALSE; // do default
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WM_KILLFOCUS @implemented
|
|
||||||
// This message is sent to a window immediately before it loses the keyboard focus.
|
|
||||||
LRESULT CACEditCtrl::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnKillFocus(%p)\n", this);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
|
|
||||||
// hide the list if lost focus
|
// hide the list if lost focus
|
||||||
HWND hwndGotFocus = (HWND)wParam;
|
hwndGotFocus = (HWND)wParam;
|
||||||
if (hwndGotFocus != m_hWnd && hwndGotFocus != m_pDropDown->m_hWnd)
|
if (hwndGotFocus != m_hwndEdit && hwndGotFocus != m_hWnd)
|
||||||
|
HideDropDown();
|
||||||
|
break;
|
||||||
|
case WM_SETTEXT:
|
||||||
|
if (!m_bInSetText)
|
||||||
|
HideDropDown(); // it's mechanical WM_SETTEXT
|
||||||
|
break;
|
||||||
|
case WM_DESTROY:
|
||||||
{
|
{
|
||||||
m_pDropDown->HideDropDown();
|
if (m_fnOldWordBreakProc)
|
||||||
|
{
|
||||||
|
::SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, reinterpret_cast<LPARAM>(m_fnOldWordBreakProc));
|
||||||
|
m_fnOldWordBreakProc = NULL;
|
||||||
|
}
|
||||||
|
::RemoveWindowSubclass(hwnd, EditSubclassProc, 0);
|
||||||
|
if (::IsWindow(m_hWnd))
|
||||||
|
PostMessageW(WM_CLOSE, 0, 0);
|
||||||
|
// remove reference to m_hwndEdit
|
||||||
|
Release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bHandled = FALSE; // do default
|
return ::DefSubclassProc(hwnd, uMsg, wParam, lParam); // do default
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WM_SETFOCUS
|
|
||||||
// This message is sent to a window after it has gained the keyboard focus.
|
|
||||||
LRESULT CACEditCtrl::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnSetFocus(%p)\n", this);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
bHandled = FALSE; // do default
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WM_SETTEXT
|
|
||||||
// An application sends this message to set the text of a window.
|
|
||||||
LRESULT CACEditCtrl::OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
|
||||||
TRACE("CACEditCtrl::OnSetText(%p)\n", this);
|
|
||||||
ATLASSERT(m_pDropDown);
|
|
||||||
if (!m_pDropDown->m_bInSetText)
|
|
||||||
m_pDropDown->HideDropDown(); // it's mechanical WM_SETTEXT
|
|
||||||
bHandled = FALSE; // do default
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -503,7 +466,7 @@ LRESULT CACListView::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
|
||||||
if (iItem != -1)
|
if (iItem != -1)
|
||||||
{
|
{
|
||||||
m_pDropDown->SelectItem(iItem); // select the item
|
m_pDropDown->SelectItem(iItem); // select the item
|
||||||
CString strText = GetItemText(iItem); // get text of item
|
CStringW strText = GetItemText(iItem); // get text of item
|
||||||
m_pDropDown->SetEditText(strText); // set text
|
m_pDropDown->SetEditText(strText); // set text
|
||||||
m_pDropDown->SetEditSel(0, strText.GetLength()); // select all
|
m_pDropDown->SetEditSel(0, strText.GetLength()); // select all
|
||||||
m_pDropDown->HideDropDown(); // hide
|
m_pDropDown->HideDropDown(); // hide
|
||||||
|
@ -545,10 +508,6 @@ LRESULT CACListView::OnNCHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// CACScrollBar
|
// CACScrollBar
|
||||||
|
|
||||||
CACScrollBar::CACScrollBar() : m_pDropDown(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND CACScrollBar::Create(HWND hwndParent)
|
HWND CACScrollBar::Create(HWND hwndParent)
|
||||||
{
|
{
|
||||||
ATLASSERT(m_hWnd == NULL);
|
ATLASSERT(m_hWnd == NULL);
|
||||||
|
@ -563,10 +522,6 @@ HWND CACScrollBar::Create(HWND hwndParent)
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// CACSizeBox
|
// CACSizeBox
|
||||||
|
|
||||||
CACSizeBox::CACSizeBox() : m_pDropDown(NULL), m_bDowner(TRUE), m_bLongList(FALSE)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND CACSizeBox::Create(HWND hwndParent)
|
HWND CACSizeBox::Create(HWND hwndParent)
|
||||||
{
|
{
|
||||||
ATLASSERT(m_hWnd == NULL);
|
ATLASSERT(m_hWnd == NULL);
|
||||||
|
@ -684,6 +639,7 @@ CAutoComplete::CAutoComplete()
|
||||||
: m_bInSetText(FALSE), m_bInSelectItem(FALSE)
|
: m_bInSetText(FALSE), m_bInSelectItem(FALSE)
|
||||||
, m_bDowner(TRUE), m_dwOptions(ACO_AUTOAPPEND | ACO_AUTOSUGGEST)
|
, m_bDowner(TRUE), m_dwOptions(ACO_AUTOAPPEND | ACO_AUTOSUGGEST)
|
||||||
, m_bEnabled(TRUE), m_hwndCombo(NULL), m_hFont(NULL), m_bResized(FALSE)
|
, m_bEnabled(TRUE), m_hwndCombo(NULL), m_hFont(NULL), m_bResized(FALSE)
|
||||||
|
, m_hwndEdit(NULL), m_fnOldEditProc(NULL), m_fnOldWordBreakProc(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,7 +649,8 @@ HWND CAutoComplete::CreateDropDown()
|
||||||
DWORD dwStyle = WS_POPUP | /*WS_VISIBLE |*/ WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER;
|
DWORD dwStyle = WS_POPUP | /*WS_VISIBLE |*/ WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER;
|
||||||
DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY;
|
DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY;
|
||||||
Create(NULL, NULL, NULL, dwStyle, dwExStyle);
|
Create(NULL, NULL, NULL, dwStyle, dwExStyle);
|
||||||
TRACE("CAutoComplete::CreateDropDown(%p): m_hWnd == %p\n", this, m_hWnd);
|
TRACE("CAutoComplete::CreateDropDown(%p): m_hWnd=%p, m_hwndEdit=%p\n",
|
||||||
|
this, m_hWnd, m_hwndEdit);
|
||||||
return m_hWnd;
|
return m_hWnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,6 +662,9 @@ CAutoComplete::~CAutoComplete()
|
||||||
::DeleteObject(m_hFont);
|
::DeleteObject(m_hFont);
|
||||||
m_hFont = NULL;
|
m_hFont = NULL;
|
||||||
}
|
}
|
||||||
|
// quit holding them
|
||||||
|
m_pEnum.Release();
|
||||||
|
m_pACList.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CAutoComplete::CanAutoSuggest()
|
BOOL CAutoComplete::CanAutoSuggest()
|
||||||
|
@ -729,6 +689,11 @@ BOOL CAutoComplete::IsComboBoxDropped()
|
||||||
return (BOOL)::SendMessageW(m_hwndCombo, CB_GETDROPPEDSTATE, 0, 0);
|
return (BOOL)::SendMessageW(m_hwndCombo, CB_GETDROPPEDSTATE, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL CAutoComplete::FilterPrefixes()
|
||||||
|
{
|
||||||
|
return !!(m_dwOptions & ACO_FILTERPREFIXES) && m_bEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
INT CAutoComplete::GetItemCount()
|
INT CAutoComplete::GetItemCount()
|
||||||
{
|
{
|
||||||
return m_outerList.GetSize();
|
return m_outerList.GetSize();
|
||||||
|
@ -743,20 +708,16 @@ CStringW CAutoComplete::GetItemText(INT iItem)
|
||||||
|
|
||||||
CStringW CAutoComplete::GetEditText()
|
CStringW CAutoComplete::GetEditText()
|
||||||
{
|
{
|
||||||
BSTR bstrText = NULL;
|
WCHAR szText[L_MAX_URL_LENGTH];
|
||||||
CStringW strText;
|
if (::GetWindowTextW(m_hwndEdit, szText, _countof(szText)))
|
||||||
if (m_hwndEdit.GetWindowTextW(bstrText))
|
return szText;
|
||||||
{
|
return L"";
|
||||||
strText = bstrText;
|
|
||||||
::SysFreeString(bstrText);
|
|
||||||
}
|
|
||||||
return strText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CAutoComplete::SetEditText(LPCWSTR pszText)
|
VOID CAutoComplete::SetEditText(LPCWSTR pszText)
|
||||||
{
|
{
|
||||||
m_bInSetText = TRUE; // don't hide drop-down
|
m_bInSetText = TRUE; // don't hide drop-down
|
||||||
m_hwndEdit.SetWindowTextW(pszText);
|
::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(pszText));
|
||||||
m_bInSetText = FALSE;
|
m_bInSetText = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +732,7 @@ CStringW CAutoComplete::GetStemText()
|
||||||
|
|
||||||
VOID CAutoComplete::SetEditSel(INT ich0, INT ich1)
|
VOID CAutoComplete::SetEditSel(INT ich0, INT ich1)
|
||||||
{
|
{
|
||||||
m_hwndEdit.SendMessageW(EM_SETSEL, ich0, ich1);
|
::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, EM_SETSEL, ich0, ich1);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CAutoComplete::ShowDropDown()
|
VOID CAutoComplete::ShowDropDown()
|
||||||
|
@ -817,23 +778,52 @@ VOID CAutoComplete::DoAutoAppend()
|
||||||
|
|
||||||
// get the common string
|
// get the common string
|
||||||
CStringW strCommon;
|
CStringW strCommon;
|
||||||
|
BOOL bFound = FALSE;
|
||||||
for (INT iItem = 0; iItem < cItems; ++iItem)
|
for (INT iItem = 0; iItem < cItems; ++iItem)
|
||||||
{
|
{
|
||||||
const CString& strItem = m_innerList[iItem]; // get the text of the item
|
const CStringW& strItem = m_innerList[iItem]; // get the text of the item
|
||||||
|
|
||||||
if (iItem == 0) // the first item
|
CStringW strBody;
|
||||||
|
if (DropPrefix(strItem, strBody) &&
|
||||||
|
::StrCmpNIW(strBody, strText, strText.GetLength()) == 0)
|
||||||
{
|
{
|
||||||
strCommon = strItem; // store the text
|
if (!bFound)
|
||||||
|
{
|
||||||
|
bFound = TRUE;
|
||||||
|
strCommon = strBody;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (INT ich = 0; ich < strBody.GetLength(); ++ich)
|
||||||
|
{
|
||||||
|
if (strCommon.GetLength() <= ich)
|
||||||
|
break;
|
||||||
|
if (ChrCmpIW(strCommon[ich], strBody[ich]) != 0)
|
||||||
|
{
|
||||||
|
strCommon = strCommon.Left(ich);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (INT ich = 0; ich < strCommon.GetLength(); ++ich)
|
if (::StrCmpNIW(strItem, strText, strText.GetLength()) == 0)
|
||||||
{
|
{
|
||||||
if (ich < strItem.GetLength() &&
|
if (!bFound)
|
||||||
::ChrCmpIW(strCommon[ich], strItem[ich]) != 0)
|
|
||||||
{
|
{
|
||||||
strCommon = strCommon.Left(ich); // shrink the common string
|
bFound = TRUE;
|
||||||
|
strCommon = strItem;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (INT ich = 0; ich < strItem.GetLength(); ++ich)
|
||||||
|
{
|
||||||
|
if (strCommon.GetLength() <= ich)
|
||||||
break;
|
break;
|
||||||
|
if (ChrCmpIW(strCommon[ich], strItem[ich]) != 0)
|
||||||
|
{
|
||||||
|
strCommon = strCommon.Left(ich);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -842,13 +832,10 @@ VOID CAutoComplete::DoAutoAppend()
|
||||||
return; // no suggestion
|
return; // no suggestion
|
||||||
|
|
||||||
// append suggestion
|
// append suggestion
|
||||||
INT cchOld = strText.GetLength();
|
SetEditText(strCommon);
|
||||||
INT cchAppend = strCommon.GetLength() - cchOld;
|
|
||||||
strText += strCommon.Right(cchAppend);
|
|
||||||
SetEditText(strText);
|
|
||||||
|
|
||||||
// select the appended suggestion
|
// select the appended suggestion
|
||||||
SetEditSel(cchOld, strText.GetLength());
|
SetEditSel(strText.GetLength(), strCommon.GetLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
// go back a word ([Ctrl]+[Backspace])
|
// go back a word ([Ctrl]+[Backspace])
|
||||||
|
@ -856,8 +843,8 @@ VOID CAutoComplete::DoBackWord()
|
||||||
{
|
{
|
||||||
// get current selection
|
// get current selection
|
||||||
INT ich0, ich1;
|
INT ich0, ich1;
|
||||||
m_hwndEdit.SendMessageW(EM_GETSEL, reinterpret_cast<WPARAM>(&ich0),
|
::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, EM_GETSEL,
|
||||||
reinterpret_cast<LPARAM>(&ich1));
|
reinterpret_cast<WPARAM>(&ich0), reinterpret_cast<LPARAM>(&ich1));
|
||||||
if (ich0 <= 0 || ich0 != ich1) // there is selection or left-side end
|
if (ich0 <= 0 || ich0 != ich1) // there is selection or left-side end
|
||||||
return; // don't do anything
|
return; // don't do anything
|
||||||
// get text
|
// get text
|
||||||
|
@ -870,7 +857,7 @@ VOID CAutoComplete::DoBackWord()
|
||||||
// select range
|
// select range
|
||||||
SetEditSel(ich0, ich1);
|
SetEditSel(ich0, ich1);
|
||||||
// replace selection with empty text (this is actually deletion)
|
// replace selection with empty text (this is actually deletion)
|
||||||
m_hwndEdit.SendMessageW(EM_REPLACESEL, TRUE, (LPARAM)L"");
|
::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, EM_REPLACESEL, TRUE, (LPARAM)L"");
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CAutoComplete::UpdateScrollBar()
|
VOID CAutoComplete::UpdateScrollBar()
|
||||||
|
@ -940,7 +927,7 @@ BOOL CAutoComplete::OnEditKeyDown(WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// select all
|
// select all
|
||||||
INT cch = m_hwndEdit.GetWindowTextLengthW();
|
INT cch = ::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, WM_GETTEXTLENGTH, 0, 0);
|
||||||
SetEditSel(0, cch);
|
SetEditSel(0, cch);
|
||||||
// hide
|
// hide
|
||||||
HideDropDown();
|
HideDropDown();
|
||||||
|
@ -963,7 +950,7 @@ BOOL CAutoComplete::OnEditKeyDown(WPARAM wParam, LPARAM lParam)
|
||||||
// is suggestion available?
|
// is suggestion available?
|
||||||
if (!CanAutoSuggest())
|
if (!CanAutoSuggest())
|
||||||
return FALSE; // do default
|
return FALSE; // do default
|
||||||
m_hwndEdit.DefWindowProcW(WM_KEYDOWN, VK_DELETE, 0); // do default
|
::DefSubclassProc(m_hwndEdit, WM_KEYDOWN, VK_DELETE, 0); // do default
|
||||||
OnEditUpdate(FALSE);
|
OnEditUpdate(FALSE);
|
||||||
return TRUE; // eat
|
return TRUE; // eat
|
||||||
}
|
}
|
||||||
|
@ -976,10 +963,6 @@ BOOL CAutoComplete::OnEditKeyDown(WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return FALSE; // default
|
return FALSE; // default
|
||||||
}
|
}
|
||||||
|
@ -989,7 +972,7 @@ LRESULT CAutoComplete::OnEditChar(WPARAM wParam, LPARAM lParam)
|
||||||
TRACE("CACEditCtrl::OnEditChar(%p, %p)\n", this, wParam);
|
TRACE("CACEditCtrl::OnEditChar(%p, %p)\n", this, wParam);
|
||||||
if (wParam == L'\n' || wParam == L'\t')
|
if (wParam == L'\n' || wParam == L'\t')
|
||||||
return 0; // eat
|
return 0; // eat
|
||||||
LRESULT ret = m_hwndEdit.DefWindowProcW(WM_CHAR, wParam, lParam); // do default
|
LRESULT ret = ::DefSubclassProc(m_hwndEdit, WM_CHAR, wParam, lParam); // do default
|
||||||
if (CanAutoSuggest() || CanAutoAppend())
|
if (CanAutoSuggest() || CanAutoAppend())
|
||||||
OnEditUpdate(wParam != VK_BACK);
|
OnEditUpdate(wParam != VK_BACK);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -997,7 +980,7 @@ LRESULT CAutoComplete::OnEditChar(WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
VOID CAutoComplete::OnEditUpdate(BOOL bAppendOK)
|
VOID CAutoComplete::OnEditUpdate(BOOL bAppendOK)
|
||||||
{
|
{
|
||||||
CString strText = GetEditText();
|
CStringW strText = GetEditText();
|
||||||
if (m_strText.CompareNoCase(strText) == 0)
|
if (m_strText.CompareNoCase(strText) == 0)
|
||||||
{
|
{
|
||||||
// no change
|
// no change
|
||||||
|
@ -1105,7 +1088,7 @@ BOOL CAutoComplete::OnListUpDown(UINT vk)
|
||||||
// @implemented
|
// @implemented
|
||||||
STDMETHODIMP CAutoComplete::Enable(BOOL fEnable)
|
STDMETHODIMP CAutoComplete::Enable(BOOL fEnable)
|
||||||
{
|
{
|
||||||
TRACE("(%p)->(%d)\n", this, fEnable);
|
TRACE("(%p)->Enable(%d)\n", this, fEnable);
|
||||||
m_bEnabled = fEnable;
|
m_bEnabled = fEnable;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -1114,37 +1097,42 @@ STDMETHODIMP
|
||||||
CAutoComplete::Init(HWND hwndEdit, IUnknown *punkACL,
|
CAutoComplete::Init(HWND hwndEdit, IUnknown *punkACL,
|
||||||
LPCOLESTR pwszRegKeyPath, LPCOLESTR pwszQuickComplete)
|
LPCOLESTR pwszRegKeyPath, LPCOLESTR pwszQuickComplete)
|
||||||
{
|
{
|
||||||
TRACE("(%p)->(0x%08lx, %p, %s, %s)\n",
|
TRACE("(%p)->Init(0x%08lx, %p, %s, %s)\n",
|
||||||
this, hwndEdit, punkACL, debugstr_w(pwszRegKeyPath), debugstr_w(pwszQuickComplete));
|
this, hwndEdit, punkACL, debugstr_w(pwszRegKeyPath), debugstr_w(pwszQuickComplete));
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (m_hwndEdit || !punkACL)
|
if (m_hwndEdit || !punkACL)
|
||||||
{
|
|
||||||
ATLASSERT(0);
|
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
if (!hwndEdit)
|
||||||
|
return E_INVALIDARG;
|
||||||
// set this pointer to m_hwndEdit
|
|
||||||
m_hwndEdit.m_pDropDown = this;
|
|
||||||
|
|
||||||
// do subclass textbox to watch messages
|
// do subclass textbox to watch messages
|
||||||
m_hwndEdit.SubclassWindow(hwndEdit);
|
m_fnOldEditProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwndEdit, GWLP_WNDPROC));
|
||||||
|
if (!m_fnOldEditProc)
|
||||||
|
return E_FAIL;
|
||||||
|
if (!::SetWindowSubclass(hwndEdit, EditSubclassProc, 0, reinterpret_cast<DWORD_PTR>(this)))
|
||||||
|
return E_FAIL;
|
||||||
|
m_hwndEdit = hwndEdit;
|
||||||
|
// add reference to m_hwndEdit
|
||||||
|
AddRef();
|
||||||
// set word break procedure
|
// set word break procedure
|
||||||
m_hwndEdit.HookWordBreakProc(TRUE);
|
m_fnOldWordBreakProc = reinterpret_cast<EDITWORDBREAKPROCW>(
|
||||||
|
::SendMessageW(m_hwndEdit, EM_SETWORDBREAKPROC, 0,
|
||||||
|
reinterpret_cast<LPARAM>(EditWordBreakProcW)));
|
||||||
// save position
|
// save position
|
||||||
m_hwndEdit.GetWindowRect(&m_rcEdit);
|
::GetWindowRect(m_hwndEdit, &m_rcEdit);
|
||||||
|
|
||||||
// get an IEnumString
|
// get an IEnumString
|
||||||
ATLASSERT(!m_pEnum);
|
ATLASSERT(!m_pEnum);
|
||||||
punkACL->QueryInterface(IID_IEnumString, (VOID **)&m_pEnum);
|
punkACL->QueryInterface(IID_IEnumString, (VOID **)&m_pEnum);
|
||||||
TRACE("m_pEnum: %p\n", static_cast<void *>(m_pEnum));
|
TRACE("m_pEnum: %p\n", static_cast<void *>(m_pEnum));
|
||||||
|
if (m_pEnum)
|
||||||
|
m_pEnum->AddRef(); // hold not to be freed
|
||||||
|
|
||||||
// get an IACList
|
// get an IACList
|
||||||
ATLASSERT(!m_pACList);
|
ATLASSERT(!m_pACList);
|
||||||
punkACL->QueryInterface(IID_IACList, (VOID **)&m_pACList);
|
punkACL->QueryInterface(IID_IACList, (VOID **)&m_pACList);
|
||||||
TRACE("m_pACList: %p\n", static_cast<void *>(m_pACList));
|
TRACE("m_pACList: %p\n", static_cast<void *>(m_pACList));
|
||||||
|
if (m_pACList)
|
||||||
AddRef(); // add reference
|
m_pACList->AddRef(); // hold not to be freed
|
||||||
|
|
||||||
UpdateDropDownState(); // create/hide the drop-down window if necessary
|
UpdateDropDownState(); // create/hide the drop-down window if necessary
|
||||||
|
|
||||||
|
@ -1238,13 +1226,8 @@ STDMETHODIMP CAutoComplete::ResetEnumerator()
|
||||||
{
|
{
|
||||||
FIXME("(%p): stub\n", this);
|
FIXME("(%p): stub\n", this);
|
||||||
|
|
||||||
HideDropDown();
|
Reset();
|
||||||
|
m_innerList.RemoveAll();
|
||||||
if (IsWindowVisible())
|
|
||||||
{
|
|
||||||
OnEditUpdate(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1305,11 +1288,7 @@ VOID CAutoComplete::UpdateDropDownState()
|
||||||
{
|
{
|
||||||
// create the drop-down window if not existed
|
// create the drop-down window if not existed
|
||||||
if (!m_hWnd)
|
if (!m_hWnd)
|
||||||
{
|
CreateDropDown();
|
||||||
AddRef();
|
|
||||||
if (!CreateDropDown())
|
|
||||||
Release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1424,7 +1403,7 @@ VOID CAutoComplete::RepositionDropDown()
|
||||||
|
|
||||||
// get m_hwndEdit position
|
// get m_hwndEdit position
|
||||||
RECT rcEdit;
|
RECT rcEdit;
|
||||||
m_hwndEdit.GetWindowRect(&rcEdit);
|
::GetWindowRect(m_hwndEdit, &rcEdit);
|
||||||
INT x = rcEdit.left, y = rcEdit.bottom;
|
INT x = rcEdit.left, y = rcEdit.bottom;
|
||||||
|
|
||||||
// get list extent
|
// get list extent
|
||||||
|
@ -1572,6 +1551,15 @@ INT CAutoComplete::UpdateOuterList()
|
||||||
{
|
{
|
||||||
// is the beginning matched?
|
// is the beginning matched?
|
||||||
const CStringW& strTarget = m_innerList[iItem];
|
const CStringW& strTarget = m_innerList[iItem];
|
||||||
|
CStringW strBody;
|
||||||
|
if (DropPrefix(strTarget, strBody))
|
||||||
|
{
|
||||||
|
if (::StrCmpNIW(strBody, strText, strText.GetLength()) == 0)
|
||||||
|
{
|
||||||
|
m_outerList.Add(strTarget);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (::StrCmpNIW(strTarget, strText, strText.GetLength()) == 0)
|
if (::StrCmpNIW(strTarget, strText, strText.GetLength()) == 0)
|
||||||
{
|
{
|
||||||
m_outerList.Add(strTarget);
|
m_outerList.Add(strTarget);
|
||||||
|
@ -1614,13 +1602,11 @@ VOID CAutoComplete::UpdateCompletion(BOOL bAppendOK)
|
||||||
RepositionDropDown();
|
RepositionDropDown();
|
||||||
else
|
else
|
||||||
HideDropDown();
|
HideDropDown();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanAutoAppend() && bAppendOK) // can we auto-append?
|
if (CanAutoAppend() && bAppendOK) // can we auto-append?
|
||||||
{
|
{
|
||||||
DoAutoAppend();
|
DoAutoAppend();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1659,28 +1645,21 @@ LRESULT CAutoComplete::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
|
||||||
m_hFont = reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
|
m_hFont = reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
|
||||||
m_hwndList.SetFont(m_hFont);
|
m_hwndList.SetFont(m_hFont);
|
||||||
|
|
||||||
|
// add reference to CAutoComplete::m_hWnd
|
||||||
|
AddRef();
|
||||||
return 0; // success
|
return 0; // success
|
||||||
}
|
}
|
||||||
|
|
||||||
// WM_DESTROY
|
// WM_NCDESTROY
|
||||||
// This message is sent when a window is being destroyed.
|
LRESULT CAutoComplete::OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||||
LRESULT CAutoComplete::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
||||||
{
|
{
|
||||||
TRACE("CAutoComplete::OnDestroy(%p)\n", this);
|
TRACE("CAutoComplete::OnNCDestroy(%p)\n", this);
|
||||||
|
|
||||||
// hide
|
// hide
|
||||||
if (IsWindowVisible())
|
if (IsWindowVisible())
|
||||||
HideDropDown();
|
HideDropDown();
|
||||||
|
|
||||||
// unsubclass EDIT control
|
|
||||||
if (m_hwndEdit)
|
|
||||||
{
|
|
||||||
m_hwndEdit.HookWordBreakProc(FALSE);
|
|
||||||
m_hwndEdit.UnsubclassWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear CAutoComplete pointers
|
// clear CAutoComplete pointers
|
||||||
m_hwndEdit.m_pDropDown = NULL;
|
|
||||||
m_hwndList.m_pDropDown = NULL;
|
m_hwndList.m_pDropDown = NULL;
|
||||||
m_hwndScrollBar.m_pDropDown = NULL;
|
m_hwndScrollBar.m_pDropDown = NULL;
|
||||||
m_hwndSizeBox.m_pDropDown = NULL;
|
m_hwndSizeBox.m_pDropDown = NULL;
|
||||||
|
@ -1692,8 +1671,8 @@ LRESULT CAutoComplete::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
m_hwndCombo = NULL;
|
m_hwndCombo = NULL;
|
||||||
|
// remove reference to CAutoComplete::m_hWnd
|
||||||
Release();
|
Release();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1709,7 +1688,7 @@ LRESULT CAutoComplete::OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, B
|
||||||
UINT uSWP_ = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
|
UINT uSWP_ = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
|
||||||
SetWindowPos(NULL, 0, 0, 0, 0, uSWP_);
|
SetWindowPos(NULL, 0, 0, 0, 0, uSWP_);
|
||||||
|
|
||||||
m_hwndEdit.SetFocus(); // restore focus
|
::SetFocus(m_hwndEdit); // restore focus
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1943,8 +1922,6 @@ LRESULT CAutoComplete::OnNCHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
|
||||||
// This message is sent when the window size is changed.
|
// This message is sent when the window size is changed.
|
||||||
LRESULT CAutoComplete::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
LRESULT CAutoComplete::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||||
{
|
{
|
||||||
TRACE("CAutoComplete::OnSize(%p)\n", this);
|
|
||||||
|
|
||||||
// calculate the positions of the controls
|
// calculate the positions of the controls
|
||||||
CRect rcList, rcScrollBar, rcSizeBox;
|
CRect rcList, rcScrollBar, rcSizeBox;
|
||||||
CalcRects(m_bDowner, rcList, rcScrollBar, rcSizeBox);
|
CalcRects(m_bDowner, rcList, rcScrollBar, rcSizeBox);
|
||||||
|
@ -1974,6 +1951,8 @@ LRESULT CAutoComplete::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOO
|
||||||
BOOL bShow = (BOOL)wParam;
|
BOOL bShow = (BOOL)wParam;
|
||||||
if (bShow)
|
if (bShow)
|
||||||
{
|
{
|
||||||
|
if (s_hWatchWnd != m_hWnd && ::IsWindowVisible(s_hWatchWnd))
|
||||||
|
::ShowWindowAsync(s_hWatchWnd, SW_HIDE);
|
||||||
s_hWatchWnd = m_hWnd; // watch this
|
s_hWatchWnd = m_hWnd; // watch this
|
||||||
|
|
||||||
// unhook mouse if any
|
// unhook mouse if any
|
||||||
|
@ -2034,7 +2013,7 @@ LRESULT CAutoComplete::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bH
|
||||||
|
|
||||||
// m_hwndEdit is moved?
|
// m_hwndEdit is moved?
|
||||||
RECT rcEdit;
|
RECT rcEdit;
|
||||||
m_hwndEdit.GetWindowRect(&rcEdit);
|
::GetWindowRect(m_hwndEdit, &rcEdit);
|
||||||
if (!::EqualRect(&rcEdit, &m_rcEdit))
|
if (!::EqualRect(&rcEdit, &m_rcEdit))
|
||||||
{
|
{
|
||||||
// if so, hide
|
// if so, hide
|
||||||
|
|
|
@ -24,53 +24,11 @@
|
||||||
#include "atltypes.h"
|
#include "atltypes.h"
|
||||||
#include "rosctrls.h"
|
#include "rosctrls.h"
|
||||||
|
|
||||||
class CACEditCtrl;
|
|
||||||
class CACListView;
|
class CACListView;
|
||||||
class CACScrollBar;
|
class CACScrollBar;
|
||||||
class CACSizeBox;
|
class CACSizeBox;
|
||||||
class CAutoComplete;
|
class CAutoComplete;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
// CACEditCtrl --- auto-completion textbox
|
|
||||||
|
|
||||||
class CACEditCtrl
|
|
||||||
: public CWindowImpl<CACEditCtrl, CWindow, CControlWinTraits>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CAutoComplete* m_pDropDown;
|
|
||||||
static LPCWSTR GetWndClassName() { return WC_EDITW; }
|
|
||||||
|
|
||||||
CACEditCtrl();
|
|
||||||
VOID HookWordBreakProc(BOOL bHook);
|
|
||||||
|
|
||||||
// message map
|
|
||||||
BEGIN_MSG_MAP(CACEditCtrl)
|
|
||||||
MESSAGE_HANDLER(WM_CHAR, OnChar)
|
|
||||||
MESSAGE_HANDLER(WM_CLEAR, OnCutPasteClear)
|
|
||||||
MESSAGE_HANDLER(WM_CUT, OnCutPasteClear)
|
|
||||||
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
|
|
||||||
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
|
|
||||||
MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
|
|
||||||
MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
|
|
||||||
MESSAGE_HANDLER(WM_PASTE, OnCutPasteClear)
|
|
||||||
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
|
|
||||||
MESSAGE_HANDLER(WM_SETTEXT, OnSetText)
|
|
||||||
END_MSG_MAP()
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// protected variables
|
|
||||||
EDITWORDBREAKPROCW m_fnOldWordBreakProc;
|
|
||||||
// message handlers
|
|
||||||
LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnCutPasteClear(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
LRESULT OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
|
||||||
};
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// CACListView --- auto-completion list control
|
// CACListView --- auto-completion list control
|
||||||
|
|
||||||
|
@ -121,8 +79,7 @@ class CACScrollBar : public CWindowImpl<CACScrollBar>
|
||||||
public:
|
public:
|
||||||
CAutoComplete* m_pDropDown;
|
CAutoComplete* m_pDropDown;
|
||||||
static LPCWSTR GetWndClassName() { return WC_SCROLLBARW; }
|
static LPCWSTR GetWndClassName() { return WC_SCROLLBARW; }
|
||||||
|
CACScrollBar() : m_pDropDown(NULL) { }
|
||||||
CACScrollBar();
|
|
||||||
HWND Create(HWND hwndParent);
|
HWND Create(HWND hwndParent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -139,8 +96,7 @@ class CACSizeBox : public CWindowImpl<CACSizeBox>
|
||||||
public:
|
public:
|
||||||
CAutoComplete* m_pDropDown;
|
CAutoComplete* m_pDropDown;
|
||||||
static LPCWSTR GetWndClassName() { return WC_SCROLLBARW; }
|
static LPCWSTR GetWndClassName() { return WC_SCROLLBARW; }
|
||||||
|
CACSizeBox() : m_pDropDown(NULL), m_bDowner(TRUE), m_bLongList(FALSE) { }
|
||||||
CACSizeBox();
|
|
||||||
HWND Create(HWND hwndParent);
|
HWND Create(HWND hwndParent);
|
||||||
VOID SetStatus(BOOL bDowner, BOOL bLongList);
|
VOID SetStatus(BOOL bDowner, BOOL bLongList);
|
||||||
|
|
||||||
|
@ -188,6 +144,7 @@ public:
|
||||||
BOOL CanAutoAppend();
|
BOOL CanAutoAppend();
|
||||||
BOOL UseTab();
|
BOOL UseTab();
|
||||||
BOOL IsComboBoxDropped();
|
BOOL IsComboBoxDropped();
|
||||||
|
BOOL FilterPrefixes();
|
||||||
INT GetItemCount();
|
INT GetItemCount();
|
||||||
CStringW GetItemText(INT iItem);
|
CStringW GetItemText(INT iItem);
|
||||||
|
|
||||||
|
@ -203,6 +160,7 @@ public:
|
||||||
VOID DoBackWord();
|
VOID DoBackWord();
|
||||||
VOID UpdateScrollBar();
|
VOID UpdateScrollBar();
|
||||||
|
|
||||||
|
LRESULT EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
LRESULT OnEditChar(WPARAM wParam, LPARAM lParam);
|
LRESULT OnEditChar(WPARAM wParam, LPARAM lParam);
|
||||||
BOOL OnEditKeyDown(WPARAM wParam, LPARAM lParam);
|
BOOL OnEditKeyDown(WPARAM wParam, LPARAM lParam);
|
||||||
VOID OnEditUpdate(BOOL bAppendOK);
|
VOID OnEditUpdate(BOOL bAppendOK);
|
||||||
|
@ -234,11 +192,13 @@ protected:
|
||||||
HFONT m_hFont; // the font
|
HFONT m_hFont; // the font
|
||||||
BOOL m_bResized; // re-sized by size-box?
|
BOOL m_bResized; // re-sized by size-box?
|
||||||
RECT m_rcEdit; // in screen coordinates, to watch the position
|
RECT m_rcEdit; // in screen coordinates, to watch the position
|
||||||
|
HWND m_hwndEdit; // the textbox
|
||||||
|
WNDPROC m_fnOldEditProc; // old textbox procedure
|
||||||
|
EDITWORDBREAKPROCW m_fnOldWordBreakProc;
|
||||||
// The following variables are non-POD:
|
// The following variables are non-POD:
|
||||||
CStringW m_strText; // internal text (used in selecting item and reverting text)
|
CStringW m_strText; // internal text (used in selecting item and reverting text)
|
||||||
CStringW m_strStemText; // dirname + '\\'
|
CStringW m_strStemText; // dirname + '\\'
|
||||||
CStringW m_strQuickComplete; // used for [Ctrl]+[Enter]
|
CStringW m_strQuickComplete; // used for [Ctrl]+[Enter]
|
||||||
CACEditCtrl m_hwndEdit; // subclassed to watch
|
|
||||||
CACListView m_hwndList; // this listview is virtual
|
CACListView m_hwndList; // this listview is virtual
|
||||||
CACScrollBar m_hwndScrollBar; // scroll bar contol
|
CACScrollBar m_hwndScrollBar; // scroll bar contol
|
||||||
CACSizeBox m_hwndSizeBox; // the size grip
|
CACSizeBox m_hwndSizeBox; // the size grip
|
||||||
|
@ -259,7 +219,7 @@ protected:
|
||||||
// message map
|
// message map
|
||||||
BEGIN_MSG_MAP(CAutoComplete)
|
BEGIN_MSG_MAP(CAutoComplete)
|
||||||
MESSAGE_HANDLER(WM_CREATE, OnCreate)
|
MESSAGE_HANDLER(WM_CREATE, OnCreate)
|
||||||
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
|
MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy)
|
||||||
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
|
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
|
||||||
MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
|
MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
|
||||||
MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
|
MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
|
||||||
|
@ -276,7 +236,7 @@ protected:
|
||||||
END_MSG_MAP()
|
END_MSG_MAP()
|
||||||
// message handlers
|
// message handlers
|
||||||
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||||
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
LRESULT OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||||
LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||||
LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||||
LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||||
|
|
Loading…
Reference in a new issue