You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3259 lines
94 KiB
3259 lines
94 KiB
/*++
|
|
|
|
Copyright (c) 2001, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
uicomp.cpp
|
|
|
|
Abstract:
|
|
|
|
This file implements the UIComposition Class.
|
|
|
|
Author:
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "private.h"
|
|
#include "resource.h"
|
|
#include "cicspres.h"
|
|
#include "uicomp.h"
|
|
#include "globals.h"
|
|
#include "ctxtcomp.h"
|
|
#include "cic.h"
|
|
#include "profile.h"
|
|
#include "cregkey.h"
|
|
#include "cresstr.h"
|
|
#include "delay.h"
|
|
#include "fontlink.h"
|
|
|
|
const TCHAR c_szCUASDefCompKey[] = TEXT("SOFTWARE\\Microsoft\\CTF\\CUAS\\DefaultCompositionWindow");
|
|
const TCHAR c_szLeft[] = TEXT("Left");
|
|
const TCHAR c_szTop[] = TEXT("Top");
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsEALang
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL IsEALang()
|
|
{
|
|
TLS* ptls = TLS::GetTLS();
|
|
if (ptls)
|
|
{
|
|
CicProfile* pProfile;
|
|
if (pProfile = ptls->GetCicProfile())
|
|
{
|
|
LANGID langid;
|
|
pProfile->GetLangId(&langid);
|
|
switch(PRIMARYLANGID(langid))
|
|
{
|
|
case LANG_JAPANESE:
|
|
case LANG_KOREAN:
|
|
case LANG_CHINESE:
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Internal_PolyTextOutW
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
Internal_PolyTextOutW(
|
|
HDC hDC,
|
|
CONST POLYTEXTW* pptxt,
|
|
int cStrings)
|
|
{
|
|
for (int i=0; i < cStrings; i++)
|
|
{
|
|
if (! FLExtTextOutW(hDC,
|
|
pptxt[i].x, pptxt[i].y,
|
|
pptxt[i].uiFlags,
|
|
&pptxt[i].rcl,
|
|
pptxt[i].lpstr, pptxt[i].n, pptxt[i].pdx))
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CDefCompFrameGripper
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameGripper::ctor
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CDefCompFrameGripper::CDefCompFrameGripper(CDefCompFrameWindow *pDefCompFrameWindow, RECT *prc, DWORD dwStyle) : CUIFGripper( pDefCompFrameWindow, prc, dwStyle)
|
|
{
|
|
m_pDefCompFrameWnd = pDefCompFrameWindow;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCompFinalizeButton
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompFinalizeButton::ctor
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CCompFinalizeButton::CCompFinalizeButton(CCompFrameWindow *pCompFrameWindow, DWORD dwID, RECT *prc, DWORD dwStyle, DWORD dwSBtnStyle, DWORD dwSBtnShowType) : CUIFToolbarButton(pCompFrameWindow, dwID, prc, dwStyle, dwSBtnStyle, dwSBtnShowType)
|
|
{
|
|
m_pCompFrameWnd = pCompFrameWindow;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompFinalizeButton::dtor
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CCompFinalizeButton::~CCompFinalizeButton()
|
|
{
|
|
HICON hIcon = GetIcon();
|
|
if (hIcon)
|
|
{
|
|
DestroyIcon(hIcon);
|
|
SetIcon(NULL);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompFinalizeButton::OnLeftClick
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CCompFinalizeButton::OnLeftClick()
|
|
{
|
|
Assert(m_pCompFrameWnd);
|
|
|
|
//
|
|
// complete string at lbutton click.
|
|
//
|
|
if (m_pCompFrameWnd->GetIMC())
|
|
ImmNotifyIME(m_pCompFrameWnd->GetIMC(),
|
|
NI_COMPOSITIONSTR,
|
|
CPS_COMPLETE,
|
|
0);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CDefCompFrameWindow
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameWindow::CDefCompFrameWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CDefCompFrameWindow::CDefCompFrameWindow(HIMC hIMC, DWORD dwStyle) : CCompFrameWindow(hIMC, dwStyle)
|
|
{
|
|
|
|
//
|
|
// get the current position from registry
|
|
//
|
|
LoadPosition();
|
|
|
|
//
|
|
// Set theme
|
|
//
|
|
SetActiveTheme(L"TASKBAR", TBP_BACKGROUNDBOTTOM, TS_NORMAL );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameWindow::~CDefCompFrameWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CDefCompFrameWindow::~CDefCompFrameWindow()
|
|
{
|
|
|
|
//
|
|
// save the current position to registry
|
|
//
|
|
SavePosition();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameWindow::OnSetCursor
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CDefCompFrameWindow::OnSetCursor( UINT uMsg, POINT pt )
|
|
{
|
|
//
|
|
// SendMessage(WM_UICOMP_SETCURSOR) will set the cursor if pt is in
|
|
// the comp str window.
|
|
//
|
|
|
|
if (IsWindow(m_hwndCompStr))
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(m_hwndCompStr, &rc);
|
|
MyScreenToClient(NULL, &rc);
|
|
if (PtInRect(&rc, pt))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameWindow::HandleMouseMsg
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CDefCompFrameWindow::HandleMouseMsg( UINT uMsg, POINT pt )
|
|
{
|
|
if (IsWindow(m_hwndCompStr))
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(m_hwndCompStr, &rc);
|
|
MyScreenToClient(NULL, &rc);
|
|
if (PtInRect(&rc, pt))
|
|
SendMessage(m_hwndCompStr, WM_UICOMP_SETCURSOR, 0, 0);
|
|
}
|
|
|
|
CUIFWindow::HandleMouseMsg(uMsg, pt );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameWindow::Init
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CDefCompFrameWindow::Init()
|
|
{
|
|
if (!m_pGripper)
|
|
{
|
|
RECT rc;
|
|
::SetRect(&rc, 0, 0, 0, 0);
|
|
m_pGripper = new CDefCompFrameGripper(this, &rc, 0);
|
|
|
|
m_pGripper->Initialize();
|
|
|
|
AddUIObj(m_pGripper);
|
|
}
|
|
|
|
if (!m_pEnterButton)
|
|
{
|
|
RECT rc;
|
|
::SetRect(&rc, 0, 0, 0, 0);
|
|
m_pEnterButton = new CCompFinalizeButton(this,
|
|
0,
|
|
&rc,
|
|
0,
|
|
UITBBUTTON_BUTTON,
|
|
0);
|
|
|
|
m_pEnterButton->Initialize();
|
|
m_pEnterButton->Init();
|
|
m_pEnterButton->SetIcon(LoadSmIcon(::GetInstance(),
|
|
MAKEINTRESOURCE(IDIC_ENTER_ICON)));
|
|
m_pEnterButton->SetToolTip(CRStr2(IDS_ENTER_BTN_TOOLTIP));
|
|
|
|
AddUIObj(m_pEnterButton);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnCreate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CDefCompFrameWindow::OnCreate(HWND hWnd)
|
|
{
|
|
//
|
|
// Set Window Theme.
|
|
//
|
|
SetWindowTheme(hWnd, L"TASKBAR", NULL);
|
|
|
|
//
|
|
// Get margins of button theme.
|
|
//
|
|
CUIFTheme themeBtn;
|
|
memset(&_marginsButton, 0, sizeof(_marginsButton));
|
|
|
|
themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);
|
|
if (SUCCEEDED(themeBtn.OpenThemeData(hWnd)))
|
|
{
|
|
themeBtn.GetThemeMargins(NULL, TS_NORMAL,
|
|
TMT_CONTENTMARGINS,
|
|
NULL, &_marginsButton);
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnWindowPosChanged
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LRESULT CDefCompFrameWindow::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
IMCLock imc(GetIMC());
|
|
if (SUCCEEDED(imc.GetResult()))
|
|
{
|
|
SendMessage(imc->hWnd,
|
|
WM_IME_NOTIFY,
|
|
IMN_PRIVATE_ONLAYOUTCHANGE,
|
|
(LPARAM)GetIMC());
|
|
}
|
|
return CUIFWindow::OnWindowPosChanged(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CDefCompFrameWindow::SetCompStrRect
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CDefCompFrameWindow::SetCompStrRect(int dx, int dy, BOOL fShow)
|
|
{
|
|
int x, y;
|
|
int nGripperWidth = GetGripperWidth();
|
|
RECT rcWnd;
|
|
|
|
GetWindowRect(GetWnd(), &rcWnd);
|
|
Move(rcWnd.left, rcWnd.top, dx + (DEFFRAME_LEFT_MARGIN * 3) + nGripperWidth + DEFFRAME_ENTER_BTN_CX, dy + DEFFRAME_TOP_MARGIN + DEFFRAME_BOTTOM_MARGIN);
|
|
|
|
if (m_pGripper)
|
|
{
|
|
RECT rc;
|
|
x = DEFFRAME_LEFT_MARGIN;
|
|
y = DEFFRAME_TOP_MARGIN;
|
|
::SetRect(&rc,
|
|
x,
|
|
y,
|
|
x + nGripperWidth,
|
|
DEFFRAME_TOP_STR_MARGIN + dy);
|
|
m_pGripper->SetRect(&rc);
|
|
}
|
|
|
|
if (m_pEnterButton)
|
|
{
|
|
RECT rc;
|
|
x = DEFFRAME_LEFT_MARGIN + nGripperWidth + dx + DEFFRAME_LEFT_MARGIN;
|
|
y = DEFFRAME_TOP_MARGIN;
|
|
::SetRect(&rc,
|
|
x,
|
|
y,
|
|
x + DEFFRAME_ENTER_BTN_CX + _marginsButton.cxLeftWidth + _marginsButton.cxRightWidth,
|
|
y + DEFFRAME_ENTER_BTN_CY + _marginsButton.cyTopHeight + _marginsButton.cyBottomHeight);
|
|
m_pEnterButton->SetRect(&rc);
|
|
}
|
|
|
|
Show(fShow);
|
|
|
|
|
|
x = DEFFRAME_LEFT_MARGIN + nGripperWidth;
|
|
y = DEFFRAME_TOP_STR_MARGIN;
|
|
::MoveWindow(m_hwndCompStr, x, y, dx, dy, TRUE);
|
|
::ShowWindow(m_hwndCompStr, fShow ? SW_SHOWNOACTIVATE : SW_HIDE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetGripperWidth
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int CDefCompFrameWindow::GetGripperWidth()
|
|
{
|
|
if (m_pGripper)
|
|
{
|
|
if (SUCCEEDED(m_pGripper->EnsureThemeData(GetWnd())))
|
|
{
|
|
int nRet = -1;
|
|
|
|
SIZE size;
|
|
HDC hdc = GetDC(GetWnd());
|
|
if (SUCCEEDED(m_pGripper->GetThemePartSize(hdc,
|
|
TS_NORMAL,
|
|
NULL,
|
|
TS_TRUE,
|
|
&size)))
|
|
{
|
|
nRet = size.cx + CUI_GRIPPER_THEME_MARGIN * 2;
|
|
}
|
|
|
|
ReleaseDC(GetWnd(), hdc);
|
|
|
|
if (nRet >= 0)
|
|
return nRet;
|
|
}
|
|
}
|
|
|
|
return 5;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SavePosition
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CDefCompFrameWindow::SavePosition()
|
|
{
|
|
CMyRegKey key;
|
|
|
|
if (key.Create(HKEY_CURRENT_USER, c_szCUASDefCompKey) == S_OK)
|
|
{
|
|
key.SetValue((DWORD)_xWnd, c_szLeft);
|
|
key.SetValue((DWORD)_yWnd, c_szTop);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// LoadPosition
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CDefCompFrameWindow::LoadPosition()
|
|
{
|
|
CMyRegKey key;
|
|
int x, y;
|
|
|
|
x = 0;
|
|
y = 0;
|
|
if (key.Open(HKEY_CURRENT_USER, c_szCUASDefCompKey, KEY_READ) == S_OK)
|
|
{
|
|
DWORD dw;
|
|
if (key.QueryValue(dw, c_szLeft) == S_OK)
|
|
x = (int)dw;
|
|
|
|
if (key.QueryValue(dw, c_szTop) == S_OK)
|
|
y = (int)dw;
|
|
}
|
|
|
|
Move(x, y, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCompButtonFrameWindow
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompButtonFrameWindow::CCompButtonFrameWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CCompButtonFrameWindow::CCompButtonFrameWindow(HIMC hIMC, DWORD dwStyle) : CCompFrameWindow(hIMC, dwStyle)
|
|
{
|
|
#ifdef COMPBUTTON_TOOLBARTHEME
|
|
//
|
|
// Set theme
|
|
//
|
|
SetActiveTheme(L"TOOLBAR", TBP_BACKGROUNDBOTTOM, TS_NORMAL );
|
|
#endif
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompButtonFrameWindow::~CCompButtonFrameWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CCompButtonFrameWindow::~CCompButtonFrameWindow()
|
|
{
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnCreate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompButtonFrameWindow::OnCreate(HWND hWnd)
|
|
{
|
|
//
|
|
// Set Window Theme.
|
|
//
|
|
#ifdef COMPBUTTON_TOOLBARTHEME
|
|
SetWindowTheme(hWnd, L"TASKBAR", NULL);
|
|
#else
|
|
SetWindowTheme(hWnd, L"TOOLBAR", NULL);
|
|
#endif
|
|
|
|
//
|
|
// Get margins of button theme.
|
|
//
|
|
CUIFTheme themeBtn;
|
|
memset(&_marginsButton, 0, sizeof(_marginsButton));
|
|
|
|
themeBtn.SetActiveTheme(L"TOOLBAR", TP_BUTTON, 0);
|
|
if (SUCCEEDED(themeBtn.OpenThemeData(hWnd)))
|
|
{
|
|
themeBtn.GetThemeMargins(NULL, TS_NORMAL,
|
|
TMT_CONTENTMARGINS,
|
|
NULL, &_marginsButton);
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompButtonFrameWindow::Init
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CCompButtonFrameWindow::Init()
|
|
{
|
|
|
|
if (!m_pEnterButton)
|
|
{
|
|
RECT rc;
|
|
::SetRect(&rc, 0, 0, 0, 0);
|
|
m_pEnterButton = new CCompFinalizeButton(this,
|
|
0,
|
|
&rc,
|
|
0,
|
|
UITBBUTTON_BUTTON,
|
|
0);
|
|
|
|
m_pEnterButton->Initialize();
|
|
m_pEnterButton->Init();
|
|
m_pEnterButton->SetIcon(LoadSmIcon(::GetInstance(),
|
|
MAKEINTRESOURCE(IDIC_ENTER_ICON)));
|
|
m_pEnterButton->SetToolTip(CRStr2(IDS_ENTER_BTN_TOOLTIP));
|
|
|
|
AddUIObj(m_pEnterButton);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompButtonFrameWindow::MoveShow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CCompButtonFrameWindow::MoveShow(int x, int y, BOOL fShow)
|
|
{
|
|
RECT rcWnd;
|
|
int cx = DEFFRAME_ENTER_BTN_CX + _marginsButton.cxLeftWidth + _marginsButton.cxRightWidth;
|
|
int cy = DEFFRAME_ENTER_BTN_CY + _marginsButton.cyTopHeight + _marginsButton.cyBottomHeight;
|
|
|
|
GetWindowRect(GetWnd(), &rcWnd);
|
|
Move(x, y,
|
|
((COMPBTN_LEFT_MARGIN + 1) * 2) + cx,
|
|
((COMPBTN_TOP_MARGIN + 1) * 2) + cy);
|
|
|
|
if (m_pEnterButton)
|
|
{
|
|
RECT rc;
|
|
x = COMPBTN_LEFT_MARGIN;
|
|
y = COMPBTN_TOP_MARGIN;
|
|
::SetRect(&rc, x, y, x + cx, x + cy);
|
|
m_pEnterButton->SetRect(&rc);
|
|
}
|
|
|
|
Show(fShow);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UIComposition
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::CompWndProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
LRESULT
|
|
UIComposition::CompWndProc(
|
|
HWND hCompWnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_SETCURSOR:
|
|
case WM_UICOMP_SETCURSOR:
|
|
{
|
|
UIComposition* pv = (UIComposition*)GetWindowLongPtr(hCompWnd, GWLP_USERDATA);
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (pv)
|
|
{
|
|
HWND hUIWnd = pv->GetUIWnd();
|
|
if (IsWindow(hUIWnd))
|
|
{
|
|
HIMC hImc = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
|
|
IMCLock imc(hImc);
|
|
if (SUCCEEDED(imc.GetResult()))
|
|
{
|
|
hr = pv->OnSetCursor(imc, wParam, lParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_PAINT:
|
|
case WM_TIMER:
|
|
{
|
|
TLS* ptls = TLS::GetTLS();
|
|
if (ptls == NULL)
|
|
return 0;
|
|
|
|
UIComposition* pv = (UIComposition*)GetWindowLongPtr(hCompWnd, GWLP_USERDATA);
|
|
if (pv != NULL)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hDC = BeginPaint(hCompWnd, &ps);
|
|
|
|
HWND hUIWnd = pv->GetUIWnd();
|
|
if (IsWindow(hUIWnd))
|
|
{
|
|
HIMC hImc = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC);
|
|
IMCLock imc(hImc);
|
|
if (SUCCEEDED(imc.GetResult()))
|
|
{
|
|
pv->OnPaint(ptls, hCompWnd, hDC, ps, imc);
|
|
}
|
|
}
|
|
EndPaint(hCompWnd, &ps);
|
|
}
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
pv->OnTimer(hCompWnd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hCompWnd, uMsg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::ctor
|
|
// UIComposition::dtor
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
UIComposition::UIComposition(HWND hUIWnd)
|
|
{
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
m_CompWnd[i].hCompWnd = NULL;
|
|
m_CompWnd[i].fDefaultCompWnd = FALSE;
|
|
}
|
|
m_DefCompWnd.hCompWnd = NULL;
|
|
m_DefCompWnd.fDefaultCompWnd = TRUE;
|
|
|
|
m_hFontLevel1 = NULL;
|
|
m_hFontLevel2 = NULL;
|
|
|
|
m_isc = 0;
|
|
m_hUIWnd = hUIWnd;
|
|
m_lpszCompStr = NULL;
|
|
m_nCompStr = 0;
|
|
m_bTimerCOMPOSITION = FALSE;
|
|
}
|
|
|
|
UIComposition::~UIComposition()
|
|
{
|
|
DestroyCompositionWindow();
|
|
|
|
if (m_hFontLevel1)
|
|
DeleteObject(m_hFontLevel1);
|
|
|
|
if (m_hFontLevel2)
|
|
DeleteObject(m_hFontLevel2);
|
|
|
|
m_hFontLevel1 = NULL;
|
|
m_hFontLevel2 = NULL;
|
|
|
|
if (m_lpszCompStr)
|
|
{
|
|
cicMemFree(m_lpszCompStr);
|
|
m_lpszCompStr = NULL;
|
|
}
|
|
m_nCompStr = 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnCreate
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnCreate()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnDestroy
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnDestroy()
|
|
{
|
|
return DestroyCompositionWindow();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeSetContext
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeSetContext(
|
|
IMCLock& imc,
|
|
HWND hUIWnd,
|
|
BOOL fActivate,
|
|
DWORD isc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (fActivate)
|
|
{
|
|
if (SUCCEEDED(imc.GetResult()))
|
|
{
|
|
//
|
|
// #598648
|
|
//
|
|
// Powerpnt XP does not clear ISC_SHOWUICOMPOSITIONWINDOW.
|
|
// even though it is AIMM filtered window. It must be Level3.
|
|
//
|
|
BOOL fFilter = MsimtfIsWindowFiltered(imc->hWnd);
|
|
if ((isc & ISC_SHOWUICOMPOSITIONWINDOW) && fFilter)
|
|
{
|
|
isc &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
|
|
|
//
|
|
// 616323
|
|
//
|
|
// Trident can not handle the existing composition string.
|
|
//
|
|
// if hIMC already has a composition string before the focus
|
|
// goes to the trident. We need to clear the comp string.
|
|
// Trident can not start the composition string in the middle
|
|
// of composing.
|
|
//
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnImeSetContext. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (comp->dwCompStrLen)
|
|
{
|
|
DWORD dwImeCompatFlags = ImmGetAppCompatFlags(NULL);
|
|
if (dwImeCompatFlags & IMECOMPAT_AIMM12_TRIDENT)
|
|
{
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(imc_ctfime.GetResult()))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnImeSetContext. _pCicContext==NULL"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
_pCicContext->EscbCompComplete(imc);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_isc = isc;
|
|
|
|
UpdateShowCompWndFlag(imc, NULL);
|
|
|
|
}
|
|
m_fActive = fActivate;
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeSetContextAfter
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeSetContextAfter(
|
|
IMCLock& imc)
|
|
{
|
|
if ((m_pDefCompFrameWnd && IsWindow(m_pDefCompFrameWnd->GetWnd())) ||
|
|
IsWindow(m_CompWnd[FIRST_WINDOW].hCompWnd)
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Validation check of imc.
|
|
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
|
|
//
|
|
hr = imc.GetResult();
|
|
|
|
//
|
|
// we show the def / level2 comp window,
|
|
//
|
|
// - if imc is valid.
|
|
// - if composition window is on Level1 or 2.
|
|
// - if it is not level 3,
|
|
// (m_isc does not have ISC_SHOWUICOMPOSITIONWINDOW)
|
|
// - if it is active.
|
|
// - if there is a composition string.
|
|
//
|
|
IME_UIWND_STATE uiwndState;
|
|
if (SUCCEEDED(hr) &&
|
|
((uiwndState = GetLevelFromIMC(imc)) == IME_UIWND_LEVEL1 || uiwndState == IME_UIWND_LEVEL2) &&
|
|
(m_isc & ISC_SHOWUICOMPOSITIONWINDOW) &&
|
|
m_fActive)
|
|
{
|
|
DWORD dwCompLen = 0;
|
|
UpdateShowCompWndFlag(imc, &dwCompLen);
|
|
|
|
if (uiwndState == IME_UIWND_LEVEL1)
|
|
{
|
|
ShowWindow(m_pDefCompFrameWnd->GetWnd(),
|
|
m_fShowCompWnd.IsSetFlag() ? SW_SHOWNOACTIVATE : SW_HIDE);
|
|
}
|
|
else if ((uiwndState == IME_UIWND_LEVEL2) && (m_fShowCompWnd.IsResetFlag()))
|
|
{
|
|
for (int i = 0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && dwCompLen > 0; i++)
|
|
{
|
|
m_CompWnd[i].caret.HideCaret();
|
|
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Both Level 1 / Level 2 window hide.
|
|
//
|
|
ShowWindow(m_pDefCompFrameWnd->GetWnd(), SW_HIDE);
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
m_CompWnd[i].caret.HideCaret();
|
|
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_isc &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeSelect
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeSelect(
|
|
BOOL fSelect)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeStartComposition
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeStartComposition(
|
|
IMCLock& imc,
|
|
HWND hUIWnd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (SUCCEEDED(hr = UpdateFont(imc)))
|
|
{
|
|
TEXTMETRIC tm;
|
|
HDC hDC;
|
|
HFONT hFontOrg;
|
|
|
|
hDC = GetDC(m_DefCompWnd.hCompWnd);
|
|
|
|
// get FontHeight for level1.
|
|
hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
|
|
GetTextMetrics(hDC, &tm);
|
|
m_tmFontHeightLevel1 = tm.tmHeight;
|
|
|
|
// get FontHeight for level2.
|
|
SelectObject(hDC, m_hFontLevel2);
|
|
GetTextMetrics(hDC, &tm);
|
|
m_tmFontHeightLevel2 = tm.tmHeight;
|
|
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
|
|
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
m_caret_size.cx = CARET_WIDTH;
|
|
m_caret_size.cy = tm.tmHeight + LINE_BOLD_WIDTH;
|
|
}
|
|
else
|
|
{
|
|
m_caret_size.cx = tm.tmHeight + LINE_BOLD_WIDTH;
|
|
m_caret_size.cy = CARET_WIDTH;
|
|
}
|
|
|
|
if (SUCCEEDED(hr = CreateCompositionWindow(imc, hUIWnd)))
|
|
{
|
|
UpdateCompositionRect(imc);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeCompositionUpdate
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeCompositionUpdate(IMCLock& imc)
|
|
{
|
|
m_isc |= ISC_SHOWUICOMPOSITIONWINDOW; // arrive WM_IME_COMPOSITION in IME UI window,
|
|
// IME should draw comp wnd.
|
|
return UpdateShowCompWndFlag(imc, NULL);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeCompositionUpdateByTimer
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeCompositionUpdateByTimer(IMCLock& imc)
|
|
{
|
|
return UpdateCompositionRect(imc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeEndComposition
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeEndComposition()
|
|
{
|
|
m_isc = 0;
|
|
return DestroyCompositionWindow();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::CreateCompositionWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::CreateCompositionWindow(
|
|
IMCLock& imc,
|
|
HWND hUIWnd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (SUCCEEDED(hr=imc.GetResult()) &&
|
|
IsWindow(hUIWnd) &&
|
|
m_fInitUIComp.IsResetFlag())
|
|
{
|
|
|
|
//
|
|
// Create three composition windows
|
|
//
|
|
// m_CompWnd[0].hCompWnd is first composition window rectangle.
|
|
// m_CompWnd[1].hCompWnd is middle composition window rectangle.
|
|
// m_CompWnd[2].hCompWnd is last composition window rectangle.
|
|
//
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
Assert(!m_CompWnd[i].hCompWnd);
|
|
m_CompWnd[i].hCompWnd = CreateWindowExW(0,
|
|
s_szCompClassName,
|
|
NULL,
|
|
WS_POPUP | WS_DISABLED,
|
|
0, 0, 0, 0,
|
|
hUIWnd, // Parent Window Handle.
|
|
NULL,
|
|
GetInstance(),
|
|
NULL);
|
|
if (m_CompWnd[i].hCompWnd == NULL)
|
|
{
|
|
DestroyCompositionWindow();
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_CompWnd[].hCompWnd==NULL"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
SetWindowLongPtr(m_CompWnd[i].hCompWnd, GWLP_USERDATA, (LONG_PTR)this);
|
|
|
|
switch (i)
|
|
{
|
|
case FIRST_WINDOW:
|
|
SetWindowLongPtr(m_CompWnd[FIRST_WINDOW].hCompWnd, COMPUI_WINDOW_INDEX, FIRST_WINDOW);
|
|
break;
|
|
case MIDDLE_WINDOW:
|
|
SetWindowLongPtr(m_CompWnd[MIDDLE_WINDOW].hCompWnd, COMPUI_WINDOW_INDEX, MIDDLE_WINDOW);
|
|
break;
|
|
case LAST_WINDOW:
|
|
SetWindowLongPtr(m_CompWnd[LAST_WINDOW].hCompWnd, COMPUI_WINDOW_INDEX, LAST_WINDOW);
|
|
break;
|
|
}
|
|
|
|
m_CompWnd[i].caret.CreateCaret(m_CompWnd[i].hCompWnd, m_caret_size);
|
|
}
|
|
|
|
if (FAILED(CreateCompButtonWnd(hUIWnd, (HIMC)imc)))
|
|
{
|
|
DestroyCompositionWindow();
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_pCompButtonFrameWindow==NULL"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(CreateDefFrameWnd(hUIWnd, (HIMC)imc)))
|
|
{
|
|
DestroyCompositionWindow();
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_pDefFrameWindow==NULL"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Create default composition window
|
|
//
|
|
Assert(!m_DefCompWnd.hCompWnd);
|
|
m_DefCompWnd.hCompWnd = CreateWindowExW(WS_EX_CLIENTEDGE,
|
|
s_szCompClassName,
|
|
NULL,
|
|
WS_CHILD | WS_DISABLED,
|
|
0, 0, 0, 0,
|
|
m_pDefCompFrameWnd->GetWnd(),
|
|
NULL,
|
|
GetInstance(),
|
|
NULL);
|
|
if (m_DefCompWnd.hCompWnd == NULL)
|
|
{
|
|
DestroyCompositionWindow();
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::Create. m_DefCompWnd.hCompWnd==NULL"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_pDefCompFrameWnd->SetCompStrWnd(m_DefCompWnd.hCompWnd);
|
|
|
|
SetWindowLongPtr(m_DefCompWnd.hCompWnd, GWLP_USERDATA, (LONG_PTR)this);
|
|
SetWindowLongPtr(m_DefCompWnd.hCompWnd, COMPUI_WINDOW_INDEX, DEFAULT_WINDOW);
|
|
|
|
m_DefCompWnd.caret.CreateCaret(m_DefCompWnd.hCompWnd, m_caret_size);
|
|
|
|
//
|
|
// Final: set flag
|
|
//
|
|
m_fInitUIComp.SetFlag();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::DestroyCompositionWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::DestroyCompositionWindow()
|
|
{
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
m_CompWnd[i].caret.DestroyCaret();
|
|
|
|
if (IsWindow(m_CompWnd[i].hCompWnd))
|
|
{
|
|
DestroyWindow(m_CompWnd[i].hCompWnd);
|
|
m_CompWnd[i].poly_text.RemoveAll();
|
|
}
|
|
m_CompWnd[i].hCompWnd = NULL;
|
|
}
|
|
|
|
if (m_pCompButtonFrameWnd)
|
|
{
|
|
DestroyWindow(m_pCompButtonFrameWnd->GetWnd());
|
|
delete m_pCompButtonFrameWnd;
|
|
m_pCompButtonFrameWnd = NULL;
|
|
}
|
|
|
|
m_DefCompWnd.caret.DestroyCaret();
|
|
|
|
if (IsWindow(m_DefCompWnd.hCompWnd))
|
|
{
|
|
DestroyWindow(m_DefCompWnd.hCompWnd);
|
|
m_DefCompWnd.poly_text.RemoveAll();
|
|
|
|
}
|
|
if (m_pDefCompFrameWnd)
|
|
{
|
|
DestroyWindow(m_pDefCompFrameWnd->GetWnd());
|
|
delete m_pDefCompFrameWnd;
|
|
m_pDefCompFrameWnd = NULL;
|
|
}
|
|
m_DefCompWnd.hCompWnd = NULL;
|
|
|
|
m_fInitUIComp.ResetFlag();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::HideCompositionWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::HideCompositionWindow()
|
|
{
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
if (IsWindow(m_CompWnd[i].hCompWnd))
|
|
{
|
|
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
|
|
}
|
|
}
|
|
|
|
if (IsWindow(m_DefCompWnd.hCompWnd))
|
|
{
|
|
ShowWindow(m_DefCompWnd.hCompWnd, SW_HIDE);
|
|
}
|
|
|
|
if (m_pDefCompFrameWnd)
|
|
m_pDefCompFrameWnd->Show(FALSE);
|
|
|
|
if (m_pCompButtonFrameWnd)
|
|
m_pCompButtonFrameWnd->Show(FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::GetSelection
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::GetSelection(
|
|
IMCLock& imc,
|
|
LONG *pacpSelStart,
|
|
LONG *pcchSel)
|
|
{
|
|
HRESULT hr;
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. _pCicContext==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
*pacpSelStart = 0;
|
|
*pcchSel = 0;
|
|
Interface<ITfRange> Selection;
|
|
Interface<ITfRangeACP> SelectionACP;
|
|
|
|
hr = _pCicContext->EscbGetSelection(imc, &Selection);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = Selection->QueryInterface(IID_ITfRangeACP, (void **)SelectionACP);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = SelectionACP->GetExtent(pacpSelStart, pcchSel);
|
|
}
|
|
}
|
|
|
|
//
|
|
// if there is no selection, we don't have to check ReadOnly area.
|
|
//
|
|
if (*pcchSel == 0)
|
|
return hr;
|
|
|
|
//
|
|
// find the first non readonly range in the text store.
|
|
//
|
|
// pacpSelSrart is the offset of the composition string,
|
|
// so we need to subtract the range of the readonly area.
|
|
//
|
|
LONG cchRO = 0;
|
|
hr = _pCicContext->EscbReadOnlyPropMargin(imc, &SelectionACP, &cchRO);
|
|
if (hr == S_OK)
|
|
{
|
|
if (cchRO <= *pacpSelStart)
|
|
{
|
|
*pacpSelStart -= cchRO;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// our selection is overwrapped to Read Only area. Why?
|
|
//
|
|
Assert(0);
|
|
*pacpSelStart = 0;
|
|
*pcchSel = 0;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::UpdateShowCompWndFlag
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::UpdateShowCompWndFlag(
|
|
IMCLock& imc,
|
|
DWORD* pdwCompStrLen)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Validation check of imc.
|
|
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
|
|
//
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateShowCompWndFlag. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (! IsWindow(imc->hWnd))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateShowCompWndFlag. imc->hWNd==NULL"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateShowCompWndFlag. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if ((m_isc & ISC_SHOWUICOMPOSITIONWINDOW) && comp->dwCompStrLen)
|
|
{
|
|
m_fShowCompWnd.SetFlag();
|
|
}
|
|
else
|
|
{
|
|
m_fShowCompWnd.ResetFlag();
|
|
}
|
|
|
|
if (pdwCompStrLen)
|
|
*pdwCompStrLen = comp->dwCompStrLen;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::UpdateCompositionRect
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::UpdateCompositionRect(
|
|
IMCLock& imc)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Validation check of imc.
|
|
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
|
|
//
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateCompositionRect. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (! IsWindow(imc->hWnd))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateCompositionRect. imc->hWNd==NULL"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateCompositionRect. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get Selection.
|
|
//
|
|
LONG acpSelStart = 0;
|
|
LONG cchSel = 0;
|
|
GetSelection(imc, &acpSelStart, &cchSel);
|
|
|
|
|
|
//
|
|
// Update show composition flag
|
|
//
|
|
DWORD dwCompLen = 0;
|
|
UpdateShowCompWndFlag(imc, &dwCompLen);
|
|
|
|
//
|
|
// Allocate temp composition string buffer
|
|
//
|
|
LPWSTR lpCompStr;
|
|
lpCompStr = GetCompStrBuffer(comp->dwCompStrLen);
|
|
if (!lpCompStr)
|
|
return E_OUTOFMEMORY;
|
|
|
|
//
|
|
// Store composition string in local buffer
|
|
//
|
|
memcpy(lpCompStr,
|
|
comp.GetOffsetPointer(comp->dwCompStrOffset),
|
|
dwCompLen * sizeof(WCHAR));
|
|
|
|
|
|
UINT fSwpShow = m_fShowCompWnd.IsSetFlag() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
|
|
|
|
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
|
|
if (uiwndState == IME_UIWND_LEVEL1)
|
|
{
|
|
//
|
|
// When the style is DEFAULT, show the default composition window.
|
|
//
|
|
if (IsWindow(m_DefCompWnd.hCompWnd))
|
|
{
|
|
POLYTEXTW poly;
|
|
memset(&poly, 0, sizeof(poly));
|
|
poly.n = dwCompLen;
|
|
poly.lpstr = (LPCWSTR)lpCompStr;
|
|
poly.uiFlags = ETO_OPAQUE;
|
|
|
|
SIZE size;
|
|
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
|
|
FLGetTextExtentPoint32(hDC, poly.lpstr, poly.n, &size);
|
|
|
|
poly.rcl.right = size.cx + 2 * GetSystemMetrics(SM_CXEDGE);
|
|
poly.rcl.bottom = size.cy + 2 * GetSystemMetrics(SM_CYEDGE);
|
|
|
|
BOOL fShowCaret = (comp->dwCursorPos <= poly.n ? TRUE : FALSE);
|
|
BOOL fEndCaret = (comp->dwCursorPos == poly.n ? TRUE : FALSE);
|
|
|
|
if (m_pDefCompFrameWnd)
|
|
{
|
|
m_pDefCompFrameWnd->SetCompStrRect(poly.rcl.right - poly.rcl.left + (fEndCaret ? m_caret_size.cx * 2: 0),
|
|
poly.rcl.bottom - poly.rcl.top + LINE_BOLD_WIDTH,
|
|
m_fShowCompWnd.IsSetFlag());
|
|
}
|
|
|
|
GuidMapAttribute guid_map(GuidMapAttribute::GetData(comp));
|
|
if (guid_map.Valid())
|
|
{
|
|
Assert(poly.n == guid_map->dwGuidMapAttrLen);
|
|
m_DefCompWnd.poly_text.RemoveAll();
|
|
|
|
PBYTE lpCompAttr = (PBYTE)guid_map.GetOffsetPointer(guid_map->dwGuidMapAttrOffset);
|
|
CCompClauseStore compclause;
|
|
compclause.Set(comp);
|
|
|
|
m_DefCompWnd.poly_text.SplitPolyStringAndAttr(imc, hDC, poly, lpCompAttr, &compclause);
|
|
}
|
|
else
|
|
{
|
|
m_DefCompWnd.poly_text.RemoveAll();
|
|
|
|
m_DefCompWnd.poly_text.SplitPolyStringAndAttr(imc, hDC, poly);
|
|
}
|
|
|
|
if (fShowCaret)
|
|
{
|
|
SetCaretPos(hDC, m_DefCompWnd.caret,
|
|
0, 0,
|
|
poly.lpstr, poly.n, comp->dwCursorPos,
|
|
FALSE, fEndCaret);
|
|
}
|
|
|
|
//
|
|
// Save Selection acp and cch
|
|
//
|
|
m_DefCompWnd.sel.acpStart = acpSelStart;
|
|
m_DefCompWnd.sel.cch = cchSel;
|
|
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
|
|
|
|
InvalidateRect(m_DefCompWnd.hCompWnd, NULL, FALSE);
|
|
}
|
|
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
if (IsWindow(m_CompWnd[i].hCompWnd))
|
|
{
|
|
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
|
|
}
|
|
}
|
|
|
|
if (m_pCompButtonFrameWnd)
|
|
{
|
|
m_pCompButtonFrameWnd->MoveShow(0, 0, FALSE);
|
|
}
|
|
}
|
|
else if (uiwndState == IME_UIWND_LEVEL2)
|
|
{
|
|
//
|
|
// When the style is not DEFAULT, show the composition window.
|
|
//
|
|
POINT pt = imc->cfCompForm.ptCurrentPos;
|
|
//
|
|
// Set the rectangle for the composition string.
|
|
//
|
|
RECT rect;
|
|
if (imc->cfCompForm.dwStyle & CFS_RECT)
|
|
rect = imc->cfCompForm.rcArea;
|
|
else
|
|
GetClientRect(imc->hWnd, &rect);
|
|
|
|
ClientToScreen(imc->hWnd, &pt);
|
|
MapWindowPoints(imc->hWnd, NULL, (LPPOINT)&rect, 2);
|
|
//
|
|
// Check the start position.
|
|
//
|
|
if (! PtInRect(&rect, pt))
|
|
return E_FAIL;
|
|
|
|
DWORD dwCursorPos = comp->dwCursorPos;
|
|
|
|
CCompClauseStore compclause;
|
|
compclause.Set(comp);
|
|
|
|
GuidMapAttribute guid_map(GuidMapAttribute::GetData(comp));
|
|
|
|
PBYTE lpCompAttr;
|
|
BOOL fCompAttr = TRUE;
|
|
|
|
if (guid_map.Valid())
|
|
{
|
|
lpCompAttr = (PBYTE)guid_map.GetOffsetPointer(guid_map->dwGuidMapAttrOffset);
|
|
Assert(dwCompLen == guid_map->dwGuidMapAttrLen);
|
|
}
|
|
else
|
|
{
|
|
TLS* ptls = TLS::GetTLS();
|
|
if (ptls)
|
|
{
|
|
CicProfile* pProfile;
|
|
if (pProfile = ptls->GetCicProfile())
|
|
{
|
|
LANGID langid;
|
|
pProfile->GetLangId(&langid);
|
|
if (PRIMARYLANGID(langid) == LANG_KOREAN)
|
|
{
|
|
fCompAttr = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fCompAttr)
|
|
return E_FAIL;
|
|
}
|
|
|
|
{
|
|
//
|
|
// composition window
|
|
//
|
|
POINT compbtn_pos = {0,0};
|
|
BOOL fInitcompbtn_pos = FALSE;
|
|
POINT window_pos;
|
|
window_pos = pt;
|
|
|
|
int window_width;
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
window_width = rect.right - pt.x;
|
|
}
|
|
else
|
|
{
|
|
window_width = rect.bottom - pt.y;
|
|
}
|
|
|
|
UINT string_length;
|
|
|
|
int i;
|
|
for (i = 0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && dwCompLen > 0; i++)
|
|
{
|
|
m_CompWnd[i].caret.HideCaret();
|
|
|
|
m_CompWnd[i].poly_text.RemoveAll();
|
|
|
|
//
|
|
// Init Selection acp and cch
|
|
//
|
|
m_CompWnd[i].sel.acpStart = 0;
|
|
m_CompWnd[i].sel.cch = 0;
|
|
|
|
SIZE size;
|
|
size.cy = 0;
|
|
if (IsWindow(m_CompWnd[i].hCompWnd))
|
|
{
|
|
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
|
|
if (i != MIDDLE_WINDOW)
|
|
{
|
|
string_length = CalcSingleTextExtentPoint(imc, hDC, lpCompStr, dwCompLen,
|
|
lpCompAttr,
|
|
fCompAttr,
|
|
&compclause,
|
|
window_width, &size,
|
|
m_CompWnd[i].poly_text, 0);
|
|
}
|
|
else
|
|
{
|
|
string_length = CalcMultiTextExtentPoint(imc, hDC, lpCompStr, dwCompLen,
|
|
lpCompAttr,
|
|
fCompAttr,
|
|
&compclause,
|
|
window_width, &size,
|
|
m_CompWnd[i].poly_text);
|
|
}
|
|
|
|
if (string_length)
|
|
{
|
|
BOOL fShowCaret = (dwCursorPos <= string_length ? TRUE : FALSE);
|
|
BOOL fEndCaret = (dwCursorPos == string_length ? TRUE : FALSE);
|
|
|
|
int pos_x = window_pos.x;
|
|
int pos_y = window_pos.y;
|
|
int cx;
|
|
int cy;
|
|
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
cx = size.cx + (fEndCaret ? m_caret_size.cx: 0);
|
|
cy = size.cy;
|
|
}
|
|
else
|
|
{
|
|
pos_x -= size.cx;
|
|
cx = size.cx;
|
|
cy = size.cy + (fEndCaret ? m_caret_size.cy: 0);
|
|
}
|
|
|
|
SetWindowPos(m_CompWnd[i].hCompWnd, HWND_TOP,
|
|
pos_x, pos_y, cx, cy,
|
|
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE |
|
|
fSwpShow);
|
|
|
|
if (fShowCaret)
|
|
{
|
|
UpdateCaretRect(hDC, i, dwCursorPos, imc.UseVerticalCompWindow(), fEndCaret);
|
|
dwCursorPos = ULONG_MAX;
|
|
}
|
|
else
|
|
{
|
|
dwCursorPos -= string_length;
|
|
}
|
|
|
|
//
|
|
// Save Selection acp and cch for this COMPWND
|
|
//
|
|
if (cchSel && (acpSelStart < (LONG)string_length))
|
|
{
|
|
m_CompWnd[i].sel.acpStart = acpSelStart;
|
|
LONG cchSelTemp = cchSel;
|
|
if (acpSelStart + cchSel > (LONG)string_length)
|
|
cchSelTemp = string_length - acpSelStart;
|
|
|
|
m_CompWnd[i].sel.cch = cchSelTemp;
|
|
|
|
//
|
|
// update cchSel for next COMPWND
|
|
//
|
|
cchSel -= cchSelTemp;
|
|
if (cchSel < 0)
|
|
cchSel = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// set level2 comp finalizing button position.
|
|
//
|
|
compbtn_pos.x = pos_x + cx;
|
|
compbtn_pos.y = pos_y;
|
|
fInitcompbtn_pos = TRUE;
|
|
|
|
//
|
|
// update CompStr, CompAttr, CompClause for next COMPWND
|
|
//
|
|
lpCompStr += string_length;
|
|
dwCompLen -= string_length;
|
|
if (fCompAttr)
|
|
{
|
|
lpCompAttr += string_length;
|
|
compclause.Shift(string_length);
|
|
}
|
|
|
|
//
|
|
// update acpSelStart for next COMPWND
|
|
//
|
|
acpSelStart -= string_length;
|
|
if (acpSelStart < 0)
|
|
acpSelStart = 0;
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
|
|
m_CompWnd[i].poly_text.RemoveAll();
|
|
}
|
|
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_CompWnd[i].hCompWnd, hDC);
|
|
|
|
InvalidateRect(m_CompWnd[i].hCompWnd, NULL, FALSE);
|
|
}
|
|
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
window_pos.x = rect.left;
|
|
window_pos.y += size.cy;
|
|
|
|
window_width = rect.right - rect.left;
|
|
|
|
rect.top += size.cy;
|
|
}
|
|
else
|
|
{
|
|
window_pos.x -= size.cx;
|
|
window_pos.y = rect.top;
|
|
|
|
window_width = rect.bottom - rect.top;
|
|
|
|
rect.left -= size.cx;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// hide the remaining window.
|
|
//
|
|
for (; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
if (IsWindow(m_CompWnd[i].hCompWnd))
|
|
ShowWindow(m_CompWnd[i].hCompWnd, SW_HIDE);
|
|
m_CompWnd[i].poly_text.RemoveAll();
|
|
}
|
|
if (IsWindow(m_DefCompWnd.hCompWnd))
|
|
{
|
|
ShowWindow(m_DefCompWnd.hCompWnd, SW_HIDE);
|
|
}
|
|
|
|
if (m_pDefCompFrameWnd)
|
|
m_pDefCompFrameWnd->Show(FALSE);
|
|
|
|
if (m_pCompButtonFrameWnd)
|
|
{
|
|
m_pCompButtonFrameWnd->MoveShow(compbtn_pos.x,
|
|
compbtn_pos.y,
|
|
m_fShowCompWnd.IsSetFlag() && fInitcompbtn_pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::UpdateFont
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::UpdateFont(
|
|
IMCLock& imc)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Validation check of imc.
|
|
// Because CIMEUIWindowHandler::ImeUIWndProcWorker doesn't check.
|
|
//
|
|
if (FAILED(hr=imc.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::UpdateFont. imc==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (m_hFontLevel1)
|
|
DeleteObject(m_hFontLevel1);
|
|
|
|
if (m_hFontLevel2)
|
|
DeleteObject(m_hFontLevel2);
|
|
|
|
LOGFONTW logfont = imc->lfFont.W;
|
|
|
|
m_hFontLevel2 = CreateFontIndirectW(&logfont);
|
|
|
|
logfont.lfEscapement = 0;
|
|
logfont.lfOrientation = 0;
|
|
if (logfont.lfFaceName[0] == L'@')
|
|
{
|
|
StringCchCopyW(logfont.lfFaceName, ARRAYSIZE(logfont.lfFaceName), &logfont.lfFaceName[1]);
|
|
}
|
|
m_hFontLevel1 = CreateFontIndirectW(&logfont);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnPaint
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnPaint(
|
|
TLS* ptls,
|
|
HWND hCompWnd,
|
|
HDC hDC,
|
|
PAINTSTRUCT& ps,
|
|
IMCLock& imc)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
COMPWNDINDEX index = (COMPWNDINDEX)GetWindowLong(hCompWnd, COMPUI_WINDOW_INDEX);
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPaint. comp==NULL"));
|
|
}
|
|
else
|
|
{
|
|
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
|
|
|
|
if ((uiwndState == IME_UIWND_LEVEL1) &&
|
|
(index == DEFAULT_WINDOW))
|
|
{
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
|
|
|
|
PolyTextAndAttrOut(ptls,
|
|
hDC,
|
|
FALSE,
|
|
&m_DefCompWnd);
|
|
SelectObject(hDC, hFontOrg);
|
|
}
|
|
else if ((uiwndState == IME_UIWND_LEVEL2) &&
|
|
(index != DEFAULT_WINDOW))
|
|
{
|
|
if (m_CompWnd[index].poly_text.GetPolySize())
|
|
{
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
|
|
PolyTextAndAttrOut(ptls,
|
|
hDC,
|
|
imc.UseVerticalCompWindow(),
|
|
&m_CompWnd[index]);
|
|
SelectObject(hDC, hFontOrg);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnTimer
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnTimer(
|
|
HWND hCompWnd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
COMPWNDINDEX index = (COMPWNDINDEX)GetWindowLong(hCompWnd, COMPUI_WINDOW_INDEX);
|
|
|
|
if (index == DEFAULT_WINDOW)
|
|
{
|
|
return m_DefCompWnd.caret.OnTimer();
|
|
}
|
|
else
|
|
{
|
|
return m_CompWnd[index].caret.OnTimer();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeNotifySetCompositionWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeNotifySetCompositionWindow(
|
|
IMCLock& imc)
|
|
{
|
|
return UpdateCompositionRect(imc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnImeNotifySetCompositionFont
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnImeNotifySetCompositionFont(
|
|
IMCLock& imc)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = UpdateFont(imc)))
|
|
return hr;
|
|
|
|
return UpdateCompositionRect(imc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::CalcSingleTextExtentPoint
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
UINT
|
|
UIComposition::CalcSingleTextExtentPoint(
|
|
IMCLock& imc,
|
|
HDC hDC,
|
|
LPCWSTR lpsz,
|
|
int string_len,
|
|
PBYTE lpAttr,
|
|
BOOL fCompAttr,
|
|
CCompClauseStore* compclause,
|
|
int window_width,
|
|
LPSIZE real_size, // OUTPUT: Total window rectangle
|
|
CPolyText& poly_text,
|
|
int row_index)
|
|
{
|
|
if (string_len == 0 || lpsz == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
SIZE delta_size;
|
|
delta_size.cx = 0;
|
|
|
|
UINT ret_len = 0;
|
|
UINT delta_len = 0;
|
|
SIZE size;
|
|
|
|
while ((delta_size.cx < window_width) && string_len)
|
|
{
|
|
++delta_len;
|
|
--string_len;
|
|
FLGetTextExtentPoint32(hDC, lpsz, delta_len, &size);
|
|
delta_size = size;
|
|
}
|
|
|
|
if (delta_size.cx < window_width)
|
|
{
|
|
ret_len = delta_len;
|
|
}
|
|
else
|
|
{
|
|
ret_len = (delta_len > 1 ? delta_len - 1 : 0);
|
|
}
|
|
|
|
if (ret_len)
|
|
{
|
|
FLGetTextExtentPoint32(hDC, lpsz, ret_len, real_size);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if string length is 0, we should return just the height.
|
|
//
|
|
real_size->cx = 0;
|
|
real_size->cy = delta_size.cy;
|
|
}
|
|
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
if (ret_len > 0)
|
|
{
|
|
real_size->cy += LINE_BOLD_WIDTH;
|
|
|
|
POLYTEXTW poly;
|
|
memset(&poly, 0, sizeof(poly));
|
|
poly.y = row_index * real_size->cy;
|
|
poly.n = ret_len;
|
|
poly.lpstr = lpsz;
|
|
poly.uiFlags = ETO_OPAQUE;
|
|
poly.rcl.top = row_index * real_size->cy;
|
|
poly.rcl.right = real_size->cx;
|
|
poly.rcl.bottom = poly.rcl.top + real_size->cy;
|
|
if (fCompAttr)
|
|
poly_text.SplitPolyStringAndAttr(imc, hDC, poly, lpAttr, compclause);
|
|
else
|
|
poly_text.SplitPolyStringAndAttr(imc, hDC, poly);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RotateSize(real_size);
|
|
|
|
if (ret_len > 0)
|
|
{
|
|
real_size->cx += LINE_BOLD_WIDTH;
|
|
|
|
//
|
|
// shift prev lines to the right.
|
|
//
|
|
poly_text.ShiftPolyText(real_size->cx, 0);
|
|
|
|
POLYTEXTW poly;
|
|
memset(&poly, 0, sizeof(poly));
|
|
poly.x = real_size->cx;
|
|
poly.n = ret_len;
|
|
poly.lpstr = lpsz;
|
|
poly.uiFlags = ETO_OPAQUE;
|
|
poly.rcl.left = 0;
|
|
poly.rcl.right = poly.rcl.left + real_size->cx;
|
|
poly.rcl.bottom = real_size->cy;
|
|
if (fCompAttr)
|
|
poly_text.SplitPolyStringAndAttr(imc, hDC, poly, lpAttr, compclause);
|
|
else
|
|
poly_text.SplitPolyStringAndAttr(imc, hDC, poly);
|
|
}
|
|
}
|
|
|
|
//
|
|
// #608684
|
|
//
|
|
// the total size of poly text could be bigger than the result of
|
|
// FLGetTextExtentPoint() with whole string. So we need to
|
|
// adjust the returning size.
|
|
//
|
|
if (ret_len)
|
|
{
|
|
int real_width = 0;
|
|
INT_PTR i;
|
|
INT_PTR nCnt = poly_text.GetPolySize();
|
|
const POLYTEXTW* ppoly = poly_text.GetPolyData();
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
if (ppoly->rcl.top == (row_index * real_size->cy))
|
|
real_width += (ppoly->rcl.right - ppoly->rcl.left);
|
|
|
|
ppoly++;
|
|
}
|
|
|
|
Assert(window_width >= real_width);
|
|
real_size->cx = real_width;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
if (ppoly->rcl.left == 0)
|
|
real_width += (ppoly->rcl.bottom - ppoly->rcl.top);
|
|
|
|
ppoly++;
|
|
}
|
|
|
|
Assert(window_width >= real_width);
|
|
real_size->cy = real_width;
|
|
}
|
|
}
|
|
|
|
return ret_len;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::CalcMultiTextExtentPoint
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
UINT
|
|
UIComposition::CalcMultiTextExtentPoint(
|
|
IMCLock& imc,
|
|
HDC hDC,
|
|
LPCWSTR lpsz,
|
|
int string_len,
|
|
PBYTE lpAttr,
|
|
BOOL fCompAttr,
|
|
CCompClauseStore *compclause,
|
|
int window_width,
|
|
LPSIZE real_size, // OUTPUT: Total window rectangle
|
|
CPolyText& poly_text)
|
|
{
|
|
SIZE single_size; // output single window rectangle from CalcSingleTextExtentPoint
|
|
single_size.cy = 0;
|
|
single_size.cx = 0;
|
|
UINT single_len;
|
|
|
|
UINT total_string_len = 0;
|
|
SIZE prev_size = {0, 0};
|
|
UINT prev_string_len = 0;
|
|
|
|
real_size->cx = 0;
|
|
real_size->cy = 0;
|
|
|
|
int row_index = 0;
|
|
CCompClauseStore compclauseTmp;
|
|
compclauseTmp.Copy(compclause);
|
|
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
while ((single_len = CalcSingleTextExtentPoint(imc, hDC, lpsz, string_len, lpAttr, fCompAttr, &compclauseTmp, window_width, &single_size, poly_text, row_index)) > 0)
|
|
{
|
|
string_len -= single_len;
|
|
lpsz += single_len;
|
|
|
|
if (fCompAttr)
|
|
{
|
|
lpAttr += single_len;
|
|
compclauseTmp.Shift(single_len);
|
|
}
|
|
|
|
real_size->cx = max(real_size->cx, single_size.cx);
|
|
real_size->cy += single_size.cy;
|
|
|
|
prev_size = single_size;
|
|
prev_string_len = single_len;
|
|
|
|
total_string_len += single_len;
|
|
|
|
++row_index;
|
|
}
|
|
|
|
real_size->cy -= prev_size.cy;
|
|
total_string_len -= prev_string_len;
|
|
poly_text.RemoveLastLine(FALSE);
|
|
}
|
|
else
|
|
{
|
|
while ((single_len = CalcSingleTextExtentPoint(imc, hDC, lpsz, string_len, lpAttr, fCompAttr, &compclauseTmp, window_width, &single_size, poly_text, row_index)) > 0)
|
|
{
|
|
string_len -= single_len;
|
|
lpsz += single_len;
|
|
|
|
if (fCompAttr)
|
|
{
|
|
lpAttr += single_len;
|
|
compclauseTmp.Shift(single_len);
|
|
}
|
|
|
|
real_size->cy = max(real_size->cy, single_size.cy);
|
|
real_size->cx += single_size.cx;
|
|
|
|
prev_size = single_size;
|
|
prev_string_len = single_len;
|
|
|
|
total_string_len += single_len;
|
|
|
|
++row_index;
|
|
}
|
|
|
|
real_size->cx -= prev_size.cx;
|
|
total_string_len -= prev_string_len;
|
|
|
|
if (poly_text.RemoveLastLine(TRUE) == S_OK)
|
|
poly_text.ShiftPolyText(-single_size.cx, 0);
|
|
}
|
|
|
|
|
|
return total_string_len;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::SetCaretPos
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::SetCaretPos(
|
|
HDC hDC,
|
|
CCaret& caret,
|
|
int x,
|
|
int y,
|
|
LPCWSTR lpCompStr,
|
|
DWORD string_length,
|
|
DWORD cursor_pos,
|
|
BOOL fVert,
|
|
BOOL fEndCaret)
|
|
{
|
|
if (cursor_pos > string_length)
|
|
return S_FALSE;
|
|
|
|
SIZE size;
|
|
FLGetTextExtentPoint32(hDC, lpCompStr, cursor_pos, &size);
|
|
|
|
POINT pos;
|
|
if (!fVert)
|
|
{
|
|
pos.x = ((x + size.cx > 1) ? (x + size.cx - (fEndCaret ? 0 : 1)) : 0);
|
|
pos.y = y;
|
|
}
|
|
else
|
|
{
|
|
RotateSize(&size);
|
|
pos.x = x - size.cx - LINE_BOLD_WIDTH;
|
|
pos.y = ((y + size.cy > 1) ? (y + size.cy - (fEndCaret ? 0 : 1)) : 0);
|
|
}
|
|
caret.SetCaretPos(pos);
|
|
caret.ShowCaret();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::UpdateCaretRect
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::UpdateCaretRect(
|
|
HDC hDC,
|
|
int index,
|
|
DWORD dwCursorPos, // dwCursorPos:: based on m_CompWnd[index].poly_text.lpstr
|
|
BOOL fVert,
|
|
BOOL fEndCaret)
|
|
{
|
|
POLYTEXTW poly;
|
|
DWORD dwCur = dwCursorPos;
|
|
BOOL fFound = FALSE;
|
|
|
|
for (int i=0; i < m_CompWnd[index].poly_text.GetPolySize(); i++)
|
|
{
|
|
poly = m_CompWnd[index].poly_text.GetPolyAt(i);
|
|
if (dwCur <= poly.n)
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
dwCur -= poly.n;
|
|
}
|
|
if (! fFound)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
SetCaretPos(hDC, m_CompWnd[index].caret,
|
|
poly.x, poly.y,
|
|
poly.lpstr, poly.n,
|
|
dwCur, fVert, fEndCaret);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::PolyTextAndAttrOut
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
const DWORD s_dwDotStyles[] = {1,2};
|
|
const DWORD s_dwDashStyles[] = {3,2};
|
|
|
|
HRESULT
|
|
UIComposition::PolyTextAndAttrOut(
|
|
TLS* ptls,
|
|
HDC hDC,
|
|
BOOL fVert,
|
|
COMPWND* pcompwnd)
|
|
{
|
|
CicBridge* cic = ptls->GetCicBridge();
|
|
if (cic == NULL)
|
|
{
|
|
Internal_PolyTextOutW(hDC, pcompwnd->poly_text.GetPolyData(), (int)pcompwnd->poly_text.GetPolySize());
|
|
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::PolyTextAndAttrOut. cic==NULL"));
|
|
return S_OK;
|
|
}
|
|
|
|
if (pcompwnd->poly_text.GetAttrSize() == 0)
|
|
{
|
|
//
|
|
// Korean default composition window.
|
|
//
|
|
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
|
|
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
|
|
Internal_PolyTextOutW(hDC, pcompwnd->poly_text.GetPolyData(), (int)pcompwnd->poly_text.GetPolySize());
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
RECT rect;
|
|
GetClientRect(pcompwnd->hCompWnd, &rect);
|
|
LONG acpStart = 0;
|
|
|
|
for (int i = 0; i < pcompwnd->poly_text.GetAttrSize(); i++)
|
|
{
|
|
POLYTEXTW poly = pcompwnd->poly_text.GetPolyAt(i);
|
|
|
|
//
|
|
// Check if this is the last in this line.
|
|
//
|
|
BOOL fLastTextInLine = FALSE;
|
|
if (i + 1 < pcompwnd->poly_text.GetAttrSize())
|
|
{
|
|
POLYTEXTW poly_next = pcompwnd->poly_text.GetPolyAt(i+1);
|
|
if (!fVert && (poly_next.x < poly.rcl.right))
|
|
fLastTextInLine = TRUE;
|
|
else if (fVert && (poly_next.y < poly.rcl.bottom))
|
|
fLastTextInLine = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fLastTextInLine = TRUE;
|
|
}
|
|
|
|
TF_DISPLAYATTRIBUTE da;
|
|
BOOL fDapNotFound = FALSE;
|
|
|
|
if (FAILED(cic->GetDisplayAttributeInfo(pcompwnd->poly_text.GetAttrAt(i), &da)))
|
|
{
|
|
memset(&da, 0, sizeof(da));
|
|
da.lsStyle = TF_LS_DOT;
|
|
da.crLine.type = TF_CT_SYSCOLOR;
|
|
da.crLine.nIndex = COLOR_WINDOWTEXT;
|
|
fDapNotFound= TRUE;
|
|
}
|
|
|
|
//
|
|
// Text and Back color.
|
|
//
|
|
switch (da.crText.type)
|
|
{
|
|
case TF_CT_SYSCOLOR: SetTextColor(hDC, GetSysColor(da.crText.nIndex)); break;
|
|
case TF_CT_COLORREF: SetTextColor(hDC, da.crText.cr); break;
|
|
default: SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); break;
|
|
}
|
|
switch (da.crBk.type)
|
|
{
|
|
case TF_CT_SYSCOLOR: SetBkColor(hDC, GetSysColor(da.crBk.nIndex)); break;
|
|
case TF_CT_COLORREF: SetBkColor(hDC, da.crBk.cr); break;
|
|
default: SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); break;
|
|
}
|
|
|
|
//
|
|
// Line
|
|
//
|
|
|
|
DWORD dwPenStyle = PS_GEOMETRIC | PS_SOLID;
|
|
DWORD dwStyles = 0;
|
|
const DWORD *lpdwStyles = NULL;
|
|
switch (da.lsStyle)
|
|
{
|
|
case TF_LS_NONE:
|
|
dwPenStyle = PS_NULL;
|
|
break;
|
|
|
|
case TF_LS_SOLID:
|
|
dwPenStyle = PS_GEOMETRIC | PS_SOLID;
|
|
break;
|
|
|
|
case TF_LS_DOT:
|
|
dwPenStyle = PS_GEOMETRIC | PS_USERSTYLE;
|
|
dwStyles = 2;
|
|
lpdwStyles = s_dwDotStyles;
|
|
break;
|
|
|
|
case TF_LS_DASH:
|
|
dwPenStyle = PS_GEOMETRIC | PS_USERSTYLE;
|
|
dwStyles = 2;
|
|
lpdwStyles = s_dwDashStyles;
|
|
break;
|
|
|
|
case TF_LS_SQUIGGLE:
|
|
dwPenStyle = PS_GEOMETRIC | PS_SOLID;
|
|
break;
|
|
}
|
|
|
|
|
|
DWORD dwWidth = 1;
|
|
if (da.fBoldLine)
|
|
{
|
|
dwWidth = LINE_BOLD_WIDTH;
|
|
}
|
|
|
|
LOGBRUSH lbr;
|
|
lbr.lbStyle = BS_SOLID;
|
|
lbr.lbColor = 0;
|
|
lbr.lbHatch = 0;
|
|
switch (da.crLine.type)
|
|
{
|
|
case TF_CT_SYSCOLOR: lbr.lbColor = GetSysColor(da.crLine.nIndex); break;
|
|
case TF_CT_COLORREF: lbr.lbColor = da.crLine.cr; break;
|
|
case TF_CT_NONE: lbr.lbColor = GetTextColor(hDC); break;
|
|
}
|
|
|
|
HPEN hPen = ExtCreatePen(dwPenStyle, dwWidth, &lbr, dwStyles, lpdwStyles);
|
|
if (hPen != NULL)
|
|
{
|
|
HPEN hPenOrg = (HPEN)SelectObject(hDC, hPen);
|
|
|
|
Internal_PolyTextOutW(hDC, &poly, 1);
|
|
|
|
SIZE size;
|
|
FLGetTextExtentPoint32(hDC, poly.lpstr, poly.n, &size);
|
|
|
|
POINT start_pt;
|
|
POINT end_pt;
|
|
if (!fVert)
|
|
{
|
|
start_pt.x = poly.x;
|
|
start_pt.y = poly.y + size.cy;
|
|
//
|
|
// (size.cy / 4) is the gap between clauses.
|
|
//
|
|
end_pt.x = poly.rcl.right;
|
|
if (!fLastTextInLine)
|
|
end_pt.x -= (size.cy / 4);
|
|
|
|
end_pt.y = start_pt.y;
|
|
}
|
|
else
|
|
{
|
|
RotateSize(&size);
|
|
|
|
start_pt.x = poly.rcl.left + 1;
|
|
start_pt.y = poly.y;
|
|
end_pt.x = poly.rcl.left + 1;
|
|
|
|
//
|
|
// (size.cx / 4) is the gap between clauses.
|
|
//
|
|
end_pt.y = poly.rcl.bottom;
|
|
if (!fLastTextInLine)
|
|
end_pt.y -= (size.cx / 4);
|
|
}
|
|
|
|
|
|
MoveToEx(hDC, start_pt.x, start_pt.y, NULL);
|
|
|
|
if (da.lsStyle != TF_LS_SQUIGGLE)
|
|
{
|
|
LineTo(hDC, end_pt.x, end_pt.y);
|
|
}
|
|
else
|
|
{
|
|
CArray<POINT, POINT> squiggle_line;
|
|
MakeSquiggleLine(start_pt, end_pt, LINE_SQUIGGLE_FREQUENCY, LINE_SQUIGGLE_AMPLITUDE, fVert, squiggle_line);
|
|
Polyline(hDC, squiggle_line.GetData(), (int)squiggle_line.GetSize());
|
|
}
|
|
|
|
SelectObject(hDC, hPenOrg);
|
|
DeleteObject(hPen);
|
|
}
|
|
else
|
|
{
|
|
Assert(0);
|
|
Internal_PolyTextOutW(hDC, &poly, 1);
|
|
}
|
|
|
|
//
|
|
// Draw Selection.
|
|
//
|
|
if (fDapNotFound && pcompwnd->sel.cch &&
|
|
((acpStart + (LONG)poly.n) > pcompwnd->sel.acpStart) &&
|
|
(acpStart <= pcompwnd->sel.acpStart + pcompwnd->sel.cch))
|
|
{
|
|
LONG acpSelStartTemp;
|
|
LONG cchSelTemp;
|
|
|
|
acpSelStartTemp = pcompwnd->sel.acpStart - acpStart;
|
|
if (acpSelStartTemp < 0)
|
|
acpSelStartTemp = 0;
|
|
|
|
cchSelTemp = pcompwnd->sel.acpStart + pcompwnd->sel.cch - acpStart - acpSelStartTemp;
|
|
if (cchSelTemp > (LONG)poly.n)
|
|
cchSelTemp = poly.n;
|
|
|
|
|
|
SIZE sizeStart;
|
|
SIZE sizeEnd;
|
|
if (acpSelStartTemp)
|
|
{
|
|
FLGetTextExtentPoint32(hDC,
|
|
poly.lpstr,
|
|
acpSelStartTemp,
|
|
&sizeStart);
|
|
}
|
|
else
|
|
{
|
|
sizeStart.cx = 0;
|
|
sizeStart.cy = pcompwnd->fDefaultCompWnd ?
|
|
m_tmFontHeightLevel1 : m_tmFontHeightLevel2;
|
|
}
|
|
|
|
FLGetTextExtentPoint32(hDC,
|
|
poly.lpstr,
|
|
acpSelStartTemp + cchSelTemp,
|
|
&sizeEnd);
|
|
|
|
RECT rcInvert;
|
|
rcInvert = poly.rcl;
|
|
if (!fVert)
|
|
{
|
|
rcInvert.left = poly.rcl.left + sizeStart.cx;
|
|
rcInvert.right = poly.rcl.left + sizeEnd.cx;
|
|
}
|
|
else
|
|
{
|
|
rcInvert.top = poly.rcl.top + sizeStart.cx;
|
|
rcInvert.bottom = poly.rcl.top + sizeEnd.cx;
|
|
}
|
|
|
|
BitBlt(hDC,
|
|
rcInvert.left,
|
|
rcInvert.top,
|
|
rcInvert.right - rcInvert.left,
|
|
rcInvert.bottom - rcInvert.top,
|
|
hDC,
|
|
rcInvert.left,
|
|
rcInvert.top,
|
|
DSTINVERT);
|
|
}
|
|
|
|
if (fLastTextInLine)
|
|
{
|
|
//
|
|
// if this is the last in this line, we just draw with bk color.
|
|
//
|
|
POLYTEXTW poly_clear;
|
|
memset(&poly_clear, 0, sizeof(poly_clear));
|
|
if (!fVert)
|
|
{
|
|
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
|
|
poly_clear.uiFlags = ETO_OPAQUE;
|
|
poly_clear.rcl.top = poly.y;
|
|
poly_clear.rcl.bottom = poly.rcl.bottom;
|
|
poly_clear.rcl.left = poly.rcl.right;
|
|
poly_clear.rcl.right = rect.right;
|
|
Internal_PolyTextOutW(hDC, &poly_clear, 1);
|
|
}
|
|
else
|
|
{
|
|
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
|
|
poly_clear.uiFlags = ETO_OPAQUE;
|
|
poly_clear.rcl.top = poly.rcl.bottom;
|
|
poly_clear.rcl.bottom = rect.bottom;
|
|
poly_clear.rcl.left = poly.rcl.left;
|
|
poly_clear.rcl.right = poly.x;
|
|
Internal_PolyTextOutW(hDC, &poly_clear, 1);
|
|
}
|
|
}
|
|
|
|
acpStart += poly.n;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::MakeSquiggleLine
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::MakeSquiggleLine(
|
|
POINT start_pt,
|
|
POINT end_pt,
|
|
int frequency,
|
|
int amplitude,
|
|
BOOL fVert,
|
|
CArray<POINT, POINT>& squiggle_line)
|
|
{
|
|
|
|
int nSquiggle = 0;
|
|
int n;
|
|
if (!fVert)
|
|
{
|
|
if (end_pt.x > start_pt.x)
|
|
n = (end_pt.x - start_pt.x) / frequency;
|
|
else
|
|
n = (start_pt.x - end_pt.x) / frequency;
|
|
}
|
|
else
|
|
{
|
|
if (end_pt.y > start_pt.y)
|
|
n = (end_pt.y - start_pt.y) / frequency;
|
|
else
|
|
n = (start_pt.y - end_pt.y) / frequency;
|
|
}
|
|
|
|
nSquiggle = n * 2; // control point.
|
|
nSquiggle++; // end point.
|
|
|
|
POINT begin_pt = start_pt;
|
|
POINT pt = begin_pt;
|
|
|
|
for (int i=1; i < nSquiggle; i++)
|
|
{
|
|
if (!fVert)
|
|
{
|
|
if ((n = i % 2) != 0)
|
|
{
|
|
// control point
|
|
pt.x += frequency / 2;
|
|
pt.y = begin_pt.y - amplitude;
|
|
}
|
|
else
|
|
{
|
|
pt.x = begin_pt.x + frequency;
|
|
pt.y = begin_pt.y;
|
|
|
|
begin_pt = pt;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((n = i % 2) != 0)
|
|
{
|
|
// control point
|
|
pt.x = begin_pt.x + amplitude;
|
|
pt.y += frequency / 2;
|
|
}
|
|
else
|
|
{
|
|
pt.x = begin_pt.x;
|
|
pt.y = begin_pt.y + frequency;
|
|
|
|
begin_pt = pt;
|
|
}
|
|
}
|
|
squiggle_line.SetAtGrow(i-1, pt);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnPrivateGetContextFlag
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnPrivateGetContextFlag(
|
|
IMCLock& imc,
|
|
BOOL fStartComposition,
|
|
IME_UIWND_STATE* uists)
|
|
{
|
|
//
|
|
// Check WM_IME_STARTCOMPOSITION already send ?
|
|
//
|
|
if (fStartComposition)
|
|
{
|
|
WINDOWPLACEMENT wndpl;
|
|
|
|
if (IsWindow(m_DefCompWnd.hCompWnd) && IsWindowVisible(m_DefCompWnd.hCompWnd))
|
|
{
|
|
*uists = IME_UIWND_LEVEL1;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
for (int i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
if (IsWindow(m_CompWnd[i].hCompWnd) && IsWindowVisible(m_CompWnd[i].hCompWnd))
|
|
{
|
|
*uists = IME_UIWND_LEVEL2;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If m_fShowCompWnd flag set, already arrived WM_IME_COMPOSITION in this UI Wnd.
|
|
// In this case, IME UI Wnd Level is either Level 1 or Level 2.
|
|
//
|
|
if (m_fShowCompWnd.IsSetFlag())
|
|
{
|
|
*uists = IME_UIWND_LEVEL1_OR_LEVEL2;
|
|
return S_OK;
|
|
}
|
|
|
|
if (! (m_isc & ISC_SHOWUICOMPOSITIONWINDOW))
|
|
{
|
|
*uists = IME_UIWND_LEVEL3;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
*uists = IME_UIWND_UNKNOWN;
|
|
return S_FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnPrivateGetCandRectFromComposition
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnPrivateGetCandRectFromComposition(
|
|
IMCLock& imc,
|
|
CandRectFromComposition* pv)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetCandRectFromComposition. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
|
|
if (uiwndState == IME_UIWND_LEVEL1)
|
|
{
|
|
LPCWSTR lpstr = (LPCWSTR)comp.GetOffsetPointer(comp->dwCompStrOffset);
|
|
|
|
SIZE size;
|
|
if (lpstr && pv->dwCharPos)
|
|
{
|
|
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
|
|
FLGetTextExtentPoint32(hDC, lpstr, pv->dwCharPos, &size);
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
|
|
}
|
|
else
|
|
{
|
|
size.cx = 0;
|
|
size.cy = m_tmFontHeightLevel1;
|
|
}
|
|
|
|
//
|
|
// When the style is DEFAULT, this is the default composition window.
|
|
//
|
|
GetWindowRect(m_DefCompWnd.hCompWnd, pv->out_rcArea);
|
|
|
|
POINT pt;
|
|
|
|
pt.x = pt.y = 0;
|
|
pv->out_rcArea->left += pt.x + size.cx;
|
|
pv->out_rcArea->right += pt.x + size.cx;
|
|
pv->out_rcArea->top += pt.y;
|
|
pv->out_rcArea->bottom += pt.y;
|
|
}
|
|
else if (uiwndState == IME_UIWND_LEVEL2)
|
|
{
|
|
BOOL fFound = FALSE;
|
|
POLYTEXTW poly;
|
|
DWORD dwCur = pv->dwCharPos;
|
|
int i;
|
|
|
|
if (PRIMARYLANGID(pv->langid) == LANG_JAPANESE)
|
|
{
|
|
//
|
|
// In Japanese case, poly_text stored each clause string.
|
|
//
|
|
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && ! fFound;)
|
|
{
|
|
for (int j=0; j < m_CompWnd[i].poly_text.GetPolySize(); j++)
|
|
{
|
|
poly = m_CompWnd[i].poly_text.GetPolyAt(j);
|
|
if (dwCur < poly.n)
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
dwCur -= poly.n;
|
|
}
|
|
if (! fFound)
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// In other language case, poly_text stored plane text. Not clause.
|
|
//
|
|
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND) && ! fFound;)
|
|
{
|
|
for (int j=0; j < m_CompWnd[i].poly_text.GetPolySize(); j++)
|
|
{
|
|
poly = m_CompWnd[i].poly_text.GetPolyAt(j);
|
|
if (dwCur <= poly.n)
|
|
{
|
|
fFound = TRUE;
|
|
poly.n = dwCur;
|
|
break;
|
|
}
|
|
dwCur -= poly.n;
|
|
}
|
|
if (! fFound)
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (! fFound)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
SIZE size;
|
|
if (poly.lpstr && poly.n)
|
|
{
|
|
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
|
|
FLGetTextExtentPoint32(hDC, poly.lpstr, poly.n, &size);
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
|
|
}
|
|
else
|
|
{
|
|
size.cx = 0;
|
|
size.cy = m_tmFontHeightLevel2;
|
|
}
|
|
|
|
if (!imc.UseVerticalCompWindow())
|
|
{
|
|
//
|
|
// When the style is not DEFAULT, this is the composition window.
|
|
//
|
|
if (PRIMARYLANGID(pv->langid) == LANG_JAPANESE)
|
|
{
|
|
pv->out_rcArea->left = poly.x;
|
|
}
|
|
else
|
|
{
|
|
pv->out_rcArea->left = poly.x + size.cx;
|
|
}
|
|
pv->out_rcArea->right = poly.x + size.cx;
|
|
pv->out_rcArea->top = poly.y;
|
|
pv->out_rcArea->bottom = poly.y + size.cy + LINE_BOLD_WIDTH;
|
|
}
|
|
else
|
|
{
|
|
RotateSize(&size);
|
|
|
|
pv->out_rcArea->left = poly.x - size.cx - LINE_BOLD_WIDTH;
|
|
pv->out_rcArea->right = poly.x;
|
|
pv->out_rcArea->top = poly.y;
|
|
pv->out_rcArea->bottom = poly.y + size.cy;
|
|
}
|
|
|
|
//
|
|
// Convert to Screen coordinate.
|
|
//
|
|
POINT pt;
|
|
pt.x = pt.y = 0;
|
|
ClientToScreen(m_CompWnd[i].hCompWnd, &pt);
|
|
pv->out_rcArea->left += pt.x;
|
|
pv->out_rcArea->right += pt.x;
|
|
pv->out_rcArea->top += pt.y;
|
|
pv->out_rcArea->bottom += pt.y;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::GetCompStrExtent
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::OnSetCursor(IMCLock &imc, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
POINT pt;
|
|
ULONG uEdge;
|
|
ULONG uQuadrant;
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnSetCursor. _pCicContext==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
|
|
GetCursorPos(&pt);
|
|
GetCompStrExtent(pt, &uEdge, &uQuadrant, imc);
|
|
|
|
DWORD dwBtnStatus = 0;
|
|
|
|
if (GetKeyState(VK_LBUTTON) < 0)
|
|
{
|
|
dwBtnStatus |= MK_LBUTTON;
|
|
}
|
|
if (GetKeyState(VK_MBUTTON) < 0)
|
|
{
|
|
dwBtnStatus |= MK_MBUTTON;
|
|
}
|
|
if (GetKeyState(VK_RBUTTON) < 0)
|
|
{
|
|
dwBtnStatus |= MK_RBUTTON;
|
|
}
|
|
|
|
if (_pCicContext->MsImeMouseHandler(uEdge, uQuadrant, dwBtnStatus, imc) == 1L)
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::GetCompStrExtent
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
UIComposition::GetCompStrExtent(
|
|
POINT pt,
|
|
ULONG *puEdge,
|
|
ULONG *puQuadrant,
|
|
IMCLock& imc)
|
|
{
|
|
|
|
Assert(puEdge);
|
|
Assert(puQuadrant);
|
|
*puEdge = 0;
|
|
*puQuadrant = 0;
|
|
ULONG uCount;
|
|
|
|
HRESULT hr;
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::GetCompStrExtent. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (!comp.GetOffsetPointer(comp->dwCompStrLen))
|
|
{
|
|
//
|
|
// There is no composition string.
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
|
|
if (uiwndState == IME_UIWND_LEVEL1)
|
|
{
|
|
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
|
|
|
|
POINT ptCli = pt;
|
|
ScreenToClient(m_DefCompWnd.hCompWnd, &ptCli);
|
|
hr = m_DefCompWnd.poly_text.GetPolyTextExtent(ptCli,
|
|
hDC,
|
|
FALSE,
|
|
puEdge,
|
|
puQuadrant);
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
|
|
}
|
|
else if (uiwndState == IME_UIWND_LEVEL2)
|
|
{
|
|
BOOL fVert = imc.UseVerticalCompWindow();
|
|
int i;
|
|
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
|
|
|
|
POINT ptCli = pt;
|
|
ScreenToClient(m_CompWnd[i].hCompWnd, &ptCli);
|
|
hr = m_CompWnd[i].poly_text.GetPolyTextExtent(ptCli,
|
|
hDC,
|
|
fVert,
|
|
puEdge,
|
|
puQuadrant);
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_CompWnd[i].hCompWnd, hDC);
|
|
if (hr == S_OK)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::CreateDefFrameWnd
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT UIComposition::CreateDefFrameWnd(HWND hwndParent, HIMC hIMC)
|
|
{
|
|
|
|
DWORD dwWndStyle = // UIWINDOW_TOPMOST |
|
|
UIWINDOW_HASTOOLTIP |
|
|
UIWINDOW_HABITATINWORKAREA |
|
|
UIWINDOW_WHISTLERLOOK |
|
|
UIWINDOW_TOOLWINDOW;
|
|
|
|
|
|
|
|
if (!m_pDefCompFrameWnd)
|
|
{
|
|
m_pDefCompFrameWnd = new CDefCompFrameWindow(hIMC, dwWndStyle);
|
|
if (!m_pDefCompFrameWnd)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (!m_pDefCompFrameWnd->Initialize())
|
|
{
|
|
delete m_pDefCompFrameWnd;
|
|
m_pDefCompFrameWnd = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pDefCompFrameWnd->Init();
|
|
}
|
|
|
|
m_pDefCompFrameWnd->CreateWnd(hwndParent);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::CreateCompButtonWnd
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT UIComposition::CreateCompButtonWnd(HWND hwndParent, HIMC hIMC)
|
|
{
|
|
//
|
|
// #500698
|
|
//
|
|
// no more level2 comp window in English Speech so we don't need
|
|
// finalizing button on level2.
|
|
//
|
|
TLS * ptls = TLS::GetTLS();
|
|
if (!ptls || !ptls->NonEACompositionEnabled())
|
|
return S_OK;
|
|
|
|
//
|
|
// we don't use Level2 Comp Finalizing Button for EA language.
|
|
//
|
|
if (IsEALang())
|
|
{
|
|
if (m_pCompButtonFrameWnd)
|
|
{
|
|
delete m_pCompButtonFrameWnd;
|
|
m_pCompButtonFrameWnd = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD dwWndStyle = // UIWINDOW_TOPMOST |
|
|
UIWINDOW_HASTOOLTIP |
|
|
UIWINDOW_HABITATINWORKAREA |
|
|
UIWINDOW_WHISTLERLOOK |
|
|
UIWINDOW_TOOLWINDOW |
|
|
UIWINDOW_WSBORDER;
|
|
|
|
|
|
|
|
if (!m_pCompButtonFrameWnd)
|
|
{
|
|
m_pCompButtonFrameWnd = new CCompButtonFrameWindow(hIMC, dwWndStyle);
|
|
if (!m_pCompButtonFrameWnd)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (!m_pCompButtonFrameWnd->Initialize())
|
|
{
|
|
delete m_pCompButtonFrameWnd;
|
|
m_pCompButtonFrameWnd = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pCompButtonFrameWnd->Init();
|
|
}
|
|
|
|
m_pCompButtonFrameWnd->CreateWnd(hwndParent);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UIComposition::OnPrivateGetTextExtent
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
HRESULT UIComposition::OnPrivateGetTextExtent(IMCLock& imc, TEXTEXT *ptext_ext)
|
|
{
|
|
ULONG uCount;
|
|
|
|
HRESULT hr;
|
|
|
|
if (m_bTimerCOMPOSITION == TRUE)
|
|
{
|
|
// UIWnd has already got WM_IME_COMPOSITION with new composition text, and
|
|
// set a timer for it, but the time-out value has not yet elapsed, so the new
|
|
// composition window text is not updated yet.
|
|
// But caller of GetTextExtent may assume the new text has already been in the
|
|
// composition window and try to get extent for the updated range.
|
|
//
|
|
// In this case, we need to call UpdateCompositionRect( ) to update the composition
|
|
// Rect.
|
|
UpdateCompositionRect(imc);
|
|
}
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. imc_ctfime==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. _pCicContext==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
LONG cch = 0;
|
|
if (FAILED(_pCicContext->EscbReadOnlyPropMargin(imc, NULL, &cch)))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
ptext_ext->acpStart -= cch;
|
|
ptext_ext->acpEnd -= cch;
|
|
|
|
if (ptext_ext->prc)
|
|
memset(ptext_ext->prc, 0, sizeof(*ptext_ext->prc));
|
|
if (ptext_ext->pfClipped)
|
|
*ptext_ext->pfClipped = FALSE;
|
|
|
|
IMCCLock<COMPOSITIONSTRING> comp(imc->hCompStr);
|
|
if (FAILED(hr=comp.GetResult()))
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("UIComposition::OnPrivateGetTextExtent. comp==NULL"));
|
|
return hr;
|
|
}
|
|
|
|
if (!comp.GetOffsetPointer(comp->dwCompStrLen))
|
|
{
|
|
//
|
|
// There is no composition string.
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
// If the requested range is beyond the composition window,
|
|
// just return the position based on the real window.
|
|
|
|
// this is hack for CHS/CHT TIP's special design.
|
|
if (ptext_ext->acpStart > (LONG)(comp->dwCompStrLen))
|
|
ptext_ext->acpStart = (LONG)(comp->dwCompStrLen);
|
|
|
|
if (ptext_ext->acpEnd > (LONG)(comp->dwCompStrLen))
|
|
ptext_ext->acpEnd = (LONG)(comp->dwCompStrLen);
|
|
|
|
RECT rcStart = {0};
|
|
RECT rcEnd = {0};
|
|
HRESULT hrStart = S_FALSE;
|
|
HRESULT hrEnd = S_FALSE;
|
|
|
|
IME_UIWND_STATE uiwndState = GetLevelFromIMC(imc);
|
|
if (uiwndState == IME_UIWND_LEVEL1)
|
|
{
|
|
HDC hDC = GetDC(m_DefCompWnd.hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel1);
|
|
|
|
DWORD acpStart = ptext_ext->acpStart;
|
|
DWORD acpEnd = ptext_ext->acpEnd;
|
|
hrStart = m_DefCompWnd.poly_text.GetPolyTextExtentRect(acpStart, hDC, FALSE, TRUE, &rcStart);
|
|
|
|
if (hrStart == S_OK)
|
|
m_DefCompWnd._ClientToScreen(&rcStart);
|
|
|
|
hrEnd = m_DefCompWnd.poly_text.GetPolyTextExtentRect(acpEnd, hDC, FALSE, TRUE, &rcEnd);
|
|
|
|
if (hrEnd == S_OK)
|
|
m_DefCompWnd._ClientToScreen(&rcEnd);
|
|
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_DefCompWnd.hCompWnd, hDC);
|
|
|
|
}
|
|
else if (uiwndState == IME_UIWND_LEVEL2)
|
|
{
|
|
DWORD acpStart;
|
|
DWORD acpEnd;
|
|
BOOL fVert;
|
|
BOOL fGetLast = FALSE;
|
|
int i;
|
|
|
|
TryWithLast:
|
|
acpStart = ptext_ext->acpStart;
|
|
acpEnd = ptext_ext->acpEnd;
|
|
|
|
fVert = imc.UseVerticalCompWindow();
|
|
|
|
for (i=0; i < sizeof(m_CompWnd)/sizeof(COMPWND); i++)
|
|
{
|
|
HDC hDC = GetDC(m_CompWnd[i].hCompWnd);
|
|
HFONT hFontOrg = (HFONT)SelectObject(hDC, m_hFontLevel2);
|
|
|
|
if (hrStart != S_OK)
|
|
{
|
|
hrStart = m_CompWnd[i].poly_text.GetPolyTextExtentRect(acpStart, hDC, fVert, fGetLast, &rcStart);
|
|
if (hrStart == S_OK)
|
|
m_CompWnd[i]._ClientToScreen(&rcStart);
|
|
}
|
|
|
|
if (hrEnd != S_OK)
|
|
{
|
|
hrEnd = m_CompWnd[i].poly_text.GetPolyTextExtentRect(acpEnd, hDC, fVert, fGetLast, &rcEnd);
|
|
if (hrEnd == S_OK)
|
|
m_CompWnd[i]._ClientToScreen(&rcEnd);
|
|
}
|
|
|
|
SelectObject(hDC, hFontOrg);
|
|
ReleaseDC(m_CompWnd[i].hCompWnd, hDC);
|
|
if ((hrStart == S_OK) && (hrEnd == S_OK))
|
|
break;
|
|
}
|
|
|
|
if (!fGetLast && (hrStart != S_OK))
|
|
{
|
|
fGetLast = TRUE;
|
|
goto TryWithLast;
|
|
}
|
|
|
|
}
|
|
|
|
if (hrStart == S_OK)
|
|
{
|
|
if (hrEnd == S_OK)
|
|
{
|
|
ptext_ext->prc->left = min(rcStart.left , rcEnd.left);
|
|
ptext_ext->prc->top = min(rcStart.top , rcEnd.top);
|
|
ptext_ext->prc->bottom = max(rcStart.bottom , rcEnd.bottom);
|
|
ptext_ext->prc->right = max(rcStart.right , rcEnd.right);
|
|
}
|
|
else
|
|
{
|
|
ptext_ext->prc->left = rcStart.left;
|
|
ptext_ext->prc->top = rcStart.top;
|
|
ptext_ext->prc->bottom = rcStart.bottom;
|
|
ptext_ext->prc->right = rcStart.right;
|
|
}
|
|
}
|
|
|
|
return hrStart;
|
|
}
|