2025-11-28 00:35:46 +09:00

1438 lines
36 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#include "Private.h"
#include "Globals.h"
#include "BaseWindow.h"
#include "CandidateWindow.h"
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CCandidateWindow::CCandidateWindow(_In_ CANDWNDCALLBACK pfnCallback, _In_ void *pv, _In_ CCandidateRange *pIndexRange, _In_ BOOL isStoreAppMode)
{
_currentSelection = 0;
_SetTextColor(CANDWND_ITEM_COLOR, GetSysColor(COLOR_WINDOW)); // text color is black
_SetFillColor((HBRUSH)(COLOR_WINDOW+1));
_pIndexRange = pIndexRange;
_pfnCallback = pfnCallback;
_pObj = pv;
_pShadowWnd = nullptr;
_cyRow = CANDWND_ROW_WIDTH;
_cxTitle = 0;
_pVScrollBarWnd = nullptr;
_wndWidth = 0;
_dontAdjustOnEmptyItemPage = FALSE;
_isStoreAppMode = isStoreAppMode;
}
//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------
CCandidateWindow::~CCandidateWindow()
{
_ClearList();
_DeleteShadowWnd();
_DeleteVScrollBarWnd();
}
//+---------------------------------------------------------------------------
//
// _Create
//
// CandidateWinow is the top window
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_Create(ATOM atom, _In_ UINT wndWidth, _In_opt_ HWND parentWndHandle)
{
BOOL ret = FALSE;
_wndWidth = wndWidth;
ret = _CreateMainWindow(atom, parentWndHandle);
if (FALSE == ret)
{
goto Exit;
}
ret = _CreateBackGroundShadowWindow();
if (FALSE == ret)
{
goto Exit;
}
ret = _CreateVScrollWindow();
if (FALSE == ret)
{
goto Exit;
}
_ResizeWindow();
Exit:
return TRUE;
}
BOOL CCandidateWindow::_CreateMainWindow(ATOM atom, _In_opt_ HWND parentWndHandle)
{
_SetUIWnd(this);
if (!CBaseWindow::_Create(atom,
WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
WS_BORDER | WS_POPUP,
NULL, 0, 0, parentWndHandle))
{
return FALSE;
}
return TRUE;
}
BOOL CCandidateWindow::_CreateBackGroundShadowWindow()
{
_pShadowWnd = new (std::nothrow) CShadowWindow(this);
if (_pShadowWnd == nullptr)
{
return FALSE;
}
if (!_pShadowWnd->_Create(Global::AtomShadowWindow,
WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED,
WS_DISABLED | WS_POPUP, this))
{
_DeleteShadowWnd();
return FALSE;
}
return TRUE;
}
BOOL CCandidateWindow::_CreateVScrollWindow()
{
BOOL ret = FALSE;
SHELL_MODE shellMode = _isStoreAppMode ? STOREAPP : DESKTOP;
CScrollBarWindowFactory* pFactory = CScrollBarWindowFactory::Instance();
_pVScrollBarWnd = pFactory->MakeScrollBarWindow(shellMode);
if (_pVScrollBarWnd == nullptr)
{
_DeleteShadowWnd();
goto Exit;
}
_pVScrollBarWnd->_SetUIWnd(this);
if (!_pVScrollBarWnd->_Create(Global::AtomScrollBarWindow, WS_EX_TOPMOST | WS_EX_TOOLWINDOW, WS_CHILD, this))
{
_DeleteVScrollBarWnd();
_DeleteShadowWnd();
goto Exit;
}
ret = TRUE;
Exit:
pFactory->Release();
return ret;
}
void CCandidateWindow::_ResizeWindow()
{
SIZE size = {0, 0};
_cxTitle = max(_cxTitle, size.cx + 2 * GetSystemMetrics(SM_CXFRAME));
int candidateListPageCnt = _pIndexRange->Count();
CBaseWindow::_Resize(0, 0, _cxTitle, _cyRow * candidateListPageCnt);
RECT rcCandRect = {0, 0, 0, 0};
_GetClientRect(&rcCandRect);
int letf = rcCandRect.right - GetSystemMetrics(SM_CXVSCROLL) * 2 - CANDWND_BORDER_WIDTH;
int top = rcCandRect.top + CANDWND_BORDER_WIDTH;
int width = GetSystemMetrics(SM_CXVSCROLL) * 2;
int height = rcCandRect.bottom - rcCandRect.top - CANDWND_BORDER_WIDTH * 2;
_pVScrollBarWnd->_Resize(letf, top, width, height);
}
//+---------------------------------------------------------------------------
//
// _Move
//
//----------------------------------------------------------------------------
void CCandidateWindow::_Move(int x, int y)
{
CBaseWindow::_Move(x, y);
}
//+---------------------------------------------------------------------------
//
// _Show
//
//----------------------------------------------------------------------------
void CCandidateWindow::_Show(BOOL isShowWnd)
{
if (_pShadowWnd)
{
_pShadowWnd->_Show(isShowWnd);
}
CBaseWindow::_Show(isShowWnd);
}
//+---------------------------------------------------------------------------
//
// _SetTextColor
// _SetFillColor
//
//----------------------------------------------------------------------------
VOID CCandidateWindow::_SetTextColor(_In_ COLORREF crColor, _In_ COLORREF crBkColor)
{
_crTextColor = _AdjustTextColor(crColor, crBkColor);
_crBkColor = crBkColor;
}
VOID CCandidateWindow::_SetFillColor(_In_ HBRUSH hBrush)
{
_brshBkColor = hBrush;
}
//+---------------------------------------------------------------------------
//
// _WindowProcCallback
//
// Cand window proc.
//----------------------------------------------------------------------------
const int PageCountPosition = 1;
const int StringPosition = 4;
LRESULT CALLBACK CCandidateWindow::_WindowProcCallback(_In_ HWND wndHandle, UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
HDC dcHandle = nullptr;
dcHandle = GetDC(wndHandle);
if (dcHandle)
{
HFONT hFontOld = (HFONT)SelectObject(dcHandle, Global::defaultlFontHandle);
GetTextMetrics(dcHandle, &_TextMetric);
_cxTitle = _TextMetric.tmMaxCharWidth * _wndWidth;
SelectObject(dcHandle, hFontOld);
ReleaseDC(wndHandle, dcHandle);
}
}
return 0;
case WM_DESTROY:
_DeleteShadowWnd();
return 0;
case WM_WINDOWPOSCHANGED:
{
WINDOWPOS* pWndPos = (WINDOWPOS*)lParam;
// move shadow
if (_pShadowWnd)
{
_pShadowWnd->_OnOwnerWndMoved((pWndPos->flags & SWP_NOSIZE) == 0);
}
// move v-scroll
if (_pVScrollBarWnd)
{
_pVScrollBarWnd->_OnOwnerWndMoved((pWndPos->flags & SWP_NOSIZE) == 0);
}
_FireMessageToLightDismiss(wndHandle, pWndPos);
}
break;
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pWndPos = (WINDOWPOS*)lParam;
// show/hide shadow
if (_pShadowWnd)
{
if ((pWndPos->flags & SWP_HIDEWINDOW) != 0)
{
_pShadowWnd->_Show(FALSE);
}
// don't go behaind of shadow
if (((pWndPos->flags & SWP_NOZORDER) == 0) && (pWndPos->hwndInsertAfter == _pShadowWnd->_GetWnd()))
{
pWndPos->flags |= SWP_NOZORDER;
}
_pShadowWnd->_OnOwnerWndMoved((pWndPos->flags & SWP_NOSIZE) == 0);
}
// show/hide v-scroll
if (_pVScrollBarWnd)
{
if ((pWndPos->flags & SWP_HIDEWINDOW) != 0)
{
_pVScrollBarWnd->_Show(FALSE);
}
_pVScrollBarWnd->_OnOwnerWndMoved((pWndPos->flags & SWP_NOSIZE) == 0);
}
}
break;
case WM_SHOWWINDOW:
// show/hide shadow
if (_pShadowWnd)
{
_pShadowWnd->_Show((BOOL)wParam);
}
// show/hide v-scroll
if (_pVScrollBarWnd)
{
_pVScrollBarWnd->_Show((BOOL)wParam);
}
break;
case WM_PAINT:
{
HDC dcHandle = nullptr;
PAINTSTRUCT ps;
dcHandle = BeginPaint(wndHandle, &ps);
_OnPaint(dcHandle, &ps);
_DrawBorder(wndHandle, CANDWND_BORDER_WIDTH*2);
EndPaint(wndHandle, &ps);
}
return 0;
case WM_SETCURSOR:
{
POINT cursorPoint;
GetCursorPos(&cursorPoint);
MapWindowPoints(NULL, wndHandle, &cursorPoint, 1);
// handle mouse message
_HandleMouseMsg(HIWORD(lParam), cursorPoint);
}
return 1;
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
{
POINT point;
POINTSTOPOINT(point, MAKEPOINTS(lParam));
// handle mouse message
_HandleMouseMsg(uMsg, point);
}
// we processes this message, it should return zero.
return 0;
case WM_MOUSEACTIVATE:
{
WORD mouseEvent = HIWORD(lParam);
if (mouseEvent == WM_LBUTTONDOWN ||
mouseEvent == WM_RBUTTONDOWN ||
mouseEvent == WM_MBUTTONDOWN)
{
return MA_NOACTIVATE;
}
}
break;
case WM_POINTERACTIVATE:
return PA_NOACTIVATE;
case WM_VSCROLL:
_OnVScroll(LOWORD(wParam), HIWORD(wParam));
return 0;
}
return DefWindowProc(wndHandle, uMsg, wParam, lParam);
}
//+---------------------------------------------------------------------------
//
// _HandleMouseMsg
//
//----------------------------------------------------------------------------
void CCandidateWindow::_HandleMouseMsg(_In_ UINT mouseMsg, _In_ POINT point)
{
switch (mouseMsg)
{
case WM_MOUSEMOVE:
_OnMouseMove(point);
break;
case WM_LBUTTONDOWN:
_OnLButtonDown(point);
break;
case WM_LBUTTONUP:
_OnLButtonUp(point);
break;
}
}
//+---------------------------------------------------------------------------
//
// _OnPaint
//
//----------------------------------------------------------------------------
void CCandidateWindow::_OnPaint(_In_ HDC dcHandle, _In_ PAINTSTRUCT *pPaintStruct)
{
SetBkMode(dcHandle, TRANSPARENT);
HFONT hFontOld = (HFONT)SelectObject(dcHandle, Global::defaultlFontHandle);
FillRect(dcHandle, &pPaintStruct->rcPaint, _brshBkColor);
UINT currentPageIndex = 0;
UINT currentPage = 0;
if (FAILED(_GetCurrentPage(&currentPage)))
{
goto cleanup;
}
_AdjustPageIndex(currentPage, currentPageIndex);
_DrawList(dcHandle, currentPageIndex, &pPaintStruct->rcPaint);
cleanup:
SelectObject(dcHandle, hFontOld);
}
//+---------------------------------------------------------------------------
//
// _OnLButtonDown
//
//----------------------------------------------------------------------------
void CCandidateWindow::_OnLButtonDown(POINT pt)
{
RECT rcWindow = {0, 0, 0, 0};;
_GetClientRect(&rcWindow);
int cyLine = _cyRow;
UINT candidateListPageCnt = _pIndexRange->Count();
UINT index = 0;
int currentPage = 0;
if (FAILED(_GetCurrentPage(&currentPage)))
{
return;
}
// Hit test on list items
index = *_PageIndex.GetAt(currentPage);
for (UINT pageCount = 0; (index < _candidateList.Count()) && (pageCount < candidateListPageCnt); index++, pageCount++)
{
RECT rc = {0, 0, 0, 0};
rc.left = rcWindow.left;
rc.right = rcWindow.right - GetSystemMetrics(SM_CXVSCROLL) * 2;
rc.top = rcWindow.top + (pageCount * cyLine);
rc.bottom = rcWindow.top + ((pageCount + 1) * cyLine);
if (PtInRect(&rc, pt) && _pfnCallback)
{
SetCursor(LoadCursor(NULL, IDC_HAND));
_currentSelection = index;
_pfnCallback(_pObj, CAND_ITEM_SELECT);
return;
}
}
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (_pVScrollBarWnd)
{
RECT rc = {0, 0, 0, 0};
_pVScrollBarWnd->_GetClientRect(&rc);
MapWindowPoints(_GetWnd(), _pVScrollBarWnd->_GetWnd(), &pt, 1);
if (PtInRect(&rc, pt))
{
_pVScrollBarWnd->_OnLButtonDown(pt);
}
}
}
//+---------------------------------------------------------------------------
//
// _OnLButtonUp
//
//----------------------------------------------------------------------------
void CCandidateWindow::_OnLButtonUp(POINT pt)
{
if (nullptr == _pVScrollBarWnd)
{
return;
}
RECT rc = {0, 0, 0, 0};
_pVScrollBarWnd->_GetClientRect(&rc);
MapWindowPoints(_GetWnd(), _pVScrollBarWnd->_GetWnd(), &pt, 1);
if (_IsCapture())
{
_pVScrollBarWnd->_OnLButtonUp(pt);
}
else if (PtInRect(&rc, pt))
{
_pVScrollBarWnd->_OnLButtonUp(pt);
}
}
//+---------------------------------------------------------------------------
//
// _OnMouseMove
//
//----------------------------------------------------------------------------
void CCandidateWindow::_OnMouseMove(POINT pt)
{
RECT rcWindow = {0, 0, 0, 0};
_GetClientRect(&rcWindow);
RECT rc = {0, 0, 0, 0};
rc.left = rcWindow.left;
rc.right = rcWindow.right - GetSystemMetrics(SM_CXVSCROLL) * 2;
rc.top = rcWindow.top;
rc.bottom = rcWindow.bottom;
if (PtInRect(&rc, pt))
{
SetCursor(LoadCursor(NULL, IDC_HAND));
return;
}
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (_pVScrollBarWnd)
{
_pVScrollBarWnd->_GetClientRect(&rc);
MapWindowPoints(_GetWnd(), _pVScrollBarWnd->_GetWnd(), &pt, 1);
if (PtInRect(&rc, pt))
{
_pVScrollBarWnd->_OnMouseMove(pt);
}
}
}
//+---------------------------------------------------------------------------
//
// _OnVScroll
//
//----------------------------------------------------------------------------
void CCandidateWindow::_OnVScroll(DWORD dwSB, _In_ DWORD nPos)
{
switch (dwSB)
{
case SB_LINEDOWN:
_SetSelectionOffset(+1);
_InvalidateRect();
break;
case SB_LINEUP:
_SetSelectionOffset(-1);
_InvalidateRect();
break;
case SB_PAGEDOWN:
_MovePage(+1, FALSE);
_InvalidateRect();
break;
case SB_PAGEUP:
_MovePage(-1, FALSE);
_InvalidateRect();
break;
case SB_THUMBPOSITION:
_SetSelection(nPos, FALSE);
_InvalidateRect();
break;
}
}
//+---------------------------------------------------------------------------
//
// _DrawList
//
//----------------------------------------------------------------------------
void CCandidateWindow::_DrawList(_In_ HDC dcHandle, _In_ UINT iIndex, _In_ RECT *prc)
{
int pageCount = 0;
int candidateListPageCnt = _pIndexRange->Count();
int cxLine = _TextMetric.tmAveCharWidth;
int cyLine = max(_cyRow, _TextMetric.tmHeight);
int cyOffset = (cyLine == _cyRow ? (cyLine-_TextMetric.tmHeight)/2 : 0);
RECT rc;
const size_t lenOfPageCount = 16;
for (;
(iIndex < _candidateList.Count()) && (pageCount < candidateListPageCnt);
iIndex++, pageCount++)
{
WCHAR pageCountString[lenOfPageCount] = {'\0'};
CCandidateListItem* pItemList = nullptr;
rc.top = prc->top + pageCount * cyLine;
rc.bottom = rc.top + cyLine;
rc.left = prc->left + PageCountPosition * cxLine;
rc.right = prc->left + StringPosition * cxLine;
// Number Font Color And BK
SetTextColor(dcHandle, CANDWND_NUM_COLOR);
SetBkColor(dcHandle, GetSysColor(COLOR_3DHIGHLIGHT));
StringCchPrintf(pageCountString, ARRAYSIZE(pageCountString), L"%d", (LONG)*_pIndexRange->GetAt(pageCount));
ExtTextOut(dcHandle, PageCountPosition * cxLine, pageCount * cyLine + cyOffset, ETO_OPAQUE, &rc, pageCountString, lenOfPageCount, NULL);
rc.left = prc->left + StringPosition * cxLine;
rc.right = prc->right;
// Candidate Font Color And BK
if (_currentSelection != iIndex)
{
SetTextColor(dcHandle, _crTextColor);
SetBkColor(dcHandle, GetSysColor(COLOR_3DHIGHLIGHT));
}
else
{
SetTextColor(dcHandle, CANDWND_SELECTED_ITEM_COLOR);
SetBkColor(dcHandle, CANDWND_SELECTED_BK_COLOR);
}
pItemList = _candidateList.GetAt(iIndex);
ExtTextOut(dcHandle, StringPosition * cxLine, pageCount * cyLine + cyOffset, ETO_OPAQUE, &rc, pItemList->_ItemString.Get(), (DWORD)pItemList->_ItemString.GetLength(), NULL);
}
for (; (pageCount < candidateListPageCnt); pageCount++)
{
rc.top = prc->top + pageCount * cyLine;
rc.bottom = rc.top + cyLine;
rc.left = prc->left + PageCountPosition * cxLine;
rc.right = prc->left + StringPosition * cxLine;
FillRect(dcHandle, &rc, (HBRUSH)(COLOR_3DHIGHLIGHT+1));
}
}
//+---------------------------------------------------------------------------
//
// _DrawBorder
//
//----------------------------------------------------------------------------
void CCandidateWindow::_DrawBorder(_In_ HWND wndHandle, _In_ int cx)
{
RECT rcWnd;
HDC dcHandle = GetWindowDC(wndHandle);
GetWindowRect(wndHandle, &rcWnd);
// zero based
OffsetRect(&rcWnd, -rcWnd.left, -rcWnd.top);
HPEN hPen = CreatePen(PS_DOT, cx, CANDWND_BORDER_COLOR);
HPEN hPenOld = (HPEN)SelectObject(dcHandle, hPen);
HBRUSH hBorderBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
HBRUSH hBorderBrushOld = (HBRUSH)SelectObject(dcHandle, hBorderBrush);
Rectangle(dcHandle, rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom);
SelectObject(dcHandle, hPenOld);
SelectObject(dcHandle, hBorderBrushOld);
DeleteObject(hPen);
DeleteObject(hBorderBrush);
ReleaseDC(wndHandle, dcHandle);
}
//+---------------------------------------------------------------------------
//
// _AddString
//
//----------------------------------------------------------------------------
void CCandidateWindow::_AddString(_Inout_ CCandidateListItem *pCandidateItem, _In_ BOOL isAddFindKeyCode)
{
DWORD_PTR dwItemString = pCandidateItem->_ItemString.GetLength();
const WCHAR* pwchString = nullptr;
if (dwItemString)
{
pwchString = new (std::nothrow) WCHAR[ dwItemString ];
if (!pwchString)
{
return;
}
memcpy((void*)pwchString, pCandidateItem->_ItemString.Get(), dwItemString * sizeof(WCHAR));
}
DWORD_PTR itemWildcard = pCandidateItem->_FindKeyCode.GetLength();
const WCHAR* pwchWildcard = nullptr;
if (itemWildcard && isAddFindKeyCode)
{
pwchWildcard = new (std::nothrow) WCHAR[ itemWildcard ];
if (!pwchWildcard)
{
if (pwchString)
{
delete [] pwchString;
}
return;
}
memcpy((void*)pwchWildcard, pCandidateItem->_FindKeyCode.Get(), itemWildcard * sizeof(WCHAR));
}
CCandidateListItem* pLI = nullptr;
pLI = _candidateList.Append();
if (!pLI)
{
if (pwchString)
{
delete [] pwchString;
pwchString = nullptr;
}
if (pwchWildcard)
{
delete [] pwchWildcard;
pwchWildcard = nullptr;
}
return;
}
if (pwchString)
{
pLI->_ItemString.Set(pwchString, dwItemString);
}
if (pwchWildcard)
{
pLI->_FindKeyCode.Set(pwchWildcard, itemWildcard);
}
return;
}
//+---------------------------------------------------------------------------
//
// _ClearList
//
//----------------------------------------------------------------------------
void CCandidateWindow::_ClearList()
{
for (UINT index = 0; index < _candidateList.Count(); index++)
{
CCandidateListItem* pItemList = nullptr;
pItemList = _candidateList.GetAt(index);
delete [] pItemList->_ItemString.Get();
delete [] pItemList->_FindKeyCode.Get();
}
_currentSelection = 0;
_candidateList.Clear();
_PageIndex.Clear();
}
//+---------------------------------------------------------------------------
//
// _SetScrollInfo
//
//----------------------------------------------------------------------------
void CCandidateWindow::_SetScrollInfo(_In_ int nMax, _In_ int nPage)
{
CScrollInfo si;
si.nMax = nMax;
si.nPage = nPage;
si.nPos = 0;
if (_pVScrollBarWnd)
{
_pVScrollBarWnd->_SetScrollInfo(&si);
}
}
//+---------------------------------------------------------------------------
//
// _GetCandidateString
//
//----------------------------------------------------------------------------
DWORD CCandidateWindow::_GetCandidateString(_In_ int iIndex, _Outptr_result_maybenull_z_ const WCHAR **ppwchCandidateString)
{
CCandidateListItem* pItemList = nullptr;
if (iIndex < 0 )
{
*ppwchCandidateString = nullptr;
return 0;
}
UINT index = static_cast<UINT>(iIndex);
if (index >= _candidateList.Count())
{
*ppwchCandidateString = nullptr;
return 0;
}
pItemList = _candidateList.GetAt(iIndex);
if (ppwchCandidateString)
{
*ppwchCandidateString = pItemList->_ItemString.Get();
}
return (DWORD)pItemList->_ItemString.GetLength();
}
//+---------------------------------------------------------------------------
//
// _GetSelectedCandidateString
//
//----------------------------------------------------------------------------
DWORD CCandidateWindow::_GetSelectedCandidateString(_Outptr_result_maybenull_ const WCHAR **ppwchCandidateString)
{
CCandidateListItem* pItemList = nullptr;
if (_currentSelection >= _candidateList.Count())
{
*ppwchCandidateString = nullptr;
return 0;
}
pItemList = _candidateList.GetAt(_currentSelection);
if (ppwchCandidateString)
{
*ppwchCandidateString = pItemList->_ItemString.Get();
}
return (DWORD)pItemList->_ItemString.GetLength();
}
//+---------------------------------------------------------------------------
//
// _SetSelectionInPage
//
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_SetSelectionInPage(int nPos)
{
if (nPos < 0)
{
return FALSE;
}
UINT pos = static_cast<UINT>(nPos);
if (pos >= _candidateList.Count())
{
return FALSE;
}
int currentPage = 0;
if (FAILED(_GetCurrentPage(&currentPage)))
{
return FALSE;
}
_currentSelection = *_PageIndex.GetAt(currentPage) + nPos;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// _MoveSelection
//
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_MoveSelection(_In_ int offSet, _In_ BOOL isNotify)
{
if (_currentSelection + offSet >= _candidateList.Count())
{
return FALSE;
}
_currentSelection += offSet;
_dontAdjustOnEmptyItemPage = TRUE;
if (_pVScrollBarWnd && isNotify)
{
_pVScrollBarWnd->_ShiftLine(offSet, isNotify);
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// _SetSelection
//
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_SetSelection(_In_ int selectedIndex, _In_ BOOL isNotify)
{
if (selectedIndex == -1)
{
selectedIndex = _candidateList.Count() - 1;
}
if (selectedIndex < 0)
{
return FALSE;
}
int candCnt = static_cast<int>(_candidateList.Count());
if (selectedIndex >= candCnt)
{
return FALSE;
}
_currentSelection = static_cast<UINT>(selectedIndex);
BOOL ret = _AdjustPageIndexForSelection();
if (_pVScrollBarWnd && isNotify)
{
_pVScrollBarWnd->_ShiftPosition(selectedIndex, isNotify);
}
return ret;
}
//+---------------------------------------------------------------------------
//
// _SetSelection
//
//----------------------------------------------------------------------------
void CCandidateWindow::_SetSelection(_In_ int nIndex)
{
_currentSelection = nIndex;
}
//+---------------------------------------------------------------------------
//
// _MovePage
//
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_MovePage(_In_ int offSet, _In_ BOOL isNotify)
{
if (offSet == 0)
{
return TRUE;
}
int currentPage = 0;
int selectionOffset = 0;
int newPage = 0;
if (FAILED(_GetCurrentPage(&currentPage)))
{
return FALSE;
}
newPage = currentPage + offSet;
if ((newPage < 0) || (newPage >= static_cast<int>(_PageIndex.Count())))
{
return FALSE;
}
// If current selection is at the top of the page AND
// we are on the "default" page border, then we don't
// want adjustment to eliminate empty entries.
//
// We do this for keeping behavior inline with downlevel.
if (_currentSelection % _pIndexRange->Count() == 0 &&
_currentSelection == *_PageIndex.GetAt(currentPage))
{
_dontAdjustOnEmptyItemPage = TRUE;
}
selectionOffset = _currentSelection - *_PageIndex.GetAt(currentPage);
_currentSelection = *_PageIndex.GetAt(newPage) + selectionOffset;
_currentSelection = _candidateList.Count() > _currentSelection ? _currentSelection : _candidateList.Count() - 1;
// adjust scrollbar position
if (_pVScrollBarWnd && isNotify)
{
_pVScrollBarWnd->_ShiftPage(offSet, isNotify);
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// _SetSelectionOffset
//
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_SetSelectionOffset(_In_ int offSet)
{
if (_currentSelection + offSet >= _candidateList.Count())
{
return FALSE;
}
BOOL fCurrentPageHasEmptyItems = FALSE;
BOOL fAdjustPageIndex = TRUE;
_CurrentPageHasEmptyItems(&fCurrentPageHasEmptyItems);
int newOffset = _currentSelection + offSet;
// For SB_LINEUP and SB_LINEDOWN, we need to special case if CurrentPageHasEmptyItems.
// CurrentPageHasEmptyItems if we are on the last page.
if ((offSet == 1 || offSet == -1) &&
fCurrentPageHasEmptyItems && _PageIndex.Count() > 1)
{
int iPageIndex = *_PageIndex.GetAt(_PageIndex.Count() - 1);
// Moving on the last page and last page has empty items.
if (newOffset >= iPageIndex)
{
fAdjustPageIndex = FALSE;
}
// Moving across page border.
else if (newOffset < iPageIndex)
{
fAdjustPageIndex = TRUE;
}
_dontAdjustOnEmptyItemPage = TRUE;
}
_currentSelection = newOffset;
if (fAdjustPageIndex)
{
return _AdjustPageIndexForSelection();
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// _GetPageIndex
//
//----------------------------------------------------------------------------
HRESULT CCandidateWindow::_GetPageIndex(UINT *pIndex, _In_ UINT uSize, _Inout_ UINT *puPageCnt)
{
HRESULT hr = S_OK;
if (uSize > _PageIndex.Count())
{
uSize = _PageIndex.Count();
}
else
{
hr = S_FALSE;
}
if (pIndex)
{
for (UINT i = 0; i < uSize; i++)
{
*pIndex = *_PageIndex.GetAt(i);
pIndex++;
}
}
*puPageCnt = _PageIndex.Count();
return hr;
}
//+---------------------------------------------------------------------------
//
// _SetPageIndex
//
//----------------------------------------------------------------------------
HRESULT CCandidateWindow::_SetPageIndex(UINT *pIndex, _In_ UINT uPageCnt)
{
uPageCnt;
_PageIndex.Clear();
for (UINT i = 0; i < uPageCnt; i++)
{
UINT *pLastNewPageIndex = _PageIndex.Append();
if (pLastNewPageIndex != nullptr)
{
*pLastNewPageIndex = *pIndex;
pIndex++;
}
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// _GetCurrentPage
//
//----------------------------------------------------------------------------
HRESULT CCandidateWindow::_GetCurrentPage(_Inout_ UINT *pCurrentPage)
{
HRESULT hr = S_OK;
if (pCurrentPage == nullptr)
{
hr = E_INVALIDARG;
goto Exit;
}
*pCurrentPage = 0;
if (_PageIndex.Count() == 0)
{
hr = E_UNEXPECTED;
goto Exit;
}
if (_PageIndex.Count() == 1)
{
*pCurrentPage = 0;
goto Exit;
}
UINT i = 0;
for (i = 1; i < _PageIndex.Count(); i++)
{
UINT uPageIndex = *_PageIndex.GetAt(i);
if (uPageIndex > _currentSelection)
{
break;
}
}
*pCurrentPage = i - 1;
Exit:
return hr;
}
//+---------------------------------------------------------------------------
//
// _GetCurrentPage
//
//----------------------------------------------------------------------------
HRESULT CCandidateWindow::_GetCurrentPage(_Inout_ int *pCurrentPage)
{
HRESULT hr = E_FAIL;
UINT needCastCurrentPage = 0;
if (nullptr == pCurrentPage)
{
goto Exit;
}
*pCurrentPage = 0;
hr = _GetCurrentPage(&needCastCurrentPage);
if (FAILED(hr))
{
goto Exit;
}
hr = UIntToInt(needCastCurrentPage, pCurrentPage);
if (FAILED(hr))
{
goto Exit;
}
Exit:
return hr;
}
//+---------------------------------------------------------------------------
//
// _AdjustPageIndexForSelection
//
//----------------------------------------------------------------------------
BOOL CCandidateWindow::_AdjustPageIndexForSelection()
{
UINT candidateListPageCnt = _pIndexRange->Count();
UINT* pNewPageIndex = nullptr;
UINT newPageCnt = 0;
if (_candidateList.Count() < candidateListPageCnt)
{
// no needed to restruct page index
return TRUE;
}
// B is number of pages before the current page
// A is number of pages after the current page
// uNewPageCount is A + B + 1;
// A is (uItemsAfter - 1) / candidateListPageCnt + 1 ->
// (_CandidateListCount - _currentSelection - CandidateListPageCount - 1) / candidateListPageCnt + 1->
// (_CandidateListCount - _currentSelection - 1) / candidateListPageCnt
// B is (uItemsBefore - 1) / candidateListPageCnt + 1 ->
// (_currentSelection - 1) / candidateListPageCnt + 1
// A + B is (_CandidateListCount - 2) / candidateListPageCnt + 1
BOOL isBefore = _currentSelection;
BOOL isAfter = _candidateList.Count() > _currentSelection + candidateListPageCnt;
// only have current page
if (!isBefore && !isAfter)
{
newPageCnt = 1;
}
// only have after pages; just count the total number of pages
else if (!isBefore && isAfter)
{
newPageCnt = (_candidateList.Count() - 1) / candidateListPageCnt + 1;
}
// we are at the last page
else if (isBefore && !isAfter)
{
newPageCnt = 2 + (_currentSelection - 1) / candidateListPageCnt;
}
else if (isBefore && isAfter)
{
newPageCnt = (_candidateList.Count() - 2) / candidateListPageCnt + 2;
}
pNewPageIndex = new (std::nothrow) UINT[ newPageCnt ];
if (pNewPageIndex == nullptr)
{
return FALSE;
}
pNewPageIndex[0] = 0;
UINT firstPage = _currentSelection % candidateListPageCnt;
if (firstPage && newPageCnt > 1)
{
pNewPageIndex[1] = firstPage;
}
for (UINT i = firstPage ? 2 : 1; i < newPageCnt; ++i)
{
pNewPageIndex[i] = pNewPageIndex[i - 1] + candidateListPageCnt;
}
_SetPageIndex(pNewPageIndex, newPageCnt);
delete [] pNewPageIndex;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// _AdjustTextColor
//
//----------------------------------------------------------------------------
COLORREF _AdjustTextColor(_In_ COLORREF crColor, _In_ COLORREF crBkColor)
{
if (!Global::IsTooSimilar(crColor, crBkColor))
{
return crColor;
}
else
{
return crColor ^ RGB(255, 255, 255);
}
}
//+---------------------------------------------------------------------------
//
// _CurrentPageHasEmptyItems
//
//----------------------------------------------------------------------------
HRESULT CCandidateWindow::_CurrentPageHasEmptyItems(_Inout_ BOOL *hasEmptyItems)
{
int candidateListPageCnt = _pIndexRange->Count();
UINT currentPage = 0;
if (FAILED(_GetCurrentPage(&currentPage)))
{
return S_FALSE;
}
if ((currentPage == 0 || currentPage == _PageIndex.Count()-1) &&
(_PageIndex.Count() > 0) &&
(*_PageIndex.GetAt(currentPage) > (UINT)(_candidateList.Count() - candidateListPageCnt)))
{
*hasEmptyItems = TRUE;
}
else
{
*hasEmptyItems = FALSE;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// _FireMessageToLightDismiss
// fire EVENT_OBJECT_IME_xxx to let LightDismiss know about IME window.
//----------------------------------------------------------------------------
void CCandidateWindow::_FireMessageToLightDismiss(_In_ HWND wndHandle, _In_ WINDOWPOS *pWndPos)
{
if (nullptr == pWndPos)
{
return;
}
BOOL isShowWnd = ((pWndPos->flags & SWP_SHOWWINDOW) != 0);
BOOL isHide = ((pWndPos->flags & SWP_HIDEWINDOW) != 0);
BOOL needResize = ((pWndPos->flags & SWP_NOSIZE) == 0);
BOOL needMove = ((pWndPos->flags & SWP_NOMOVE) == 0);
BOOL needRedraw = ((pWndPos->flags & SWP_NOREDRAW) == 0);
if (isShowWnd)
{
NotifyWinEvent(EVENT_OBJECT_IME_SHOW, wndHandle, OBJID_CLIENT, CHILDID_SELF);
}
else if (isHide)
{
NotifyWinEvent(EVENT_OBJECT_IME_HIDE, wndHandle, OBJID_CLIENT, CHILDID_SELF);
}
else if (needResize || needMove || needRedraw)
{
if (IsWindowVisible(wndHandle))
{
NotifyWinEvent(EVENT_OBJECT_IME_CHANGE, wndHandle, OBJID_CLIENT, CHILDID_SELF);
}
}
}
HRESULT CCandidateWindow::_AdjustPageIndex(_Inout_ UINT & currentPage, _Inout_ UINT & currentPageIndex)
{
HRESULT hr = E_FAIL;
UINT candidateListPageCnt = _pIndexRange->Count();
currentPageIndex = *_PageIndex.GetAt(currentPage);
BOOL hasEmptyItems = FALSE;
if (FAILED(_CurrentPageHasEmptyItems(&hasEmptyItems)))
{
goto Exit;
}
if (FALSE == hasEmptyItems)
{
goto Exit;
}
if (TRUE == _dontAdjustOnEmptyItemPage)
{
goto Exit;
}
UINT tempSelection = _currentSelection;
// Last page
UINT candNum = _candidateList.Count();
UINT pageNum = _PageIndex.Count();
if ((currentPageIndex > candNum - candidateListPageCnt) && (pageNum > 0) && (currentPage == (pageNum - 1)))
{
_currentSelection = candNum - candidateListPageCnt;
_AdjustPageIndexForSelection();
_currentSelection = tempSelection;
if (FAILED(_GetCurrentPage(&currentPage)))
{
goto Exit;
}
currentPageIndex = *_PageIndex.GetAt(currentPage);
}
// First page
else if ((currentPageIndex < candidateListPageCnt) && (currentPage == 0))
{
_currentSelection = 0;
_AdjustPageIndexForSelection();
_currentSelection = tempSelection;
}
_dontAdjustOnEmptyItemPage = FALSE;
hr = S_OK;
Exit:
return hr;
}
void CCandidateWindow::_DeleteShadowWnd()
{
if (nullptr != _pShadowWnd)
{
delete _pShadowWnd;
_pShadowWnd = nullptr;
}
}
void CCandidateWindow::_DeleteVScrollBarWnd()
{
if (nullptr != _pVScrollBarWnd)
{
delete _pVScrollBarWnd;
_pVScrollBarWnd = nullptr;
}
}