mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 02:13:29 +00:00
![Katayama Hirofumi MZ](/assets/img/avatar_default.png)
- Move imageArea code into canvasWindow. - Delete imgarea.cpp, imgarea.h, and imageArea. - Add CCanvasWindow::ImageToCanvas and CCanvasWindow::CanvasToImage to convert the coordinates. - Realize drawing of resizing image area. CORE-18867
436 lines
11 KiB
C++
436 lines
11 KiB
C++
/*
|
|
* 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 last 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, hProgInstance, 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);
|
|
}
|