/* * PROJECT: PAINT for ReactOS * LICENSE: LGPL * FILE: base/applications/mspaint/textedit.cpp * PURPOSE: Text editor and font chooser for the text tool * PROGRAMMERS: Benedikt Freisen */ #include "precomp.h" #define CXY_GRIP 3 CTextEditWindow textEditWindow; /* FUNCTIONS ********************************************************/ CTextEditWindow::CTextEditWindow() : m_hFont(NULL), m_hFontZoomed(NULL), m_nAppIsMovingOrSizing(0) { SetRectEmpty(&m_rc); } INT CTextEditWindow::DoHitTest(RECT& rc, POINT pt) { switch (getSizeBoxHitTest(pt, &rc)) { case HIT_NONE: return HTNOWHERE; case HIT_UPPER_LEFT: return HTTOPLEFT; case HIT_UPPER_CENTER: return HTTOP; case HIT_UPPER_RIGHT: return HTTOPRIGHT; case HIT_MIDDLE_LEFT: return HTLEFT; case HIT_MIDDLE_RIGHT: return HTRIGHT; case HIT_LOWER_LEFT: return HTBOTTOMLEFT; case HIT_LOWER_CENTER: return HTBOTTOM; case HIT_LOWER_RIGHT: return HTBOTTOMRIGHT; case HIT_BORDER: return HTCAPTION; // Enable drag move case HIT_INNER: return HTCLIENT; } return HTNOWHERE; } void CTextEditWindow::DrawGrip(HDC hDC, RECT& rc) { drawSizeBoxes(hDC, &rc, TRUE, NULL); } void CTextEditWindow::FixEditPos(LPCTSTR pszOldText) { CString szText; GetWindowText(szText); RECT rcParent; ::GetWindowRect(m_hwndParent, &rcParent); RECT rc, rcWnd, rcText; GetWindowRect(&rcWnd); rcText = rcWnd; HDC hDC = GetDC(); if (hDC) { SelectObject(hDC, m_hFontZoomed); TEXTMETRIC tm; GetTextMetrics(hDC, &tm); szText += TEXT("x"); // This is a trick to enable the g_ptEnd newlines const UINT uFormat = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_EXPANDTABS | DT_WORDBREAK; DrawText(hDC, szText, -1, &rcText, uFormat | DT_CALCRECT); if (tm.tmDescent > 0) rcText.bottom += tm.tmDescent; ReleaseDC(hDC); } UnionRect(&rc, &rcText, &rcWnd); ::MapWindowPoints(NULL, m_hwndParent, (LPPOINT)&rc, 2); rcWnd = rc; ::GetClientRect(m_hwndParent, &rcParent); IntersectRect(&rc, &rcParent, &rcWnd); ++m_nAppIsMovingOrSizing; MoveWindow(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); --m_nAppIsMovingOrSizing; DefWindowProc(WM_HSCROLL, SB_LEFT, 0); DefWindowProc(WM_VSCROLL, SB_TOP, 0); ::InvalidateRect(m_hwndParent, &rc, TRUE); } LRESULT CTextEditWindow::OnChar(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (wParam == VK_TAB) return 0; // FIXME: Tabs CString szText; GetWindowText(szText); LRESULT ret = DefWindowProc(nMsg, wParam, lParam); FixEditPos(szText); return ret; } LRESULT CTextEditWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (wParam == VK_ESCAPE) { toolsModel.OnCancelDraw(); return 0; } CString szText; GetWindowText(szText); LRESULT ret = DefWindowProc(nMsg, wParam, lParam); FixEditPos(szText); return ret; } LRESULT CTextEditWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT ret = DefWindowProc(nMsg, wParam, lParam); DefWindowProc(WM_HSCROLL, SB_LEFT, 0); DefWindowProc(WM_VSCROLL, SB_TOP, 0); return ret; } LRESULT CTextEditWindow::OnEraseBkGnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HDC hDC = (HDC)wParam; if (!toolsModel.IsBackgroundTransparent()) { RECT rc; GetClientRect(&rc); HBRUSH hbr = CreateSolidBrush(paletteModel.GetBgColor()); FillRect(hDC, &rc, hbr); DeleteObject(hbr); } SetTextColor(hDC, paletteModel.GetFgColor()); return TRUE; } LRESULT CTextEditWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { RECT rc; GetClientRect(&rc); DefWindowProc(nMsg, wParam, lParam); HDC hDC = GetDC(); if (hDC) { DrawGrip(hDC, rc); ReleaseDC(hDC); } return 0; } LRESULT CTextEditWindow::OnNCPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { RECT rc; GetWindowRect(&rc); HDC hDC = GetDCEx(NULL, DCX_WINDOW | DCX_PARENTCLIP); if (hDC) { OffsetRect(&rc, -rc.left, -rc.top); DrawGrip(hDC, rc); ReleaseDC(hDC); } return 0; } LRESULT CTextEditWindow::OnNCCalcSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return 0; // No frame. } LRESULT CTextEditWindow::OnNCHitTest(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; RECT rc; GetWindowRect(&rc); return DoHitTest(rc, pt); } LRESULT CTextEditWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { UINT nHitTest = LOWORD(lParam); if (nHitTest == HTCAPTION) { ::SetCursor(::LoadCursor(NULL, IDC_SIZEALL)); // Enable drag move return FALSE; } return DefWindowProc(nMsg, wParam, lParam); } LRESULT CTextEditWindow::OnMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT ret = DefWindowProc(nMsg, wParam, lParam); if (m_nAppIsMovingOrSizing == 0) { Reposition(); InvalidateEditRect(); } return ret; } LRESULT CTextEditWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT ret = DefWindowProc(nMsg, wParam, lParam); RECT rc; GetClientRect(&rc); SendMessage(EM_SETRECTNP, 0, (LPARAM)&rc); SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); if (m_nAppIsMovingOrSizing == 0) { Reposition(); InvalidateEditRect(); } return ret; } // Hack: Use DECLARE_WND_SUPERCLASS instead! HWND CTextEditWindow::Create(HWND hwndParent) { m_hwndParent = hwndParent; const DWORD style = ES_LEFT | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | WS_CHILD | WS_THICKFRAME; HWND hwnd = ::CreateWindowEx(0, WC_EDIT, NULL, style, 0, 0, 0, 0, hwndParent, NULL, g_hinstExe, NULL); if (hwnd) { #undef SubclassWindow // Don't use this macro SubclassWindow(hwnd); UpdateFont(); PostMessage(WM_SIZE, 0, 0); } return m_hWnd; } void CTextEditWindow::DoFillBack(HWND hwnd, HDC hDC) { if (toolsModel.IsBackgroundTransparent()) return; RECT rc; SendMessage(EM_GETRECT, 0, (LPARAM)&rc); MapWindowPoints(hwnd, (LPPOINT)&rc, 2); HBRUSH hbr = CreateSolidBrush(paletteModel.GetBgColor()); FillRect(hDC, &rc, hbr); DeleteObject(hbr); } LRESULT CTextEditWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { UpdateFont(); return 0; } LRESULT CTextEditWindow::OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ShowWindow(SW_HIDE); if (m_hFont) { DeleteObject(m_hFont); m_hFont = NULL; } if (m_hFontZoomed) { DeleteObject(m_hFontZoomed); m_hFontZoomed = NULL; } return 0; } void CTextEditWindow::InvalidateEditRect() { RECT rc; GetWindowRect(&rc); ::MapWindowPoints(NULL, m_hwndParent, (LPPOINT)&rc, 2); ::InvalidateRect(m_hwndParent, &rc, TRUE); GetClientRect(&rc); MapWindowPoints(canvasWindow, (LPPOINT)&rc, 2); canvasWindow.CanvasToImage(rc); m_rc = rc; } LRESULT CTextEditWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { UpdateFont(); return 0; } LRESULT CTextEditWindow::OnToolsModelSettingsChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { UpdateFont(); return 0; } LRESULT CTextEditWindow::OnToolsModelZoomChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { UpdateFont(); ValidateEditRect(NULL); return 0; } LRESULT CTextEditWindow::OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (wParam == TOOL_TEXT) { UpdateFont(); } else { ShowWindow(SW_HIDE); } return 0; } void CTextEditWindow::UpdateFont() { if (m_hFont) { DeleteObject(m_hFont); m_hFont = NULL; } if (m_hFontZoomed) { DeleteObject(m_hFontZoomed); m_hFontZoomed = NULL; } LOGFONT lf; ZeroMemory(&lf, sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; // registrySettings.CharSet; // Ignore lf.lfWeight = (registrySettings.Bold ? FW_BOLD : FW_NORMAL); lf.lfItalic = registrySettings.Italic; lf.lfUnderline = registrySettings.Underline; lstrcpyn(lf.lfFaceName, registrySettings.strFontName, _countof(lf.lfFaceName)); HDC hdc = GetDC(); if (hdc) { INT nFontSize = registrySettings.PointSize; lf.lfHeight = -MulDiv(nFontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72); ReleaseDC(hdc); } m_hFont = ::CreateFontIndirect(&lf); lf.lfHeight = Zoomed(lf.lfHeight); m_hFontZoomed = ::CreateFontIndirect(&lf); SetWindowFont(m_hWnd, m_hFontZoomed, TRUE); DefWindowProc(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); FixEditPos(NULL); Invalidate(); } LRESULT CTextEditWindow::OnSetSel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT ret = DefWindowProc(nMsg, wParam, lParam); DefWindowProc(WM_HSCROLL, SB_LEFT, 0); DefWindowProc(WM_VSCROLL, SB_TOP, 0); InvalidateEditRect(); return ret; } BOOL CTextEditWindow::GetEditRect(LPRECT prc) const { *prc = m_rc; return TRUE; } void CTextEditWindow::ValidateEditRect(LPCRECT prc OPTIONAL) { if (prc) m_rc = *prc; CRect rc = m_rc; canvasWindow.ImageToCanvas(rc); ++m_nAppIsMovingOrSizing; MoveWindow(rc.left, rc.top, rc.Width(), rc.Height(), TRUE); --m_nAppIsMovingOrSizing; } void CTextEditWindow::Reposition() { CRect rc; GetWindowRect(&rc); ::MapWindowPoints(NULL, canvasWindow, (LPPOINT)&rc, 2); canvasWindow.CanvasToImage(rc); CRect rcImage; canvasWindow.GetImageRect(rcImage); if (rc.bottom > rcImage.bottom) ::OffsetRect(&rc, 0, rcImage.Height()); if (rc.right > rcImage.right) ::OffsetRect(&rc, rcImage.Width(), 0); if (rc.left < 0) ::OffsetRect(&rc, -rc.left, 0); if (rc.top < 0) ::OffsetRect(&rc, 0, -rc.top); canvasWindow.ImageToCanvas(rc); ++m_nAppIsMovingOrSizing; MoveWindow(rc.left, rc.top, rc.Width(), rc.Height(), TRUE); --m_nAppIsMovingOrSizing; } LRESULT CTextEditWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return ::SendMessage(GetParent(), nMsg, wParam, lParam); }