Something went wrong. Try again.
Reactos
Something went wrong. Try again.
13 kB · 518 lines
C++
at listview
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519/* * PROJECT: PAINT for ReactOS * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) * PURPOSE: Text editor and font chooser for the text tool * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net> */
#include "precomp.h"
#define CXY_GRIP 3
CTextEditWindow textEditWindow;
/* FUNCTIONS ********************************************************/
CTextEditWindow::CTextEditWindow() : m_hFont(NULL) , m_hFontZoomed(NULL){ 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(LPCWSTR pszOldText){ CStringW szText; GetWindowText(szText);
RECT rcParent; ::GetWindowRect(m_hwndParent, &rcParent);
CRect rc, rcWnd, rcText; GetWindowRect(&rcWnd); rcText = rcWnd;
HDC hDC = GetDC(); if (hDC) { SelectObject(hDC, m_hFontZoomed); TEXTMETRIC tm; GetTextMetrics(hDC, &tm); szText += L"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; DrawTextW(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); rc.IntersectRect(&rcParent, &rcWnd);
MoveWindow(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
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
CStringW 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.OnEndDraw(TRUE); return 0; }
CStringW 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){ CRect rc; GetWindowRect(&rc);
HDC hDC = GetDCEx(NULL, DCX_WINDOW | DCX_PARENTCLIP); if (hDC) { rc.OffsetRect(-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){ if (CWaitCursor::IsWaiting()) { bHandled = FALSE; return 0; }
UINT nHitTest = LOWORD(lParam); if (nHitTest == HTCAPTION) { ::SetCursor(::LoadCursorW(NULL, (LPCWSTR)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); 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));
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; }
LOGFONTW lf; ZeroMemory(&lf, sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; // registrySettings.CharSet; // Ignore lf.lfWeight = (registrySettings.Bold ? FW_BOLD : FW_NORMAL); lf.lfItalic = (BYTE)registrySettings.Italic; lf.lfUnderline = (BYTE)registrySettings.Underline; StringCchCopyW(lf.lfFaceName, _countof(lf.lfFaceName), registrySettings.strFontName);
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);
MoveWindow(rc.left, rc.top, rc.Width(), rc.Height(), TRUE);}
LRESULT CTextEditWindow::OnMoving(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ // Restrict the window position to the image area LPRECT prcMoving = (LPRECT)lParam; CRect rcMoving = *prcMoving;
CRect rcImage; canvasWindow.GetImageRect(rcImage); canvasWindow.ImageToCanvas(rcImage); canvasWindow.MapWindowPoints(NULL, &rcImage);
CRect rcWnd; GetWindowRect(&rcWnd); INT cx = rcWnd.Width(), cy = rcWnd.Height();
if (rcMoving.left < rcImage.left) { rcMoving.left = rcImage.left; rcMoving.right = rcImage.left + cx; } else if (rcMoving.right > rcImage.right) { rcMoving.right = rcImage.right; rcMoving.left = rcImage.right - cx; }
if (rcMoving.top < rcImage.top) { rcMoving.top = rcImage.top; rcMoving.bottom = rcImage.top + cy; } else if (rcMoving.bottom > rcImage.bottom) { rcMoving.bottom = rcImage.bottom; rcMoving.top = rcImage.bottom - cy; }
*prcMoving = rcMoving; Invalidate(TRUE); return TRUE;}
LRESULT CTextEditWindow::OnSizing(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ // Restrict the window size to the image area LPRECT prcSizing = (LPRECT)lParam; CRect rcSizing = *prcSizing;
CRect rcImage; canvasWindow.GetImageRect(rcImage); canvasWindow.ImageToCanvas(rcImage); canvasWindow.MapWindowPoints(NULL, &rcImage);
// Horizontally switch (wParam) { case WMSZ_BOTTOMLEFT: case WMSZ_LEFT: case WMSZ_TOPLEFT: if (rcSizing.left < rcImage.left) rcSizing.left = rcImage.left; break; case WMSZ_BOTTOMRIGHT: case WMSZ_RIGHT: case WMSZ_TOPRIGHT: if (rcSizing.right > rcImage.right) rcSizing.right = rcImage.right; break; case WMSZ_TOP: case WMSZ_BOTTOM: default: break; }
// Vertically switch (wParam) { case WMSZ_BOTTOM: case WMSZ_BOTTOMLEFT: case WMSZ_BOTTOMRIGHT: if (rcSizing.bottom > rcImage.bottom) rcSizing.bottom = rcImage.bottom; break; case WMSZ_TOP: case WMSZ_TOPLEFT: case WMSZ_TOPRIGHT: if (rcSizing.top < rcImage.top) rcSizing.top = rcImage.top; break; case WMSZ_LEFT: case WMSZ_RIGHT: default: break; }
*prcSizing = rcSizing; Invalidate(TRUE); return TRUE;}
LRESULT CTextEditWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ return ::SendMessageW(GetParent(), nMsg, wParam, lParam);}
LRESULT CTextEditWindow::OnCut(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ LRESULT ret = DefWindowProc(nMsg, wParam, lParam); Invalidate(TRUE); // Redraw return ret;}
LRESULT CTextEditWindow::OnPaste(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ LRESULT ret = DefWindowProc(nMsg, wParam, lParam); FixEditPos(NULL); return ret;}
LRESULT CTextEditWindow::OnClear(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ LRESULT ret = DefWindowProc(nMsg, wParam, lParam); Invalidate(TRUE); // Redraw return ret;}