|
|
/*
* @doc INTERNAL * * @module HOST.C -- Text Host for CreateWindow() Rich Edit Control | * Implements CTxtWinHost message and ITextHost interfaces * * Original Author: <nl> * Original RichEdit code: David R. Fulmer * Christian Fortini * Murray Sargent * * History: <nl> * 8/1/95 ricksa Documented and brought to new ITextHost definition * 10/28/95 murrays cleaned up and moved default char/paraformat cache * cache code into text services * * Set tabs every four (4) columns * * Copyright (c) 1995-1998 Microsoft Corporation. All rights reserved. */ #include "_common.h"
#include "_host.h"
#include "imm.h"
#include "_format.h"
#include "_edit.h"
#include "_cfpf.h"
ASSERTDATA
//////////////////////////// System Window Procs ////////////////////////////
LRESULT CreateAnsiWindow( HWND hwnd, UINT msg, CREATESTRUCTA *pcsa, BOOL fIs10) { AssertSz((WM_CREATE == msg) || (WM_NCCREATE == msg), "CreateAnsiWindow called with invalid message!");
CTxtWinHost *phost = (CTxtWinHost *) GetWindowLongPtr(hwnd, ibPed);
// The only thing we need to convert are the strings,
// so just do a structure copy and replace the strings.
CREATESTRUCTW csw = *(CREATESTRUCTW *)pcsa; CStrInW strinwName(pcsa->lpszName, GetKeyboardCodePage()); CStrInW strinwClass(pcsa->lpszClass, CP_ACP);
csw.lpszName = (WCHAR *)strinwName; csw.lpszClass = (WCHAR *)strinwClass;
if (!phost) { // No host yet so create it
phost = CTxtWinHost::OnNCCreate(hwnd, &csw, TRUE, fIs10); }
if (WM_NCCREATE == msg) { return phost != NULL; }
if (NULL == phost) { // For WM_CREATE -1 indicates failure
return -1; }
// Do the stuff specific to create
return phost->OnCreate(&csw); }
CTxtWinHost *g_phostdel = NULL;
void DeleteDanglingHosts() { CLock lock; CTxtWinHost *phostdel = g_phostdel; while(phostdel) { CTxtWinHost *phost = phostdel; phostdel = phostdel->_pnextdel; CTxtWinHost::OnNCDestroy(phost); } g_phostdel = NULL; }
extern "C" LRESULT CALLBACK RichEdit10ANSIWndProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { TRACEBEGINPARAM(TRCSUBSYSHOST, TRCSCOPEINTERN, "RichEdit10ANSIWndProc", msg);
if ((WM_CREATE == msg) || (WM_NCCREATE == msg)) { return CreateAnsiWindow(hwnd, msg, (CREATESTRUCTA *) lparam, TRUE); }
// ignore WM_DESTROY and wait for WM_NCDESTROY
if (WM_DESTROY == msg) { CLock lock; CTxtWinHost *phost = (CTxtWinHost *) GetWindowLongPtr(hwnd, ibPed); phost->_pnextdel = g_phostdel; g_phostdel = phost; return 0; }
if (WM_NCDESTROY == msg) msg = WM_DESTROY;
return W32->ANSIWndProc( hwnd, msg, wparam, lparam, TRUE); }
LRESULT CALLBACK RichEditANSIWndProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { TRACEBEGINPARAM(TRCSUBSYSHOST, TRCSCOPEINTERN, "RichEditANSIWndProc", msg);
if ((WM_CREATE == msg) || (WM_NCCREATE == msg)) { return CreateAnsiWindow(hwnd, msg, (CREATESTRUCTA *) lparam, FALSE); }
return W32->ANSIWndProc( hwnd, msg, wparam, lparam, FALSE);
}
/*
* RichEditWndProc (hwnd, msg, wparam, lparam) * * @mfunc * Handle window messages pertinent to the host and pass others on to * text services. * * #rdesc * LRESULT = (code processed) ? 0 : 1 */ LRESULT CALLBACK RichEditWndProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "RichEditWndProc");
LRESULT lres = 0; HRESULT hr; SETTEXTEX st;
CTxtWinHost *phost = hwnd ? (CTxtWinHost *) GetWindowLongPtr(hwnd, ibPed) : NULL;
#ifdef DEBUG
Tracef(TRCSEVINFO, "hwnd %lx, msg %lx, wparam %lx, lparam %lx", hwnd, msg, wparam, lparam); #endif // DEBUG
switch(msg) { case WM_NCCREATE: return CTxtWinHost::OnNCCreate(hwnd, (CREATESTRUCT *)lparam, FALSE, FALSE) != NULL;
case WM_CREATE: // We may be on a system with no WM_NCCREATE (e.g. WinCE)
if (!phost) { phost = CTxtWinHost::OnNCCreate(hwnd, (CREATESTRUCT *) lparam, FALSE, FALSE); }
break;
case WM_DESTROY: if(phost) { CLock lock; CTxtWinHost *phostdel = g_phostdel; if (phostdel == phost) g_phostdel = phost->_pnextdel; else { while (phostdel) { if (phostdel->_pnextdel == phost) { phostdel->_pnextdel = phost->_pnextdel; break; } phostdel = phostdel->_pnextdel; } }
CTxtWinHost::OnNCDestroy(phost); } return 0; }
if (!phost) return ::DefWindowProc(hwnd, msg, wparam, lparam);
// In certain out-of-memory situations, clients may try to re-enter us
// with calls. Just bail on the call if we don't have a text services
// pointer.
if(!phost->_pserv) return 0;
// stabilize ourselves
phost->AddRef();
// Handle mouse/keyboard/scroll message-filter notifications
if(phost->_fKeyMaskSet || phost->_fMouseMaskSet || phost->_fScrollMaskSet) { // We may need to fire a MSGFILTER notification. In the tests
// below, we check to see if mouse, keyboard, or scroll events
// are hit and enabled for notifications. If so, we fire the
// msgfilter notification. The list of events was generated
// from RichEdit 1.0 sources. The code gets all keyboard and
// mouse actions, whereas the RichEdit 1.0 code only got
// WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_SYSKEYDOWN, WM_SYSKEYUP,
// WM_MOUSEACTIVATE, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE,
// WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP. Note that the
// following code doesn't send a notification for AltGr characters
// (LeftCtrl+RightAlt+vkey), since some hosts misinterpret these
// characters as hot keys.
if (phost->_fKeyMaskSet && IN_RANGE(WM_KEYFIRST, msg, WM_KEYLAST) && (msg != WM_KEYDOWN || (GetKeyboardFlags() & (ALT | CTRL)) != (LCTRL | RALT)) || // AltGr
phost->_fMouseMaskSet && (msg == WM_MOUSEACTIVATE || IN_RANGE(WM_MOUSEFIRST, msg, WM_MOUSELAST)) || phost->_fScrollMaskSet && IN_RANGE(WM_HSCROLL, msg, WM_VSCROLL)) { MSGFILTER msgfltr;
ZeroMemory(&msgfltr.nmhdr, sizeof(NMHDR)); msgfltr.msg = msg; msgfltr.wParam = wparam; msgfltr.lParam = lparam;
// The MSDN document on MSGFILTER is wrong, if the
// send message returns 0 (NOERROR via TxNotify in this
// case), it means process the event. Otherwise, return.
//
// The documentation states the reverse.
//
if(phost->TxNotify(EN_MSGFILTER, &msgfltr) == NOERROR) { // Since client is allowed to modify the contents of
// msgfltr, we must use the returned values.
msg = msgfltr.msg; wparam = msgfltr.wParam; lparam = msgfltr.lParam; } else { lres = ::DefWindowProc(hwnd, msg, wparam, lparam); goto Exit; } } }
switch(msg) { case EM_SETEVENTMASK: phost->_fKeyMaskSet = !!(lparam & ENM_KEYEVENTS); phost->_fMouseMaskSet = !!(lparam & ENM_MOUSEEVENTS); phost->_fScrollMaskSet = !!(lparam & ENM_SCROLLEVENTS); goto serv;
case EM_SETSEL:
// When we are in a dialog box that is empty, EM_SETSEL will not select
// the final always existing EOP if the control is rich.
if (phost->_fUseSpecialSetSel && ((CTxtEdit *)phost->_pserv)->GetAdjustedTextLength() == 0 && wparam != -1) { lparam = 0; wparam = 0; } goto serv;
case WM_CREATE: { //bug fix #5386
//need to convert ANSI -> UNICODE for Win9x systems which didn't go through
//the ANSI wndProc
if (W32->OnWin9x() && !phost->_fANSIwindow) { CREATESTRUCT cs = *(CREATESTRUCT*)lparam; CStrInW strinwName(((CREATESTRUCTA*)lparam)->lpszName, GetKeyboardCodePage()); CStrInW strinwClass(((CREATESTRUCTA*)lparam)->lpszClass, CP_ACP);
cs.lpszName = (WCHAR*)strinwName; cs.lpszClass = (WCHAR*)strinwClass; lres = phost->OnCreate(&cs); } else lres = phost->OnCreate((CREATESTRUCT*)lparam); } break; case WM_KEYDOWN: lres = phost->OnKeyDown((WORD) wparam, (DWORD) lparam); if(lres) // Didn't process code:
goto serv; // give it to text services
break;
case WM_GETTEXT: GETTEXTEX gt; if (W32->OnWin9x() || phost->_fANSIwindow) W32->AnsiFilter( msg, wparam, lparam, (void *) > ); goto serv;
case WM_COPYDATA: PCOPYDATASTRUCT pcds; pcds = (PCOPYDATASTRUCT) lparam; if (HIWORD(pcds->dwData) == 1200 && // Unicode code page
LOWORD(pcds->dwData) == WM_SETTEXT) // Only message we know about
{ st.flags = ST_CHECKPROTECTION; st.codepage = 1200; msg = EM_SETTEXTEX; wparam = (WPARAM) &st; lparam = (LPARAM) pcds->lpData; goto serv; } else lres = ::DefWindowProc(hwnd, msg, wparam, lparam); break;
case WM_GETTEXTLENGTH: GETTEXTLENGTHEX gtl; if (W32->OnWin9x() || phost->_fANSIwindow) W32->AnsiFilter( msg, wparam, lparam, (void *) >l ); goto serv;
case WM_CHAR: if(GetKeyboardFlags() & ALTNUMPAD) // Handle Alt+0ddd in CTxtEdit
goto serv; // so that other hosts also work
else if (W32->OnWin9x() || phost->_fANSIwindow) { CW32System::WM_CHAR_INFO wmci; wmci._fAccumulate = phost->_fAccumulateDBC != 0; W32->AnsiFilter( msg, wparam, lparam, (void *) &wmci, ((CTxtEdit *)phost->_pserv)->Get10Mode() ); if (wmci._fLeadByte) { phost->_fAccumulateDBC = TRUE; phost->_chLeadByte = wparam << 8; goto Exit; // Wait for trail byte
} else if (wmci._fTrailByte) { wparam = phost->_chLeadByte | wparam; phost->_fAccumulateDBC = FALSE; phost->_chLeadByte = 0; msg = WM_IME_CHAR; goto serv; } else if (wmci._fIMEChar) { msg = WM_IME_CHAR; goto serv; } }
lres = phost->OnChar((WORD) wparam, (DWORD) lparam); if(lres) // Didn't process code:
goto serv; // give it to text services
break;
case WM_ENABLE: if(!wparam ^ phost->_fDisabled) { // Stated of window changed so invalidate it so it will
// get redrawn.
InvalidateRect(phost->_hwnd, NULL, TRUE); phost->SetScrollBarsForWmEnable(wparam); } phost->_fDisabled = !wparam; // Set disabled flag
lres = 0; // Return value for message
// Fall thru to WM_SYSCOLORCHANGE?
case WM_SYSCOLORCHANGE: phost->OnSysColorChange(); goto serv; // Notify text services that
// system colors have changed
case WM_GETDLGCODE: lres = phost->OnGetDlgCode(wparam, lparam); break;
case EM_GETOPTIONS: lres = phost->OnGetOptions(); break;
case EM_GETPASSWORDCHAR: lres = phost->_chPassword; break;
case EM_GETRECT: phost->OnGetRect((LPRECT)lparam); break;
case EM_HIDESELECTION: if(lparam) { DWORD dwPropertyBits = 0;
phost->_dwStyle |= ES_NOHIDESEL; if(wparam) { phost->_dwStyle &= ~ES_NOHIDESEL; dwPropertyBits = TXTBIT_HIDESELECTION; }
// Notify text services of change in status.
phost->_pserv->OnTxPropertyBitsChange(TXTBIT_HIDESELECTION, dwPropertyBits); } goto serv;
case EM_SETBKGNDCOLOR: lres = (LRESULT) phost->_crBackground; phost->_fNotSysBkgnd = !wparam; phost->_crBackground = (COLORREF) lparam;
if(wparam) phost->_crBackground = GetSysColor(COLOR_WINDOW);
if(lres != (LRESULT) phost->_crBackground) { // Notify text services that color has changed
LRESULT lres1 = 0; phost->_pserv->TxSendMessage(WM_SYSCOLORCHANGE, 0, 0, &lres1); phost->TxInvalidateRect(NULL, TRUE); } break;
case WM_STYLECHANGING: // Just pass this one to the default window proc
lres = ::DefWindowProc(hwnd, msg, wparam, lparam); break;
case WM_STYLECHANGED: //
// For now, we only interested in GWL_EXSTYLE Transparent mode changed.
// This is to fix Bug 753 since Window95 is not passing us
// the WS_EX_TRANSPARENT.
//
lres = 1; if(GWL_EXSTYLE == wparam) { LPSTYLESTRUCT lpss = (LPSTYLESTRUCT) lparam; if(phost->IsTransparentMode() != (BOOL)(lpss->styleNew & WS_EX_TRANSPARENT)) { phost->_dwExStyle = lpss->styleNew; ((CTxtEdit *)phost->_pserv)->OnTxBackStyleChange(TRUE);
// Return 0 to indicate we have handled this message
lres = 0; } } break;
case EM_SHOWSCROLLBAR: { Assert(wparam == SB_VERT || wparam == SB_HORZ); DWORD dwBit = wparam == SB_VERT ? WS_VSCROLL : WS_HSCROLL;
phost->_dwStyle |= dwBit; if(!lparam) phost->_dwStyle &= ~dwBit;
phost->TxShowScrollBar((int) wparam, lparam); if (lparam) phost->TxSetScrollRange((int) wparam, 0, 0, TRUE); } break;
case EM_SETOPTIONS: phost->OnSetOptions((WORD) wparam, (DWORD) lparam); lres = (phost->_dwStyle & ECO_STYLES); if(phost->_fEnableAutoWordSel) lres |= ECO_AUTOWORDSELECTION; break;
case EM_SETPASSWORDCHAR: if(phost->_chPassword != (TCHAR)wparam) { phost->_chPassword = (TCHAR)wparam; phost->_pserv->OnTxPropertyBitsChange(TXTBIT_USEPASSWORD, phost->_chPassword ? TXTBIT_USEPASSWORD : 0); } break;
case EM_SETREADONLY: phost->OnSetReadOnly(BOOL(wparam)); lres = 1; break;
case EM_SETRECTNP: case EM_SETRECT: phost->OnSetRect((LPRECT)lparam, wparam == 1, msg == EM_SETRECT); break; case WM_SIZE: phost->_pserv->TxSendMessage(msg, wparam, lparam, &lres); lres = phost->OnSize(hwnd, wparam, (int)LOWORD(lparam), (int)HIWORD(lparam)); break;
case WM_WINDOWPOSCHANGING: lres = ::DefWindowProc(hwnd, msg, wparam, lparam); // richedit 1.0 didn't cause InvalidateRect which OnSunkenWindowPosChanging will do
if(phost->TxGetEffects() == TXTEFFECT_SUNKEN && !((CTxtEdit *)phost->_pserv)->Get10Mode()) phost->OnSunkenWindowPosChanging(hwnd, (WINDOWPOS *) lparam); break;
case WM_SETCURSOR: // Only set cursor when over us rather than a child; this
// helps prevent us from fighting it out with an inplace child
if((HWND)wparam == hwnd) { if(!(lres = ::DefWindowProc(hwnd, msg, wparam, lparam))) { POINT pt; GetCursorPos(&pt); ::ScreenToClient(hwnd, &pt); phost->_pserv->OnTxSetCursor( DVASPECT_CONTENT, -1, NULL, NULL, NULL, NULL, NULL, // Client rect - no redraw
pt.x, pt.y); lres = TRUE; } } break;
case WM_SHOWWINDOW: hr = phost->OnTxVisibleChange((BOOL)wparam); break;
case WM_NCPAINT: lres = ::DefWindowProc(hwnd, msg, wparam, lparam); if(phost->TxGetEffects() == TXTEFFECT_SUNKEN && dwMajorVersion < VERS4) { HDC hdc = GetDC(hwnd); if(hdc) { phost->DrawSunkenBorder(hwnd, hdc); ReleaseDC(hwnd, hdc); } } break;
case WM_PRINTCLIENT: case WM_PAINT: { PAINTSTRUCT ps; HPALETTE hpalOld = NULL; HDC hdc = BeginPaint(hwnd, &ps); RECT rcClient;
// Set up the palette for drawing our data
if(phost->_hpal) { hpalOld = SelectPalette(hdc, phost->_hpal, TRUE); RealizePalette(hdc); }
// Since we are using the CS_PARENTDC style, make sure
// the clip region is limited to our client window.
GetClientRect(hwnd, &rcClient); SaveDC(hdc); IntersectClipRect(hdc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
#if 0 // Useful for debugging
TCHAR rgch[512]; wsprintf(rgch, TEXT("Paint : (%d, %d, %d, %d)\n"), rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); OutputDebugString(rgch); #endif
phost->_pserv->TxDraw( DVASPECT_CONTENT, // Draw Aspect
-1, // Lindex
NULL, // Info for drawing optimazation
NULL, // target device information
hdc, // Draw device HDC
NULL, // Target device HDC
(const RECTL *) &rcClient,// Bounding client rectangle
NULL, // Clipping rectangle for metafiles
&ps.rcPaint, // Update rectangle
NULL, // Call back function
NULL, // Call back parameter
TXTVIEW_ACTIVE); // What view - the active one!
// Restore palette if there is one
#ifndef PEGASUS
if(hpalOld) SelectPalette(hdc, hpalOld, TRUE); #endif
if(phost->TxGetEffects() == TXTEFFECT_SUNKEN && dwMajorVersion < VERS4) phost->DrawSunkenBorder(hwnd, hdc);
RestoreDC(hdc, -1); EndPaint(hwnd, &ps); } break;
case EM_SETMARGINS:
phost->OnSetMargins(wparam, LOWORD(lparam), HIWORD(lparam)); break;
case EM_SETPALETTE:
// Application is setting a palette for us to use.
phost->_hpal = (HPALETTE) wparam;
// Invalidate the window & repaint to reflect the new palette.
InvalidateRect(hwnd, NULL, FALSE); break;
default: serv: hr = phost->_pserv->TxSendMessage(msg, wparam, lparam, &lres); if(hr == S_FALSE) { // Message was not processed by text services so send it
// to the default window proc.
lres = ::DefWindowProc(hwnd, msg, wparam, lparam); } }
Exit: phost->Release(); return lres; } static BOOL GetIconic( HWND hwnd) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetIconic");
while(hwnd) { if(IsIconic(hwnd)) return TRUE; hwnd = GetParent(hwnd); } return FALSE; }
//////////////// CTxtWinHost Creation/Initialization/Destruction ///////////////////////
/*
* CTxtWinHost::OnNCCreate (hwnd, pcs) * * @mfunc * Static global method to handle WM_NCCREATE message (see remain.c) */ CTxtWinHost *CTxtWinHost::OnNCCreate( HWND hwnd, const CREATESTRUCT *pcs, BOOL fIsAnsi, BOOL fIs10Mode) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnNCCreate");
#if defined DEBUG && !defined(PEGASUS)
GdiSetBatchLimit(1); #endif
CTxtWinHost *phost = new CTxtWinHost();
if(!phost) return 0;
CREATESTRUCT cs = *pcs; // prefer C++ compiler not to modify constant
//bug fix #5386
// Window wasn't created with the Richedit20A window class
// and we are under Win9x, need to convert string to UNICODE
CStrInW strinwName(((LPSTR)pcs->lpszName), GetKeyboardCodePage()); CStrInW strinwClass(((LPSTR)pcs->lpszClass), CP_ACP); if (!fIsAnsi && W32->OnWin9x()) { cs.lpszName = (WCHAR *)strinwName; cs.lpszClass = (WCHAR *)strinwClass; }
// Stores phost in associated window data
if(!phost->Init(hwnd, (const CREATESTRUCT*)&cs, fIsAnsi, fIs10Mode)) { phost->Shutdown(); delete phost; phost = NULL; } return phost; }
/*
* CTxtWinHost::OnNCDestroy (phost) * * @mfunc * Static global method to handle WM_CREATE message * * @devnote * phost ptr is stored in window data (GetWindowLong()) */ void CTxtWinHost::OnNCDestroy( CTxtWinHost *phost) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnNCDestroy");
phost->Shutdown(); phost->Release(); }
/*
* CTxtWinHost::CTxtWinHost() * * @mfunc * constructor */ CTxtWinHost::CTxtWinHost() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::CTxtWinHost");
#ifndef NOACCESSIBILITY
_pTypeInfo = NULL; #endif
_fRegisteredForDrop = FALSE; _crefs = 1; if(!_fNotSysBkgnd) _crBackground = GetSysColor(COLOR_WINDOW); }
/*
* CTxtWinHost::~CTxtWinHost() * * @mfunc * destructor */ CTxtWinHost::~CTxtWinHost() { AssertSz(_pserv == NULL, "CTxtWinHost::~CTxtWinHost - shutdown not called till destructor");
if(_pserv) Shutdown(); }
/*
* CTxtWinHost::Shutdown() * * @mfunc Shut down this object, but doesn't delete memory */ void CTxtWinHost::Shutdown() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::Shutdown"); ITextServices *pserv; HostRevokeDragDrop(); // Revoke our drop target
if(_pserv) { // Guarantee that no recursive callbacks can happen during shutdown.
pserv = _pserv; _pserv = NULL;
pserv->OnTxInPlaceDeactivate(); pserv->Release();
// Host release was not the final release so notify
// text services that they need to keep their reference
// to the host valid.
if (!_fTextServiceFree) { ((CTxtEdit *)pserv)->SetReleaseHost();
} }
ImmTerminate(); // Terminate only useful on Mac.
if(_hwnd) SetWindowLongPtr(_hwnd, ibPed, 0); }
/*
* CTxtWinHost::Init (hwnd, pcs) * * @mfunc * Initialize this CTxtWinHost */ BOOL CTxtWinHost::Init( HWND hwnd, //@parm Window handle for this control
const CREATESTRUCT *pcs, //@parm Corresponding CREATESTRUCT
BOOL fIsAnsi, //@parm is ansi window
BOOL fIs10Mode) //@parm is 1.0 mode window
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::Init");
AssertSz(!fIs10Mode || (fIsAnsi && fIs10Mode), "CTxtWinHost::Init input flags are out of sync!");
if(!pcs->lpszClass) return FALSE;
// Set pointer back to CTxtWinHost from the window
if(hwnd) SetWindowLongPtr(hwnd, ibPed, (INT_PTR)this); _hwnd = hwnd;
// Here we want to keep track of the "RichEdit20A"window class
// The RICHEDIT window class is handled by a wrapper dll.
// If the class name is "RICHEDIT", then we need to turn on the
// RichEdit 1.0 compatibility bit. IsAnsiWindowClass tests that class as well.
_fANSIwindow = fIsAnsi;
// Edit controls created without a window are multiline by default
// so that paragraph formats can be
_dwStyle = ES_MULTILINE; _fHidden = TRUE; if(pcs) { _hwndParent = pcs->hwndParent; _dwExStyle = pcs->dwExStyle; _dwStyle = pcs->style;
if (!fIs10Mode) { // Only set this for 2.0 windows
// According to the edit control documentation WS_HSCROLL implies that
// ES_AUTOSCROLL is set and WS_VSCROLL implies that ES_AUTOVSCROLL is
// set. Here, we make this so.
if(_dwStyle & WS_HSCROLL) _dwStyle |= ES_AUTOHSCROLL;
// handle default disabled
if(_dwStyle & WS_DISABLED) _fDisabled = TRUE; } else { if (GetBkMode(GetDC(hwnd)) == TRANSPARENT) { _dwExStyle |= WS_EX_TRANSPARENT; } else { _dwExStyle &= ~WS_EX_TRANSPARENT; } }
if(_dwStyle & WS_VSCROLL) _dwStyle |= ES_AUTOVSCROLL;
_fBorder = !!(_dwStyle & WS_BORDER);
if((_dwStyle & ES_SUNKEN) || (_dwExStyle & WS_EX_CLIENTEDGE)) _fBorder = TRUE;
// handle default passwords
if(_dwStyle & ES_PASSWORD) _chPassword = TEXT('*');
// On Win95 ES_SUNKEN and WS_BORDER get mapped to WS_EX_CLIENTEDGE
if(_fBorder && dwMajorVersion >= VERS4) { _dwExStyle |= WS_EX_CLIENTEDGE; SetWindowLong(_hwnd, GWL_EXSTYLE, _dwExStyle); }
// Process some flags for mirrored control
if (_dwExStyle & WS_EX_LAYOUTRTL) { // Swap whatever RTL params we have
_dwStyle = (_dwStyle & ~ES_RIGHT) | (_dwStyle & ES_RIGHT ^ ES_RIGHT); _dwExStyle = (_dwExStyle & ~WS_EX_RTLREADING) | (_dwExStyle & WS_EX_RTLREADING ^ WS_EX_RTLREADING); _dwExStyle = (_dwExStyle & ~WS_EX_LEFTSCROLLBAR) | (_dwStyle & ES_RIGHT ? WS_EX_LEFTSCROLLBAR : 0); // Disable mirroring layout to avoid GDI mirroring mapping mode
_dwExStyle &= ~WS_EX_LAYOUTRTL; SetWindowLong(_hwnd, GWL_STYLE, _dwStyle); SetWindowLong(_hwnd, GWL_EXSTYLE, _dwExStyle); } }
// Create Text Services component
// Watch out for sys param and sys font initialization!! see below.
if(FAILED(CreateTextServices())) return FALSE;
_xInset = (char)W32->GetCxBorder(); _yInset = (char)W32->GetCyBorder();
if (!_fBorder) { _xInset += _xInset; _yInset += _yInset; }
// At this point the border flag is set and so is the pixels per inch
// so we can initalize the inset.
// This must be done after CreatingTextServices so sys params are valid
SetDefaultInset();
// Set alignment and paragraph direction
PARAFORMAT PF2; PF2.dwMask = 0;
BOOL fRCAlign = _dwStyle & (ES_RIGHT | ES_CENTER) || _dwExStyle & WS_EX_RIGHT; if(fRCAlign) { PF2.dwMask |= PFM_ALIGNMENT; PF2.wAlignment = (WORD)(_dwStyle & ES_CENTER ? PFA_CENTER : PFA_RIGHT); // right or center-aligned
}
if(_dwExStyle & WS_EX_RTLREADING) { PF2.dwMask |= PFM_RTLPARA; PF2.wEffects = PFE_RTLPARA; // RTL reading order
}
if (PF2.dwMask) { PF2.cbSize = sizeof(PARAFORMAT2); // tell text services
_pserv->TxSendMessage(EM_SETPARAFORMAT, SPF_SETDEFAULT, (LPARAM)&PF2, NULL); }
if (fIs10Mode) { ((CTxtEdit *)_pserv)->Set10Mode(); // Remove the WS_VSCROLL and WS_HSCROLL initially
if (_hwnd && !(_dwStyle & ES_DISABLENOSCROLL)) { SetScrollRange(_hwnd, SB_VERT, 0, 0, TRUE); SetScrollRange(_hwnd, SB_HORZ, 0, 0, TRUE); DWORD dwStyle = _dwStyle & ~(WS_VSCROLL | WS_HSCROLL); SetWindowLong(_hwnd, GWL_STYLE, dwStyle);
// bug fix:
// On some systems, ie Digital PII-266, we don't get a WM_PAINT message
// when we change the window style. So force a WM_PAINT into the message queue
InvalidateRect(_hwnd, NULL, TRUE); } }
// Set window text
if(pcs && pcs->lpszName) { if(FAILED(_pserv->TxSetText((TCHAR *)pcs->lpszName))) { SafeReleaseAndNULL((IUnknown **)&_pserv); return FALSE; } }
if(_dwStyle & ES_LOWERCASE) _pserv->TxSendMessage(EM_SETEDITSTYLE, SES_LOWERCASE, SES_LOWERCASE | SES_UPPERCASE, NULL);
if(!ImmInitialize()) // Mac Only
{ #if defined(DEBUG) && defined(MACPORT)
OutputDebugString(TEXT("Could not register Imm ImmInitializeForMac.\r\n")); #endif // DEBUG
}
return TRUE; }
HRESULT CTxtWinHost::CreateTextServices() { IUnknown *pUnk; HRESULT hr = ::CreateTextServices(NULL, this, &pUnk);
if(hr != NOERROR) return hr;
// Get text services interface
hr = pUnk->QueryInterface(IID_ITextServices, (void **)&_pserv);
// Regardless of whether the previous call succeeded or failed, we are
// done with the private interface.
pUnk->Release();
if(hr == NOERROR) { ((CTxtEdit *)_pserv)->_fInOurHost = TRUE; // FE extended styles might set the fFE bit
if(_dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)) _pserv->TxSendMessage(EM_SETEDITSTYLE, SES_BIDI, SES_BIDI, NULL); }
return hr; }
/*
* CTxtWinHost::OnCreate (pcs) * * @mfunc * Handle WM_CREATE message * * @rdesc * LRESULT = -1 if failed to in-place activate; else 0 */ LRESULT CTxtWinHost::OnCreate( const CREATESTRUCT *pcs) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnCreate");
RECT rcClient;
// sometimes, these values are -1 (from windows itself); just treat them
// as zero in that case
LONG cy = (pcs->cy < 0) ? 0 : pcs->cy; LONG cx = (pcs->cx < 0) ? 0 : pcs->cx;
rcClient.top = pcs->y; rcClient.bottom = rcClient.top + cy; rcClient.left = pcs->x; rcClient.right = rcClient.left + cx; // Notify Text Services that we are in place active
if(FAILED(_pserv->OnTxInPlaceActivate(&rcClient))) return -1;
DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE); // Hide all scrollbars to start
if(_hwnd && !(dwStyle & ES_DISABLENOSCROLL) && !((CTxtEdit *)_pserv)->Get10Mode()) { SetScrollRange(_hwnd, SB_VERT, 0, 0, TRUE); SetScrollRange(_hwnd, SB_HORZ, 0, 0, TRUE);
dwStyle &= ~(WS_VSCROLL | WS_HSCROLL); SetWindowLong(_hwnd, GWL_STYLE, dwStyle); }
if(!(dwStyle & (ES_READONLY | ES_NOOLEDRAGDROP))) { // This isn't a read only window or a no drop window,
// so we need a drop target.
HostRegisterDragDrop(); }
_usIMEMode = 0; if(dwStyle & ES_NOIME) { _usIMEMode = ES_NOIME; // Tell textservices to turnoff ime
_pserv->TxSendMessage(EM_SETEDITSTYLE, SES_NOIME, SES_NOIME, NULL); } else if(dwStyle & ES_SELFIME) _usIMEMode = ES_SELFIME;
return 0; }
///////////////////////////////// IUnknown ////////////////////////////////
HRESULT CTxtWinHost::QueryInterface(REFIID riid, void **ppv) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::QueryInterface");
if(IsEqualIID(riid, IID_IUnknown)) *ppv = (IUnknown *)(ITextHost2*)this;
else if(IsEqualIID(riid, IID_ITextHost) ) *ppv = (ITextHost *)(CTxtWinHost*)this;
else if(IsEqualIID(riid, IID_ITextHost2) ) *ppv = (ITextHost2 *)(CTxtWinHost*)this;
else *ppv = NULL;
if(*ppv) { AddRef(); return NOERROR; } return E_NOINTERFACE; }
ULONG CTxtWinHost::AddRef(void) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::AddRef");
return ++_crefs; }
ULONG CTxtWinHost::Release(void) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::Release");
--_crefs;
if(!_crefs) { #ifndef NOACCESSIBILITY
if(_pTypeInfo) { _pTypeInfo->Release(); _pTypeInfo = NULL; } #endif
delete this; return 0; } return _crefs; }
//////////////////////////////// Activation ////////////////////////////////
//////////////////////////////// Properties ////////////////////////////////
TXTEFFECT CTxtWinHost::TxGetEffects() const { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::TxGetEffects");
if((_dwStyle & ES_SUNKEN) || (_dwExStyle & WS_EX_CLIENTEDGE)) return TXTEFFECT_SUNKEN;
return TXTEFFECT_NONE; }
/////////////////////////////// Keyboard Messages //////////////////////////////////
/*
* CTxtWinHost::OnKeyDown (vkey, dwFlags) * * @mfunc * Handle WM_KEYDOWN messages that need to send a message to the parent * window (may happen when control is in a dialog box) * * #rdesc * LRESULT = (code processed) ? 0 : 1 */ LRESULT CTxtWinHost::OnKeyDown( WORD vkey, //@parm WM_KEYDOWN wparam (virtual key code)
DWORD dwFlags) //@parm WM_KEYDOWN flags
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnKeyDown");
if(!_fInDialogBox) // Not in a dialog box
return 1; // Signal key-down msg not processed
DWORD dwKeyFlags = GetKeyboardFlags();
switch(vkey) { case VK_ESCAPE: PostMessage(_hwndParent, WM_CLOSE, 0, 0); return 0; case VK_RETURN: if(!(dwKeyFlags & CTRL) && !(_dwStyle & ES_WANTRETURN)) { // Send to default button
HWND hwndT; LRESULT id = SendMessage(_hwndParent, DM_GETDEFID, 0, 0);
if(LOWORD(id) && (hwndT = GetDlgItem(_hwndParent, LOWORD(id)))) { SendMessage(_hwndParent, WM_NEXTDLGCTL, (WPARAM) hwndT, (LPARAM) 1); if(GetFocus() != _hwnd) PostMessage(hwndT, WM_KEYDOWN, (WPARAM) VK_RETURN, 0); } return 0; } break;
case VK_TAB: if(!(dwKeyFlags & CTRL)) { SendMessage(_hwndParent, WM_NEXTDLGCTL, !!(dwKeyFlags & SHIFT), 0); return 0; } break; }
return 1; }
/*
* CTxtWinHost::OnChar (vkey, dwFlags) * * @mfunc * Eat some WM_CHAR messages for a control in a dialog box * * #rdesc * LRESULT = (code processed) ? 0 : 1 */ LRESULT CTxtWinHost::OnChar( WORD vkey, //@parm WM_CHAR wparam (translated key code)
DWORD dwFlags) //@parm WM_CHAR flags
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnChar");
if(!_fInDialogBox || (GetKeyboardFlags() & CTRL)) return 1; switch(vkey) { case 'J' - 0x40: // Ctrl-Return generates Ctrl-J (LF):
case VK_RETURN: // treat it as an ordinary return
// We need to filter-out cases where we don't want to insert <cr> in
// 1.0 mode here since the info isn't available within the ped
if (((CTxtEdit*)_pserv)->Get10Mode()) { if (_fInDialogBox && dwFlags != MK_CONTROL && !(_dwStyle & ES_WANTRETURN)) return 0; if (!(_dwStyle & ES_MULTILINE)) { //richedit beeps in this case
((CTxtEdit*)_pserv)->Beep(); return 0; } } else if (!(_dwStyle & ES_WANTRETURN)) return 0; // Signal char processed (eaten)
break;
case VK_TAB: return 0; } return 1; // Signal char not processed
}
///////////////////////////////// View rectangle //////////////////////////////////////
void CTxtWinHost::OnGetRect( LPRECT prc) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnGetRect");
RECT rcInset; LONG lSelBarWidth = 0;
if(_fEmSetRectCalled) { // Get the selection bar width and add it back to the view inset so
// we return the rectangle that the application set.
TxGetSelectionBarWidth(&lSelBarWidth); }
// Get view inset (in HIMETRIC)
TxGetViewInset(&rcInset);
// Get client rect in pixels
TxGetClientRect(prc);
// Modify the client rect by the inset converted to pixels
prc->left += W32->HimetricXtoDX(rcInset.left + lSelBarWidth, W32->GetXPerInchScreenDC()); prc->top += W32->HimetricYtoDY(rcInset.top, W32->GetYPerInchScreenDC()); prc->right -= W32->HimetricXtoDX(rcInset.right, W32->GetXPerInchScreenDC()); prc->bottom -= W32->HimetricYtoDY(rcInset.bottom, W32->GetYPerInchScreenDC()); }
void CTxtWinHost::OnSetRect( LPRECT prc, //@parm Desired formatting RECT
BOOL fNewBehavior, //@parm If TRUE, prc is inset RECT directly
BOOL fRedraw) //@parm If TRUE, redraw after setting RECT
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnSetRect");
RECT rcClient; LONG lSelBarWidth; // Assuming this is not set to the default, turn on special EM_SETRECT
// processing. The important part of this is that we subtract the selection
// bar from the view inset because the EM_SETRECT rectangle does not
// include the selection bar.
_fEmSetRectCalled = TRUE;
if(!prc) { // We are back to the default so turn off special EM_SETRECT procesing.
_fEmSetRectCalled = FALSE; SetDefaultInset(); } else { // For screen display, the following intersects new view RECT
// with adjusted client area RECT
TxGetClientRect(&rcClient);
// Adjust client rect. Factors in space for borders
if(_fBorder) { rcClient.top += _yInset; rcClient.bottom -= _yInset - 1; rcClient.left += _xInset; rcClient.right -= _xInset; } if(!fNewBehavior) { // Intersect new view rectangle with adjusted client area rectangle
if(!IntersectRect(&_rcViewInset, &rcClient, prc)) _rcViewInset = rcClient; } else _rcViewInset = *prc;
// Get selection bar width
TxGetSelectionBarWidth(&lSelBarWidth);
// Compute inset in pixels and convert to HIMETRIC.
_rcViewInset.left = W32->DXtoHimetricX(_rcViewInset.left - rcClient.left, W32->GetXPerInchScreenDC()) - lSelBarWidth; _rcViewInset.top = W32->DYtoHimetricY(_rcViewInset.top - rcClient.top, W32->GetYPerInchScreenDC()); _rcViewInset.right = W32->DXtoHimetricX(rcClient.right - _rcViewInset.right, W32->GetXPerInchScreenDC()); _rcViewInset.bottom = W32->DYtoHimetricY(rcClient.bottom - _rcViewInset.bottom, W32->GetYPerInchScreenDC()); } if(fRedraw) { _pserv->OnTxPropertyBitsChange(TXTBIT_VIEWINSETCHANGE, TXTBIT_VIEWINSETCHANGE); } }
/////////////////////////////// System notifications //////////////////////////////////
void CTxtWinHost::OnSysColorChange() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnSysColorChange");
if(!_fNotSysBkgnd) _crBackground = GetSysColor(COLOR_WINDOW); TxInvalidateRect(NULL, TRUE); }
/*
* CTxtWinHost::OnGetDlgCode (wparam, lparam) * * @mfunc * Handle some WM_GETDLGCODE messages * * #rdesc * LRESULT = dialog code */ LRESULT CTxtWinHost::OnGetDlgCode( WPARAM wparam, LPARAM lparam) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnGetDlgCode");
LRESULT lres = DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_WANTTAB;
if(_dwStyle & ES_MULTILINE) lres |= DLGC_WANTALLKEYS;
if(!(_dwStyle & ES_SAVESEL)) lres |= DLGC_HASSETSEL;
// HACK: If we get one of these messages then we turn on the special
// EM_SETSEL behavior. The problem is that _fInDialogBox gets turned
// on after the EM_SETSEL has occurred.
_fUseSpecialSetSel = TRUE;
/*
** -------------------------------------------- JEFFBOG HACK ---- ** Only set Dialog Box Flag if GETDLGCODE message is generated by ** IsDialogMessage -- if so, the lParam will be a pointer to the ** message structure passed to IsDialogMessage; otherwise, lParam ** will be NULL. Reason for the HACK alert: the wParam & lParam ** for GETDLGCODE is still not clearly defined and may end up ** changing in a way that would throw this off ** -------------------------------------------- JEFFBOG HACK ---- */ if(lparam) _fInDialogBox = TRUE;
/*
** If this is a WM_SYSCHAR message generated by the UNDO keystroke ** we want this message so we can EAT IT in remain.c, case WM_SYSCHAR: */ if (lparam && (((LPMSG)lparam)->message == WM_SYSCHAR) && (((LPMSG)lparam)->lParam & SYS_ALTERNATE) && wparam == VK_BACK) { lres |= DLGC_WANTMESSAGE; }
return lres; }
///////////////////////////////// Other messages //////////////////////////////////////
LRESULT CTxtWinHost::OnGetOptions() const { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnGetOptions");
LRESULT lres = (_dwStyle & ECO_STYLES);
if(_fEnableAutoWordSel) lres |= ECO_AUTOWORDSELECTION; return lres; }
void CTxtWinHost::OnSetOptions( WORD wOp, DWORD eco) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnSetOptions");
DWORD dwChangeMask = 0; DWORD dwProp = 0; DWORD dwStyle; DWORD dwStyleNew = _dwStyle; const BOOL fAutoWordSel = !!(eco & ECO_AUTOWORDSELECTION); BOOL bNeedToTurnOffIME = FALSE;
// We keep track of the bits changed and then if any have changed we
// query for all of our property bits and then send them. This simplifies
// the code because we don't have to set all the bits specially. If the
// code is changed to make the properties more in line with the new
// model, we want to look at this code again.
// Single line controls can't have a selection bar or do vertical writing
if(!(_dwStyle & ES_MULTILINE)) eco &= ~ECO_SELECTIONBAR;
Assert((DWORD)fAutoWordSel <= 1); // Make sure that BOOL is 1/0
dwStyle = (eco & ECO_STYLES);
switch(wOp) { case ECOOP_SET: dwStyleNew = (dwStyleNew & ~ECO_STYLES) | dwStyle; _fEnableAutoWordSel = fAutoWordSel; break;
case ECOOP_OR: dwStyleNew |= dwStyle; // Setting a :1 flag = TRUE
if(fAutoWordSel) // or FALSE is 1 instruction
_fEnableAutoWordSel = TRUE; // Setting it to a BOOL
break; // averages 9 instructions!
case ECOOP_AND: dwStyleNew &= (dwStyle | ~ECO_STYLES); if(!fAutoWordSel) _fEnableAutoWordSel = FALSE; break;
case ECOOP_XOR: dwStyleNew ^= dwStyle; if(fAutoWordSel) _fEnableAutoWordSel ^= 1; break; }
if(_fEnableAutoWordSel != (unsigned)fAutoWordSel) dwChangeMask |= TXTBIT_AUTOWORDSEL;
if(dwStyleNew != _dwStyle) { DWORD dwChange = dwStyleNew ^ _dwStyle;
AssertSz(!(dwChange & ~ECO_STYLES), "non-eco style changed"); _dwStyle = dwStyleNew; SetWindowLong(_hwnd, GWL_STYLE, dwStyleNew);
if(dwChange & ES_NOHIDESEL) dwChangeMask |= TXTBIT_HIDESELECTION;
// These two local variables to use to keep track of
// previous setting of ES_READONLY
BOOL bReadOnly = (_dwStyle & ES_READONLY);
if(dwChange & ES_READONLY) { dwChangeMask |= TXTBIT_READONLY;
// Change drop target state as appropriate.
if(dwStyleNew & ES_READONLY) HostRevokeDragDrop();
else HostRegisterDragDrop(); bReadOnly = (dwStyleNew & ES_READONLY); }
if(dwChange & ES_VERTICAL) dwChangeMask |= TXTBIT_VERTICAL;
if(dwChange & ES_NOIME) { _usIMEMode = (dwStyleNew & ES_NOIME) ? ES_NOIME : 0; bNeedToTurnOffIME = (_usIMEMode ==ES_NOIME); } else if(dwChange & ES_SELFIME) _usIMEMode = (dwStyleNew & ES_SELFIME) ? ES_SELFIME : 0; // No action required for ES_WANTRETURN nor for ES_SAVESEL
// Do this last
if(dwChange & ES_SELECTIONBAR) dwChangeMask |= TXTBIT_SELBARCHANGE; }
if (dwChangeMask) { TxGetPropertyBits(dwChangeMask, &dwProp); _pserv->OnTxPropertyBitsChange(dwChangeMask, dwProp); }
if (bNeedToTurnOffIME) // Tell textservices to turnoff ime
_pserv->TxSendMessage(EM_SETEDITSTYLE, SES_NOIME, SES_NOIME, NULL); }
void CTxtWinHost::OnSetReadOnly( BOOL fReadOnly) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnSetReadOnly");
DWORD dwT = GetWindowLong(_hwnd, GWL_STYLE); DWORD dwUpdatedBits = 0;
if(fReadOnly) { dwT |= ES_READONLY; _dwStyle |= ES_READONLY;
// Turn off Drag Drop
HostRevokeDragDrop(); dwUpdatedBits |= TXTBIT_READONLY; } else { dwT &= ~ES_READONLY; _dwStyle &= ~ES_READONLY;
// Turn drag drop back on
HostRegisterDragDrop(); }
_pserv->OnTxPropertyBitsChange(TXTBIT_READONLY, dwUpdatedBits);
SetWindowLong(_hwnd, GWL_STYLE, dwT); }
//////////////////////////////////// Helpers /////////////////////////////////////////
void CTxtWinHost::SetDefaultInset() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::SetDefaultInset");
// Generate default view rect from client rect
if(_fBorder) { // Factors in space for borders
_rcViewInset.top = W32->DYtoHimetricY(_yInset, W32->GetYPerInchScreenDC()); _rcViewInset.bottom = W32->DYtoHimetricY(_yInset - 1, W32->GetYPerInchScreenDC()); _rcViewInset.left = W32->DXtoHimetricX(_xInset, W32->GetXPerInchScreenDC()); _rcViewInset.right = W32->DXtoHimetricX(_xInset, W32->GetXPerInchScreenDC()); } else { // Default the top and bottom inset to 0 and the left and right
// to the size of the border.
_rcViewInset.top = 0; _rcViewInset.bottom = 0; _rcViewInset.left = W32->DXtoHimetricX(W32->GetCxBorder(), W32->GetXPerInchScreenDC()); _rcViewInset.right = W32->DXtoHimetricX(W32->GetCxBorder(), W32->GetXPerInchScreenDC()); } }
///////////////////////////////// Far East Support //////////////////////////////////////
//#ifdef WIN95_IME
HIMC CTxtWinHost::TxImmGetContext() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::TxImmGetContext");
HIMC himc;
Assert(_hwnd); himc = ImmGetContext(_hwnd); return himc; }
void CTxtWinHost::TxImmReleaseContext( HIMC himc) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::TxImmReleaseContext");
Assert(_hwnd); ImmReleaseContext(_hwnd, himc); }
//#endif
void CTxtWinHost::HostRevokeDragDrop() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::HostRevokeDragDrop");
if(_fRegisteredForDrop) { // Note that if the revoke fails we want to know about this in debug
// builds so we can fix any problems. In retail, we can't really do
// so we just ignore it.
#ifdef DEBUG
HRESULT hr = #endif // DEBUG
RevokeDragDrop(_hwnd);
#ifdef DEBUG
TESTANDTRACEHR(hr); #endif // DEBUG
_fRegisteredForDrop = FALSE; } }
void CTxtWinHost::HostRegisterDragDrop() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::RegisterDragDrop");
IDropTarget *pdt;
if(!_fRegisteredForDrop && _pserv->TxGetDropTarget(&pdt) == NOERROR) { // The most likely reason for RegisterDragDrop to fail is some kind of
// bug in our program.
HRESULT hr = RegisterDragDrop(_hwnd, pdt);
if(hr == NOERROR) _fRegisteredForDrop = TRUE;
#ifndef PEGASUS
pdt->Release(); #endif
} }
static void DrawRectFn( HDC hdc, RECT *prc, INT icrTL, INT icrBR, BOOL fBot, BOOL fRght) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "DrawRectFn");
COLORREF cr = GetSysColor(icrTL); COLORREF crSave = SetBkColor(hdc, cr); RECT rc = *prc;
// top
rc.bottom = rc.top + 1; ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
// left
rc.bottom = prc->bottom; rc.right = rc.left + 1; ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
if(icrTL != icrBR) { cr = GetSysColor(icrBR); SetBkColor(hdc, cr); }
// right
rc.right = prc->right; rc.left = rc.right - 1; if(!fBot) rc.bottom -= W32->GetCyHScroll(); if(fRght) ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
// bottom
if(fBot) { rc.left = prc->left; rc.top = rc.bottom - 1; if(!fRght) rc.right -= W32->GetCxVScroll(); ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); } SetBkColor(hdc, crSave); }
#define cmultBorder 1
void CTxtWinHost::OnSunkenWindowPosChanging( HWND hwnd, WINDOWPOS *pwndpos) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnSunkenWindowPosChanging");
if(IsWindowVisible(hwnd)) { RECT rc; HWND hwndParent;
GetWindowRect(hwnd, &rc); InflateRect(&rc, W32->GetCxBorder() * cmultBorder, W32->GetCyBorder() * cmultBorder); hwndParent = GetParent(hwnd); MapWindowPoints(HWND_DESKTOP, hwndParent, (POINT *) &rc, 2); InvalidateRect(hwndParent, &rc, FALSE); } }
void CTxtWinHost::DrawSunkenBorder( HWND hwnd, HDC hdc) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::DrawSunkenBorder"); BOOL fVScroll = (_dwStyle & WS_VSCROLL); BOOL fHScroll = (_dwStyle & WS_HSCROLL);
RECT rc; RECT rcParent; HWND hwndParent;
// if we're not visible, don't do anything.
if(!IsWindowVisible(hwnd)) return;
GetWindowRect(hwnd, &rc); hwndParent = GetParent(hwnd); rcParent = rc; MapWindowPoints(HWND_DESKTOP, hwndParent, (POINT *)&rcParent, 2); InflateRect(&rcParent, W32->GetCxBorder(), W32->GetCyBorder()); OffsetRect(&rc, -rc.left, -rc.top);
if(_pserv) { // If we have a text control then get whether it thinks there are
// scroll bars.
_pserv->TxGetHScroll(NULL, NULL, NULL, NULL, &fHScroll); _pserv->TxGetVScroll(NULL, NULL, NULL, NULL, &fVScroll); }
// Draw inner rect
DrawRectFn(hdc, &rc, icr3DDarkShadow, COLOR_BTNFACE, !fHScroll, !fVScroll);
// Draw outer rect
hwndParent = GetParent(hwnd); hdc = GetDC(hwndParent); DrawRectFn(hdc, &rcParent, COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, TRUE, TRUE); ReleaseDC(hwndParent, hdc); }
LRESULT CTxtWinHost::OnSize( HWND hwnd, WORD fwSizeType, int nWidth, int nHeight) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnSize");
BOOL fIconic = GetIconic(hwnd); DWORD dw = TXTBIT_CLIENTRECTCHANGE; if(_sWidth != nWidth && !fIconic && !_fIconic) { _sWidth = (short)nWidth; // Be sure to update _sWidth
dw = TXTBIT_EXTENTCHANGE; }
if(!_fVisible) { if(!fIconic) _fResized = TRUE; } else if(!fIconic) { // We use this property because this will force a recalc.
// We don't actually recalc on a client rect change because
// most of the time it is pointless. We force one here because
// some applications use size changes to calculate the optimal
// size of the window.
_pserv->OnTxPropertyBitsChange(dw, dw);
if(_fIconic) { TRACEINFOSZ("Restoring from iconic"); InvalidateRect(hwnd, NULL, FALSE); } // Draw borders
if(TxGetEffects() == TXTEFFECT_SUNKEN && dwMajorVersion < VERS4) DrawSunkenBorder(hwnd, NULL); } _fIconic = fIconic; // Update _fIconic
return 0; }
HRESULT CTxtWinHost::OnTxVisibleChange( BOOL fVisible) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::OnTxVisibleChange");
_fVisible = fVisible;
if(!_fVisible && _fResized) { RECT rc; // Control was resized while hidden, need to really resize now
TxGetClientRect(&rc); _fResized = FALSE; _pserv->OnTxPropertyBitsChange(TXTBIT_CLIENTRECTCHANGE, TXTBIT_CLIENTRECTCHANGE); } return S_OK; }
//////////////////////////// ITextHost Interface ////////////////////////////
// @doc EXTERNAL
/*
* CTxtWinHost::TxGetDC() * * @mfunc * Abstracts GetDC so Text Services does not need a window handle. * * @rdesc * A DC or NULL in the event of an error. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ HDC CTxtWinHost::TxGetDC() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetDC");
Assert(_hwnd); return ::GetDC(_hwnd); }
/*
* CTxtWinHost::TxReleaseDC (hdc) * * @mfunc * Release DC gotten by TxGetDC. * * @rdesc * 1 - HDC was released. <nl> * 0 - HDC was not released. <nl> * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ int CTxtWinHost::TxReleaseDC( HDC hdc) //@parm DC to release
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxReleaseDC");
Assert(_hwnd); return ::ReleaseDC (_hwnd, hdc); }
/*
* CTxtWinHost::TxShowScrollBar (fnBar, fShow) * * @mfunc * Shows or Hides scroll bar in Text Host window * * @rdesc * TRUE on success, FALSE otherwise * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxShowScrollBar( INT fnBar, //@parm Specifies scroll bar(s) to be shown or hidden
BOOL fShow) //@parm Specifies whether scroll bar is shown or hidden
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxShowScrollBar");
Assert(_hwnd); LONG nMax;
if(fnBar == SB_HORZ) _pserv->TxGetHScroll(NULL, &nMax, NULL, NULL, NULL); else _pserv->TxGetVScroll(NULL, &nMax, NULL, NULL, NULL);
return W32->ShowScrollBar(_hwnd, fnBar, fShow, nMax); }
/*
* CTxtWinHost::TxEnableScrollBar (fuSBFlags, fuArrowflags) * * @mfunc * Enables or disables one or both scroll bar arrows * in Text Host window. * * @rdesc * If the arrows are enabled or disabled as specified, the return * value is TRUE. If the arrows are already in the requested state or an * error occurs, the return value is FALSE. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxEnableScrollBar ( INT fuSBFlags, //@parm Specifies scroll bar type
INT fuArrowflags) //@parm Specifies whether and which scroll bar arrows
// are enabled or disabled
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxEnableScrollBar");
Assert(_hwnd); return W32->EnableScrollBar(_hwnd, fuSBFlags, fuArrowflags); }
/*
* CTxtWinHost::TxSetScrollRange (fnBar, nMinPos, nMaxPos, fRedraw) * * @mfunc * Sets the minimum and maximum position values for the specified * scroll bar in the text host window. * * @rdesc * If the arrows are enabled or disabled as specified, the return value * is TRUE. If the arrows are already in the requested state or an error * occurs, the return value is FALSE. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxSetScrollRange( INT fnBar, //@parm Scroll bar flag
LONG nMinPos, //@parm Minimum scrolling position
INT nMaxPos, //@parm Maximum scrolling position
BOOL fRedraw) //@parm Specifies whether scroll bar should be redrawn
{ // to reflect change
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetScrollRange");
Assert(_hwnd);
if(NULL == _pserv) { // We are initializing so do this instead of callback
return ::SetScrollRange(_hwnd, fnBar, nMinPos, nMaxPos, fRedraw); } SetScrollInfo(fnBar, fRedraw); return TRUE; }
/*
* CTxtWinHost::TxSetScrollPos (fnBar, nPos, fRedraw) * * @mfunc * Tells Text host to set the position of the scroll box (thumb) in the * specified scroll bar and, if requested, redraws the scroll bar to * reflect the new position of the scroll box. * * @rdesc * TRUE on success; FALSE otherwise. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxSetScrollPos ( INT fnBar, //@parm Scroll bar flag
INT nPos, //@parm New position in scroll box
BOOL fRedraw) //@parm Redraw flag
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetScrollPos");
Assert(_hwnd);
if(NULL == _pserv) { // We are initializing so do this instead of callback
return ::SetScrollPos(_hwnd, fnBar, nPos, fRedraw); } SetScrollInfo(fnBar, fRedraw); return TRUE; }
/*
* CTxtWinHost::TxInvalidateRect (prc, fMode) * * @mfunc * Adds a rectangle to the Text Host window's update region * * @comm * This function may be called while inactive; however the host * implementation is free to invalidate an area greater than * the requested rect. */ void CTxtWinHost::TxInvalidateRect( LPCRECT prc, //@parm Address of rectangle coordinates
BOOL fMode) //@parm Erase background flag
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxInvalidateRect");
Assert(_hwnd);
if(!_fVisible) { // There doesn't seem to be a deterministic way to determine whether
// our window is visible or not via message notifications. Therefore,
// we check this each time incase it might have changed.
_fVisible = IsWindowVisible(_hwnd);
if(_fVisible) OnTxVisibleChange(TRUE); }
// Don't bother with invalidating rect if we aren't visible
if(_fVisible) { if(IsTransparentMode()) { RECT rcParent; HWND hParent = ::GetParent (_hwnd); Assert(hParent);
// For transparent mode, we need to invalidate the parent
// so it will paint the background.
if(prc) rcParent = *prc; else TxGetClientRect(&rcParent);
::MapWindowPoints(_hwnd, hParent, (LPPOINT)&rcParent, 2); ::InvalidateRect(hParent, &rcParent, fMode); // ::HideCaret(_hwnd);
} ::InvalidateRect(_hwnd, prc, fMode); } }
/*
* CTxtWinHost::TxViewChange (fUpdate) * * @mfunc * Notify Text Host that update region should be repainted. * * @comm * It is the responsibility of the text services to call * TxViewChanged every time it decides that it's visual representation * has changed, regardless of whether the control is active or * not. If the control is active, the text services has the additional * responsibility of making sure the controls window is updated. * It can do this in a number of ways: 1) get a DC for the control's * window and start blasting pixels (TxGetDC and TxReleaseDC), 2) * invalidate the control's window (TxInvalidate), or 3) scroll * the control's window (TxScrollWindowEx). * * Text services can choose to call TxViewChange after it has * performed any operations to update the active view and pass a * true along with the call. By passing true, the text host * calls UpdateWindow to make sure any unpainted areas of the * active control are repainted. */ void CTxtWinHost::TxViewChange( BOOL fUpdate) //@parm TRUE = call update window
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxViewChange");
Assert(_hwnd);
// Don't bother with paint since we aren't visible
if(_fVisible) { // For updates requests that are FALSE, we will let the next WM_PAINT
// message pick up the draw.
if(fUpdate) { if(IsTransparentMode()) { HWND hParent = GetParent (_hwnd); Assert(hParent);
// For transparent mode, we need to update the parent first
// before we can update ourself. Otherwise, what we painted will
// be erased by the parent's background later.
::UpdateWindow (hParent); } ::UpdateWindow (_hwnd); } } }
/*
* CTxtWinHost::TxCreateCaret (hbmp, xWidth, yHeight) * * @mfunc * Create new shape for Text Host's caret * * @rdesc * TRUE on success, FALSE otherwise. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxCreateCaret( HBITMAP hbmp, //@parm Handle of bitmap for caret shape
INT xWidth, //@parm Caret width
INT yHeight) //@parm Caret height
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxCreateCaret");
Assert(_hwnd); return ::CreateCaret (_hwnd, hbmp, xWidth, yHeight); }
/*
* CTxtWinHost::TxShowCaret (fShow) * * @mfunc * Make caret visible/invisible at caret position in Text Host window. * * @rdesc * TRUE - call succeeded <nl> * FALSE - call failed <nl> * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxShowCaret( BOOL fShow) //@parm Flag whether caret is visible
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxShowCaret");
return fShow ? ::ShowCaret(_hwnd) : ::HideCaret(_hwnd); }
/*
* CTxtWinHost::TxSetCaretPos (x, y) * * @mfunc * Move caret position to specified coordinates in Text Host window. * * @rdesc * TRUE - call succeeded <nl> * FALSE - call failed <nl> * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ BOOL CTxtWinHost::TxSetCaretPos( INT x, //@parm Horizontal position (in client coordinates)
INT y) //@parm Vertical position (in client coordinates)
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetCaretPos");
return ::SetCaretPos(x, y); }
/*
* CTxtWinHost::TxSetTimer (idTimer, uTimeout) * * @mfunc * Request Text Host to creates a timer with specified time out. * * @rdesc * TRUE - call succeeded <nl> * FALSE - call failed <nl> */ BOOL CTxtWinHost::TxSetTimer( UINT idTimer, //@parm Timer identifier
UINT uTimeout) //@parm Timeout in msec
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetTimer");
Assert(_hwnd); return ::SetTimer(_hwnd, idTimer, uTimeout, NULL); }
/*
* CTxtWinHost::TxKillTimer (idTimer) * * @mfunc * Destroy specified timer * * @rdesc * TRUE - call succeeded <nl> * FALSE - call failed <nl> * * @comm * This method may be called at any time irrespective of active versus * inactive state. */ void CTxtWinHost::TxKillTimer( UINT idTimer) //@parm id of timer
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxKillTimer");
Assert(_hwnd); ::KillTimer(_hwnd, idTimer); }
/*
* CTxtWinHost::TxScrollWindowEx (dx, dy, lprcScroll, lprcClip, hrgnUpdate, * lprcUpdate, fuScroll) * @mfunc * Request Text Host to scroll the content of the specified client area * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ void CTxtWinHost::TxScrollWindowEx ( INT dx, //@parm Amount of horizontal scrolling
INT dy, //@parm Amount of vertical scrolling
LPCRECT lprcScroll, //@parm Scroll rectangle
LPCRECT lprcClip, //@parm Clip rectangle
HRGN hrgnUpdate, //@parm Handle of update region
LPRECT lprcUpdate, //@parm Update rectangle
UINT fuScroll) //@parm Scrolling flags
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxScrollWindowEx");
Assert(_hwnd); ::ScrollWindowEx(_hwnd, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate, fuScroll); }
/*
* CTxtWinHost::TxSetCapture (fCapture) * * @mfunc * Set mouse capture in Text Host's window. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may do nothing. */ void CTxtWinHost::TxSetCapture( BOOL fCapture) //@parm Whether to get or release capture
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetCapture");
Assert(_hwnd); if (fCapture) ::SetCapture(_hwnd); else ::ReleaseCapture(); }
/*
* CTxtWinHost::TxSetFocus () * * @mfunc * Set focus in text host window. * * @comm * This method is only valid when the control is in-place active; * calls while inactive may fail. */ void CTxtWinHost::TxSetFocus() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetFocus");
Assert(_hwnd); ::SetFocus(_hwnd); }
/*
* CTxtWinHost::TxSetCursor (hcur, fText) * * @mfunc * Establish a new cursor shape in the Text Host's window. * * @comm * This method may be called at any time, irrespective of * active vs. inactive state. * * ITextHost::TxSetCursor should be called back by the Text Services * to actually set the mouse cursor. If the fText parameter is TRUE, * Text Services is trying to set the "text" cursor (cursor over text * that is not selected, currently an IBEAM). In that case, the host * can set it to whatever the control MousePointer property is. This is * required by VB compatibility since, via the MousePointer property, * the VB programmer has control over the shape of the mouse cursor, * whenever it would normally be set to an IBEAM. */ void CTxtWinHost::TxSetCursor( HCURSOR hcur, //@parm Handle to cursor
BOOL fText) //@parm Indicates caller wants to set text cursor
// (IBeam) if true.
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxSetCursor");
::SetCursor(hcur); }
/*
* CTxtWinHost::TxScreenToClient (lppt) * * @mfunc * Convert screen coordinates to Text Host window coordinates. * * @rdesc * TRUE - call succeeded <nl> * FALSE - call failed <nl> */ BOOL CTxtWinHost::TxScreenToClient( LPPOINT lppt) //@parm Coordinates for point
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxScreenToClient");
Assert(_hwnd); return ::ScreenToClient(_hwnd, lppt); }
/*
* CTxtWinHost::TxClientToScreen (lppt) * * @mfunc * Convert Text Host coordinates to screen coordinates * * @rdesc * TRUE - call succeeded <nl> * FALSE - call failed <nl> * * @comm * This call is valid at any time, although it is allowed to * fail. In general, if text services has coordinates it needs * to translate from client coordinates (e.g. for TOM's * PointFromRange method) the text services will actually be * visible. * * However, if no conversion is possible, then the method will fail. */ BOOL CTxtWinHost::TxClientToScreen( LPPOINT lppt) //@parm Client coordinates to convert.
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxClientToScreen");
Assert(_hwnd); return ::ClientToScreen(_hwnd, lppt); }
/*
* CTxtWinHost::TxActivate (plOldState) * * @mfunc * Notify Text Host that control is active * * @rdesc * S_OK - call succeeded. <nl> * E_FAIL - activation is not possible at this time * * @comm * It is legal for the host to refuse an activation request; * the control may be minimized and thus invisible, for instance. * * The caller should be able to gracefully handle failure to activate. * * Calling this method more than once does not cumulate; only * once TxDeactivate call is necessary to deactive. * * This function returns an opaque handle in <p plOldState>. The caller * (Text Services) should hang onto this handle and return it in a * subsequent call to TxDeactivate. */ HRESULT CTxtWinHost::TxActivate( LONG *plOldState) //@parm Where to put previous activation state
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxActivate");
return S_OK; }
/*
* CTxtWinHost::TxDeactivate (lNewState) * * @mfunc * Notify Text Host that control is now inactive * * @rdesc * S_OK - call succeeded. <nl> * E_FAIL <nl> * * @comm * Calling this method more than once does not cumulate */ HRESULT CTxtWinHost::TxDeactivate( LONG lNewState) //@parm New state (typically value returned by
// TxActivate
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxDeactivate");
return S_OK; } /*
* CTxtWinHost::TxGetClientRect (prc) * * @mfunc * Retrive client coordinates of Text Host's client area. * * @rdesc * HRESULT = (success) ? S_OK : E_FAIL */ HRESULT CTxtWinHost::TxGetClientRect( LPRECT prc) //@parm Where to put client coordinates
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetClientRect");
Assert(_hwnd && prc); return ::GetClientRect(_hwnd, prc) ? S_OK : E_FAIL; }
/*
* CTxtWinHost::TxGetViewInset (prc) * * @mfunc * Get inset for Text Host window. Inset is the "white space" * around text. * * @rdesc * HRESULT = NOERROR * * @comm * The Inset rectangle is not strictly a rectangle. The top, bottom, * left, and right fields of the rect structure indicate how far in * each direction drawing should be inset. Inset sizes are in client * coordinates. */ HRESULT CTxtWinHost::TxGetViewInset( LPRECT prc) //@parm Where to put inset rectangle
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetViewInset");
Assert(prc);
*prc = _rcViewInset; return NOERROR; }
/*
* CTxtWinHost::TxGetCharFormat (ppCF) * * @mfunc * Get Text Host's default character format * * @rdesc * HRESULT = E_NOTIMPL (not needed in simple Windows host, since text * services provides desired default) * * @comm * The callee retains ownwership of the charformat returned. However, * the pointer returned must remain valid until the callee notifies * Text Services via OnTxPropertyBitsChange that the default character * format has changed. */ HRESULT CTxtWinHost::TxGetCharFormat( const CHARFORMAT **ppCF) //@parm Where to put ptr to default
// character format
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetCharFormat");
return E_NOTIMPL; }
/*
* CTxtWinHost::TxGetParaFormat (ppPF) * * @mfunc * Get Text Host default paragraph format * * @rdesc * HRESULT = E_NOTIMPL (not needed in simple Windows host, since text * services provides desired default) * * @comm * The host object (callee) retains ownership of the PARAFORMAT returned. * However, the pointer returned must remain valid until the host notifies * Text Services (the caller) via OnTxPropertyBitsChange that the default * paragraph format has changed. */ HRESULT CTxtWinHost::TxGetParaFormat( const PARAFORMAT **ppPF) //@parm Where to put ptr to default
// paragraph format
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetParaFormat");
return E_NOTIMPL; }
/*
* CTxtWinHost::TxGetSysColor (nIndex) * * @mfunc * Get specified color identifer from Text Host. * * @rdesc * Color identifier * * @comm * Note that the color returned may be *different* than the * color that would be returned from a call to GetSysColor. * This allows hosts to override default system behavior. * * Needless to say, hosts should be very careful about overriding * normal system behavior as it could result in inconsistent UI * (particularly with respect to Accessibility options). */ COLORREF CTxtWinHost::TxGetSysColor( int nIndex) //@parm Color to get, same parameter as
// GetSysColor Win32 API
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetSysColor");
if (!_fDisabled || nIndex != COLOR_WINDOW && nIndex != COLOR_WINDOWTEXT) { // This window is not disabled or the color is not interesting
// in the disabled case.
return (nIndex == COLOR_WINDOW && _fNotSysBkgnd) ? _crBackground : GetSysColor(nIndex); }
// Disabled case
if (COLOR_WINDOWTEXT == nIndex) { // Color of text for disabled window
return GetSysColor(COLOR_GRAYTEXT); }
// Background color for disabled window
return GetSysColor(COLOR_3DFACE); }
/*
* CTxtWinHost::TxGetBackStyle (pstyle) * * @mfunc * Get Text Host background style. * * @rdesc * HRESULT = S_OK * * @xref <e TXTBACKSTYLE> */ HRESULT CTxtWinHost::TxGetBackStyle( TXTBACKSTYLE *pstyle) //@parm Where to put background style
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetBackStyle");
*pstyle = (_dwExStyle & WS_EX_TRANSPARENT) ? TXTBACK_TRANSPARENT : TXTBACK_OPAQUE; return NOERROR; }
/*
* CTxtWinHost::TxGetMaxLength (pLength) * * @mfunc * Get Text Host's maximum allowed length. * * @rdesc * HRESULT = S_OK * * @comm * This method parallels the EM_LIMITTEXT message. * If INFINITE (0xFFFFFFFF) is returned, then text services * will use as much memory as needed to store any given text. * * If the limit returned is less than the number of characters * currently in the text engine, no data is lost. Instead, * no edits will be allowed to the text *other* than deletion * until the text is reduced to below the limit. */ HRESULT CTxtWinHost::TxGetMaxLength( DWORD *pLength) //@parm Maximum allowed length, in number of
// characters
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetMaxLength"); AssertSz(FALSE, "CTxtWinHost::TxGetMaxLength why is this being called?"); return NOERROR; }
/*
* CTxtWinHost::TxGetScrollBars (pdwScrollBar) * * @mfunc * Get Text Host's scroll bars supported. * * @rdesc * HRESULT = S_OK * * @comm * <p pdwScrollBar> is filled with a boolean combination of the * window styles related to scroll bars. Specifically, these are: * * WS_VSCROLL <nl> * WS_HSCROLL <nl> * ES_AUTOVSCROLL <nl> * ES_AUTOHSCROLL <nl> * ES_DISABLENOSCROLL <nl> */ HRESULT CTxtWinHost::TxGetScrollBars( DWORD *pdwScrollBar) //@parm Where to put scrollbar information
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetScrollBars");
*pdwScrollBar = _dwStyle & (WS_VSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_DISABLENOSCROLL); return NOERROR; }
/*
* CTxtWinHost::TxGetPasswordChar (pch) * * @mfunc * Get Text Host's password character. * * @rdesc * HRESULT = (password character not enabled) ? S_FALSE : S_OK * * @comm * The password char will only be shown if the TXTBIT_USEPASSWORD bit * is enabled in TextServices. If the password character changes, * re-enable the TXTBIT_USEPASSWORD bit via * ITextServices::OnTxPropertyBitsChange. */ HRESULT CTxtWinHost::TxGetPasswordChar( TCHAR *pch) //@parm Where to put password character
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetPasswordChar");
*pch = _chPassword; return NOERROR; }
/*
* CTxtWinHost::TxGetAcceleratorPos (pcp) * * @mfunc * Get special character to use for underlining accelerator character. * * @rdesc * Via <p pcp>, returns character position at which underlining * should occur. -1 indicates that no character should be underlined. * Return value is an HRESULT (usually S_OK). * * @comm * Accelerators allow keyboard shortcuts to various UI elements (like * buttons. Typically, the shortcut character is underlined. * * This function tells Text Services which character is the accelerator * and thus should be underlined. Note that Text Services will *not* * process accelerators; that is the responsiblity of the host. * * This method will typically only be called if the TXTBIT_SHOWACCELERATOR * bit is set in text services. * * Note that *any* change to the text in text services will result in the * invalidation of the accelerator underlining. In this case, it is the * host's responsibility to recompute the appropriate character position * and inform text services that a new accelerator is available. */ HRESULT CTxtWinHost::TxGetAcceleratorPos( LONG *pcp) //@parm Out parm to receive cp of character to underline
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetAcceleratorPos");
*pcp = -1; return S_OK; }
/*
* CTxtWinHost::OnTxCharFormatChange * * @mfunc * Set default character format for the Text Host. * * @rdesc * S_OK - call succeeded. <nl> * E_INVALIDARG <nl> * E_FAIL <nl> */ HRESULT CTxtWinHost::OnTxCharFormatChange( const CHARFORMAT *pcf) //@parm New default character format
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::OnTxCharFormatChange");
return S_OK; }
/*
* CTxtWinHost::OnTxParaFormatChange * * @mfunc * Set default paragraph format for the Text Host. * * @rdesc * S_OK - call succeeded. <nl> * E_INVALIDARG <nl> * E_FAIL <nl> */ HRESULT CTxtWinHost::OnTxParaFormatChange( const PARAFORMAT *ppf) //@parm New default paragraph format
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::OnTxParaFormatChange");
return S_OK; }
/*
* CTxtWinHost::TxGetPropertyBits (dwMask, dwBits) * * @mfunc * Get the bit property settings for Text Host. * * @rdesc * S_OK * * @comm * This call is valid at any time, for any combination of * requested property bits. <p dwMask> may be used by the * caller to request specific properties. */ HRESULT CTxtWinHost::TxGetPropertyBits( DWORD dwMask, //@parm Mask of bit properties to get
DWORD *pdwBits) //@parm Where to put bit values
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetPropertyBits");
// FUTURE: Obvious optimization is to save bits in host the same way that
// they are returned and just return them instead of this mess.
// Note: this RichEdit host never sets TXTBIT_SHOWACCELERATOR or
// TXTBIT_SAVESELECTION. They are currently only used by Forms^3 host.
// This host is always rich text.
DWORD dwProperties = TXTBIT_RICHTEXT | TXTBIT_ALLOWBEEP;
#ifdef DEBUG
// make sure that TS doesn't think it's plain text mode when
// we return TXTBIT_RICHTEXT
if((dwMask & TXTBIT_RICHTEXT) && _pserv) { DWORD mode; mode = _pserv->TxSendMessage(EM_GETTEXTMODE, 0, 0, NULL); Assert(mode == TM_RICHTEXT); } #endif // DEBUG
if(_dwStyle & ES_MULTILINE) dwProperties |= TXTBIT_MULTILINE;
if(_dwStyle & ES_READONLY) dwProperties |= TXTBIT_READONLY;
if(_dwStyle & ES_PASSWORD) dwProperties |= TXTBIT_USEPASSWORD;
if(!(_dwStyle & ES_NOHIDESEL)) dwProperties |= TXTBIT_HIDESELECTION;
if(_fEnableAutoWordSel) dwProperties |= TXTBIT_AUTOWORDSEL;
if(!(_dwStyle & ES_AUTOHSCROLL)) dwProperties |= TXTBIT_WORDWRAP;
if(_dwStyle & ES_NOOLEDRAGDROP) dwProperties |= TXTBIT_DISABLEDRAG;
*pdwBits = dwProperties & dwMask; return NOERROR; }
/*
* CTxtWinHost::TxNotify (iNotify, pv) * * @mfunc * Notify Text Host of various events. Note that there are * two basic categories of events, "direct" events and * "delayed" events. Direct events are sent immediately as * they need some processing: EN_PROTECTED is a canonical * example. Delayed events are sent after all processing * has occurred; the control is thus in a "stable" state. * EN_CHANGE, EN_ERRSPACE, EN_SELCHANGED are examples * of delayed notifications. * * * @rdesc * S_OK - call succeeded <nl> * S_FALSE -- success, but do some different action * depending on the event type (see below). * * @comm * The notification events are the same as the notification * messages sent to the parent window of a richedit window. * The firing of events may be controlled with a mask set via * the EM_SETEVENTMASK message. * * In general, is legal to make any calls to text services while * processing this method; however, implementors are cautioned * to avoid excessive recursion. * * Here is the complete list of notifications that may be * sent and a brief description of each: * * <p EN_CHANGE> Sent when some data in the edit control * changes (such as text or formatting). Controlled by the * ENM_CHANGE event mask. This notification is sent _after_ * any screen updates have been requested. * * <p EN_CORRECTTEXT> PenWin only; currently unused. * * <p EN_DROPFILES> If the client registered the edit * control via DragAcceptFiles, this event will be sent when * a WM_DROPFILES or DragEnter(CF_HDROP) message is received. * If S_FALSE is returned, the drop will be ignored, otherwise, * the drop will be processed. The ENM_DROPFILES mask * controls this event notification. * * <p EN_ERRSPACE> Sent when the edit control cannot * allocate enough memory. No additional data is sent and * there is no mask for this event. * * <p EN_HSCROLL> Sent when the user clicks on an edit * control's horizontal scroll bar, but before the screen * is updated. No additional data is sent. The ENM_SCROLL * mask controls this event. * * <p EN_IMECHANGE> unused * * <p EN_KILLFOCUS> Sent when the edit control looses focus. * No additional data is sent and there is no mask. * * <p EN_MAXTEXT> Sent when the current text insertion * has exceeded the specified number of characters for the * edit control. The text insertion has been truncated. * There is no mask for this event. * * <p EN_MSGFILTER> NB!!! THIS MESSAGE IS NOT SENT TO * TxNotify, but is included here for completeness. With * ITextServices::TxSendMessage, client have complete * flexibility in filtering all window messages. * * Sent on a keyboard or mouse event * in the control. A MSGFILTER data structure is sent, * containing the msg, wparam and lparam. If S_FALSE is * returned from this notification, the msg is processed by * TextServices, otherwise, the message is ignored. Note * that in this case, the callee has the opportunity to modify * the msg, wparam, and lparam before TextServices continues * processing. The ENM_KEYEVENTS and ENM_MOUSEEVENTS masks * control this event for the respective event types. * * <p EN_OLEOPFAILED> Sent when an OLE call fails. The * ENOLEOPFAILED struct is passed with the index of the object * and the error code. Mask value is nothing. * * <p EN_PROTECTED> Sent when the user is taking an * action that would change a protected range of text. An * ENPROTECTED data structure is sent, indicating the range * of text affected and the window message (if any) affecting * the change. If S_FALSE is returned, the edit will fail. * The ENM_PROTECTED mask controls this event. * * <p EN_REQUESTRESIZE> Sent when a control's contents are * either smaller or larger than the control's window size. * The client is responsible for resizing the control. A * REQRESIZE structure is sent, indicating the new size of * the control. NB! Only the size is indicated in this * structure; it is the host's responsibility to do any * translation necessary to generate a new client rectangle. * The ENM_REQUESTRESIZE mask controls this event. * * <p EN_SAVECLIPBOARD> Sent when an edit control is being * destroyed, the callee should indicate whether or not * OleFlushClipboard should be called. Data indicating the * number of characters and objects to be flushed is sent * in the ENSAVECLIPBOARD data structure. * Mask value is nothing. * * <p EN_SELCHANGE> Sent when the current selection has * changed. A SELCHANGE data structure is also sent, which * indicates the new selection range at the type of data * the selection is currently over. Controlled via the * ENM_SELCHANGE mask. * * <p EN_SETFOCUS> Sent when the edit control receives the * keyboard focus. No extra data is sent; there is no mask. * * <p EN_STOPNOUNDO> Sent when an action occurs for which * the control cannot allocate enough memory to maintain the * undo state. If S_FALSE is returned, the action will be * stopped; otherwise, the action will continue. * * <p EN_UPDATE> Sent before an edit control requests a * redraw of altered data or text. No additional data is * sent. This event is controlled via the ENM_UPDATE mask. * * <p EN_VSCROLL> Sent when the user clicks an edit control's * vertical scrollbar bar before the screen is updated. * Controlled via the ENM_SCROLL mask; no extra data is sent. * * <p EN_LINK> Sent when a mouse event (or WM_SETCURSOR) happens * over a range of text that has the EN_LINK mask bit set. * An ENLINK data structure will be sent with relevant info. */ HRESULT CTxtWinHost::TxNotify( DWORD iNotify, //@parm Event to notify host of. One of the
// EN_XXX values from Win32, e.g., EN_CHANGE
void *pv) //@parm In-only parameter with extra data. Type
// dependent on <p iNotify>
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxNotify");
HRESULT hr = NOERROR; LONG nId; NMHDR * phdr; REQRESIZE * preq; RECT rcOld;
// We assume here that TextServices has already masked out notifications,
// so if we get one here, it should be sent
if(_hwndParent) { nId = GetWindowLong(_hwnd, GWL_ID); // First, handle WM_NOTIFY style notifications
switch(iNotify) { case EN_REQUESTRESIZE: // Need to map new size into correct rectangle
Assert(pv); GetWindowRect(_hwnd, &rcOld); MapWindowPoints(HWND_DESKTOP, _hwndParent, (POINT *) &rcOld, 2); preq = (REQRESIZE *)pv; preq->rc.top = rcOld.top; preq->rc.left = rcOld.left; preq->rc.right += rcOld.left; preq->rc.bottom += rcOld.top;
// FALL-THROUGH!!
case EN_DROPFILES: case EN_MSGFILTER: case EN_OLEOPFAILED: case EN_PROTECTED: case EN_SAVECLIPBOARD: case EN_SELCHANGE: case EN_STOPNOUNDO: case EN_LINK: case EN_OBJECTPOSITIONS: case EN_DRAGDROPDONE: if(pv) // Fill out NMHDR portion of pv
{ phdr = (NMHDR *)pv; phdr->hwndFrom = _hwnd; phdr->idFrom = nId; phdr->code = iNotify; }
if(SendMessage(_hwndParent, WM_NOTIFY, (WPARAM) nId, (LPARAM) pv)) hr = S_FALSE; break;
default: SendMessage(_hwndParent, WM_COMMAND, GET_WM_COMMAND_MPS(nId, _hwnd, iNotify)); } }
return hr; }
/*
* CTxtWinHost::TxGetExtent (lpExtent) * * @mfunc * Return native size of the control in HIMETRIC * * @rdesc * S_OK <nl> * some failure code <nl> * * @comm * This method is used by Text Services to implement zooming. * Text Services would derive the zoom factor from the ratio between * the himetric and device pixel extent of the client rectangle. * * [vertical zoom factor] = [pixel height of the client rect] * 2540 * / [himetric vertical extent] * [pixel per vertical inch (from DC)] * * If the vertical and horizontal zoom factors are not the same, Text * Services could ignore the horizontal zoom factor and assume it is * the same as the vertical one. */ HRESULT CTxtWinHost::TxGetExtent( LPSIZEL lpExtent) //@parm Extent in himetric
{ TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetExtent");
AssertSz(lpExtent, "CTxtWinHost::TxGetExtent Invalid lpExtent");
// We could implement the TxGetExtent in the following way. However, the
// call to this in ITextServices is implemented in such a way that it
// does something sensible in the face of an error in this call. That
// something sensible is that it sets the extent equal to the current
// client rectangle which is what the following does in a rather convoluted
// manner. Therefore, we dump the following and just return an error.
#if 0
// The window's host extent is always the same as the client
// rectangle.
RECT rc; HRESULT hr = TxGetClientRect(&rc);
// Get our client rectangle
if(SUCCEEDED(hr)) { // Calculate the length & convert to himetric
lpExtent->cx = DXtoHimetricX(rc.right - rc.left, W32->GetXPerInchScreenDC()); lpExtent->cy = DYtoHimetricY(rc.bottom - rc.top, W32->GetYPerInchScreenDC()); }
return hr; #endif // 0
return E_NOTIMPL; }
/*
* CTxtWinHost::TxGetSelectionBarWidth (lSelBarWidth) * * @mfunc * Returns size of selection bar in HIMETRIC * * @rdesc * S_OK <nl> */ HRESULT CTxtWinHost::TxGetSelectionBarWidth ( LONG *lSelBarWidth) //@parm Where to return selection bar width
// in HIMETRIC
{ *lSelBarWidth = (_dwStyle & ES_SELECTIONBAR) ? W32->GetDxSelBar() : 0; return S_OK; }
//
// ITextHost2 methods
//
/*
* CTxtWinHost::TxIsDoubleClickPending * * @mfunc Look into the message queue for this hwnd and see if a * double click is pending. This enables TextServices to * effeciently transition between two inplace active objects. * * @rdesc BOOL */ BOOL CTxtWinHost::TxIsDoubleClickPending() { MSG msg;
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxIsDoubleClickPending");
if(PeekMessage(&msg, _hwnd, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_NOREMOVE | PM_NOYIELD)) { return TRUE; } return FALSE; }
/*
* CTxtWinHost::TxGetWindow * * @mfunc Fetches the window associated with this control (or * set of controls potentially). Useful for answering * IOleWindow::GetWindow. * * @rdesc HRESULT */ HRESULT CTxtWinHost::TxGetWindow(HWND *phwnd) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::GetWindow"); *phwnd = _hwnd; return NOERROR; }
/*
* CTxtWinHost::SetForegroundWindow * * @mfunc Sets window to foreground window & gives the focus * * @rdesc NOERROR - succeeded * E_FAIL - failed. */ HRESULT CTxtWinHost::TxSetForegroundWindow() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::SetForegroundWindow");
if(!SetForegroundWindow(_hwnd)) SetFocus(_hwnd);
return NOERROR; }
/*
* CTxtWinHost::TxGetPalette * * @mfunc Returns application specific palette if there is one * * @rdesc ~NULL - there was one * NULL - use default palette */ HPALETTE CTxtWinHost::TxGetPalette() { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetPalette");
return _hpal; }
/*
* CTxtWinHost::TxGetFEFlags * * @mfunc return FE settings * * @rdesc NOERROR - succeeded * E_FAIL - failed. */ HRESULT CTxtWinHost::TxGetFEFlags(LONG *pFEFlags) { TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CTxtWinHost::TxGetFEFlags");
if (!pFEFlags) return E_INVALIDARG; *pFEFlags = 0;
if (_usIMEMode == ES_NOIME) *pFEFlags |= ES_NOIME; if (_usIMEMode == ES_SELFIME) *pFEFlags |= ES_SELFIME;
return NOERROR; }
// Helper function in edit.cpp
LONG GetECDefaultHeightAndWidth( ITextServices *pts, HDC hdc, LONG lZoomNumerator, LONG lZoomDenominator, LONG yPixelsPerInch, LONG *pxAveWidth, LONG *pxOverhang, LONG *pxUnderhang);
/*
* CTxtWinHost::OnSetMargins * * @mfunc Handle EM_SETMARGINS message * * @rdesc None. */ void CTxtWinHost::OnSetMargins( DWORD fwMargin, //@parm Type of requested operation
DWORD xLeft, //@parm Where to put left margin
DWORD xRight) //@parm Where to put right margin
{ LONG xLeftMargin = -1; LONG xRightMargin = -1; HDC hdc;
if(EC_USEFONTINFO == fwMargin) { // Get the DC since it is needed for the call
hdc = GetDC(_hwnd);
// Multiline behaves differently than single line
if (_dwStyle & ES_MULTILINE) { // Multiline - over/underhange controls margin
GetECDefaultHeightAndWidth(_pserv, hdc, 1, 1, W32->GetYPerInchScreenDC(), NULL, &xLeftMargin, &xRightMargin); } else { // Single line edit controls set the margins to
// the average character width on both left and
// right.
GetECDefaultHeightAndWidth(_pserv, hdc, 1, 1, W32->GetYPerInchScreenDC(), &xLeftMargin, NULL, NULL);
xRightMargin = xLeftMargin; } ReleaseDC(_hwnd, hdc); } else { // The request is for setting exact pixels.
if(EC_LEFTMARGIN & fwMargin) xLeftMargin = xLeft;
if(EC_RIGHTMARGIN & fwMargin) xRightMargin = xRight; }
// Set left margin if so requested
if (xLeftMargin != -1) _rcViewInset.left = W32->DXtoHimetricX(xLeftMargin, W32->GetXPerInchScreenDC());
// Set right margin if so requested
if (xRightMargin != -1) _rcViewInset.right = W32->DXtoHimetricX(xRightMargin, W32->GetXPerInchScreenDC());
if (xLeftMargin != -1 || xRightMargin != -1) _pserv->OnTxPropertyBitsChange(TXTBIT_VIEWINSETCHANGE, TXTBIT_VIEWINSETCHANGE); }
/*
* CTxtWinHost::SetScrollInfo * * @mfunc Set scrolling information for the scroll bar. */ void CTxtWinHost::SetScrollInfo( INT fnBar, //@parm Specifies scroll bar to be updated
BOOL fRedraw) //@parm whether redraw is necessary
{ // Set up the basic structure for the call
SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL;
AssertSz(_pserv != NULL, "CTxtWinHost::SetScrollInfo called with NULL _pserv");
// Call back to the control to get the parameters
if(fnBar == SB_HORZ) { _pserv->TxGetHScroll((LONG *) &si.nMin, (LONG *) &si.nMax, (LONG *) &si.nPos, (LONG *) &si.nPage, NULL); } else { _pserv->TxGetVScroll((LONG *) &si.nMin, (LONG *) &si.nMax, (LONG *) &si.nPos, (LONG *) &si.nPage, NULL); }
// Do the call
::SetScrollInfo(_hwnd, fnBar, &si, fRedraw); }
/*
* CTxtWinHost::SetScrollBarsForWmEnable * * @mfunc Enable/Disable scroll bars * * @rdesc None. */ void CTxtWinHost::SetScrollBarsForWmEnable( BOOL fEnable) //@parm Whether scrollbars s/b enabled or disabled.
{ if(!_pserv) // If no edit object,
return; // no scrollbars
BOOL fHoriz = FALSE; BOOL fVert = FALSE; UINT wArrows = fEnable ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
_pserv->TxGetHScroll(NULL, NULL, NULL, NULL, &fHoriz); _pserv->TxGetVScroll(NULL, NULL, NULL, NULL, &fVert);
if(fHoriz) // There is a horizontal scroll bar
W32->EnableScrollBar(_hwnd, SB_HORZ, wArrows);
if(fVert) // There is a vertical scroll bar
W32->EnableScrollBar(_hwnd, SB_VERT, wArrows); }
/*
* CTxtWinHost::SetScrollBarsForWmEnable * * @mfunc Notification that Text Services is released. * * @rdesc None. */ void CTxtWinHost::TxFreeTextServicesNotification() { _fTextServiceFree = TRUE; }
/*
* CTxtWinHost::TxGetEditStyle * * @mfunc Get Edit Style flags * * @rdesc NOERROR is data available. */ HRESULT CTxtWinHost::TxGetEditStyle( DWORD dwItem, DWORD *pdwData) { if (!pdwData) return E_INVALIDARG; *pdwData = 0;
if (dwItem & TXES_ISDIALOG && _fInDialogBox) *pdwData |= TXES_ISDIALOG;
return NOERROR; }
/*
* CTxtWinHost::TxGetWindowStyles * * @mfunc Return window style bits * * @rdesc NOERROR is data available. */ HRESULT CTxtWinHost::TxGetWindowStyles(DWORD *pdwStyle, DWORD *pdwExStyle) { if (!pdwStyle || !pdwExStyle) return E_INVALIDARG;
*pdwStyle = _dwStyle; *pdwExStyle = _dwExStyle;
return NOERROR; }
|