/** * @file XTPFlowGraphDrawContext.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" #include "GraphicLibrary/GdiPlus/XTPGdiPlus.h" #include "Common/XTPTypeId.h" #include "Common/XTPCasting.h" #include "Common/XTPFramework.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPVC80Helpers.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPImageManager.h" #include "Common/Base/Types/XTPSize.h" #include #include "Markup/XTPMarkupObject.h" #include "Markup/XTPMarkupInputElement.h" #include "Markup/XTPMarkupUIElement.h" #include "Markup/XTPMarkupContext.h" #include "Markup/XTPMarkupDrawingContext.h" #include "FlowGraph/XTPFlowGraphTools.h" #include "FlowGraph/XTPFlowGraphDrawContext.h" #include "FlowGraph/XTPFlowGraphImage.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif using namespace Gdiplus; using namespace Gdiplus::DllExports; ////////////////////////////////////////////////////////////////////////// // CXTPFlowGraphDrawContext CXTPFlowGraphDrawContext::CXTPFlowGraphDrawContext(HDC hDC, HDC /*hAttribDC*/, BOOL bPrinting, BOOL bSaveToFile) { m_hDC = hDC; m_bPrinting = bPrinting; m_bSaveToFile = bSaveToFile; #if 0 SetSmoothingMode(0); #endif m_hActiveBrush = NULL; m_hActivePen = NULL; m_hActiveFont = NULL; ::GetClipBox(m_hDC, m_rcClipRect); } void CXTPFlowGraphDrawContext::SetSmoothingMode(int /*nMode*/) { } CXTPFlowGraphDrawContext::~CXTPFlowGraphDrawContext() { if (m_hActivePen) DeleteObject(m_hActivePen); } void CXTPFlowGraphDrawContext::SetWorldTransform(CPoint ptOffset, double dZoomLevel) { ::SetMapMode(m_hDC, MM_ANISOTROPIC); ::SetViewportExtEx(m_hDC, int(dZoomLevel * 96), int(dZoomLevel * 96), 0); ::SetWindowExtEx(m_hDC, int(96), int(96), 0); CSize m_sizeWinExt, m_sizeVpExt; ::GetWindowExtEx(m_hDC, &m_sizeWinExt); ::GetViewportExtEx(m_hDC, &m_sizeVpExt); SetViewportOrgEx(m_hDC, -ptOffset.x * m_sizeVpExt.cx / m_sizeWinExt.cx, -ptOffset.y * m_sizeVpExt.cy / m_sizeWinExt.cy, NULL); ::GetClipBox(m_hDC, m_rcClipRect); } void CXTPFlowGraphDrawContext::SetClipRect(CRect /*rc*/) { } CRect CXTPFlowGraphDrawContext::GetClipRect() const { return m_rcClipRect; } void CXTPFlowGraphDrawContext::Clear(COLORREF clr) { FillSolidRect(m_rcClipRect, clr); } void CXTPFlowGraphDrawContext::FillSolidRect(LPCRECT lpRect, COLORREF clr) { if ((clr & 0xFF000000) == 0) { ::SetBkColor(m_hDC, clr); ::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL); } else { LPDWORD lpBits; HBITMAP hBitmap = CXTPImageManager::Create32BPPDIBSection(m_hDC, 1, 1, (LPBYTE*)&lpBits); if (hBitmap) { lpBits[0] = RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)); HDC hDC = CreateCompatibleDC(m_hDC); HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap); XTPImageManager()->AlphaBlend2(m_hDC, lpRect, hDC, CRect(0, 0, 1, 1), 100); SelectObject(hDC, hOldBitmap); DeleteObject(hBitmap); DeleteDC(hDC); } } } void CXTPFlowGraphDrawContext::FillSolidRect(int x, int y, int cx, int cy, COLORREF clr) { CRect rect(x, y, x + cx, y + cy); FillSolidRect(rect, clr); } void CXTPFlowGraphDrawContext::Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight) { Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight); } void CXTPFlowGraphDrawContext::Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight) { FillSolidRect(x, y, cx - 1, 1, clrTopLeft); FillSolidRect(x, y, 1, cy - 1, clrTopLeft); FillSolidRect(x + cx, y, -1, cy, clrBottomRight); FillSolidRect(x, y + cy, cx, -1, clrBottomRight); } void CXTPFlowGraphDrawContext::DrawFrame(int x, int y, int cx, int cy, int sz, COLORREF clr) { FillSolidRect(x, y, cx - sz, sz, clr); FillSolidRect(x, y, sz, cy - sz, clr); FillSolidRect(x + cx, y, -sz, cy, clr); FillSolidRect(x, y + cy, cx, -sz, clr); } CSize CXTPFlowGraphDrawContext::MeasureMarkupElement(CXTPMarkupUIElement* pMarkupUIElement) { pMarkupUIElement->GetMarkupContext()->SetDefaultFont(m_hActiveFont); CXTPMarkupDrawingContext dc(pMarkupUIElement->GetMarkupContext(), m_hDC); pMarkupUIElement->Measure(&dc, CSize(INT_MAX, INT_MAX)); CSize sz = pMarkupUIElement->GetDesiredSize(); return sz; } void CXTPFlowGraphDrawContext::DrawMarkupElement(CXTPMarkupUIElement* pMarkupUIElement, LPCRECT lpRect, UINT /*uFormat*/) { // pMarkupUIElement->GetMarkupContext()->SetDefaultFont(m_hActiveFont); // pMarkupUIElement->GetMarkupContext()->SetDefaultTextColor(::GetTextColor(m_hDC)); CXTPMarkupDrawingContext dc(pMarkupUIElement->GetMarkupContext(), m_hDC); pMarkupUIElement->Arrange(lpRect); pMarkupUIElement->Render(&dc); } CSize CXTPFlowGraphDrawContext::MeasureString(const CString& str) { if (!m_hActiveFont) return CSize(0, 0); HFONT hOldFont = (HFONT)SelectObject(m_hDC, m_hActiveFont); CSize sz; if (str.GetLength() != 0) { ::GetTextExtentPoint(m_hDC, str, str.GetLength(), &sz); } else { ::GetTextExtentPoint(m_hDC, _T(" "), 1, &sz); } ::SelectObject(m_hDC, hOldFont); return sz; } void CXTPFlowGraphDrawContext::DrawText(LPCTSTR lpszText, LPCRECT lpRect, UINT uFormat) { if (!m_hActiveFont) return; HFONT hOldFont = (HFONT)SelectObject(m_hDC, m_hActiveFont); ::SetBkMode(m_hDC, TRANSPARENT); ::DrawText(m_hDC, lpszText, (int)_tcslen(lpszText), (LPRECT)lpRect, uFormat | DT_SINGLELINE); ::SelectObject(m_hDC, hOldFont); } void CXTPFlowGraphDrawContext::DrawCurve(Gdiplus::GraphicsPath* pPath) { if (!pPath) return; int nCount = pPath->GetPointCount(); Point* lppt = new Point[XTPToUIntChecked(nCount)]; pPath->GetPathPoints(lppt, nCount); BYTE* pTypes = new BYTE[XTPToUIntChecked(nCount)]; pPath->GetPathTypes(pTypes, nCount); CDC* pDC = CDC::FromHandle(m_hDC); int nIndex; Point* pptLastMoveTo = NULL; HPEN hOldPen = (HPEN)SelectObject(m_hDC, m_hActivePen); // for each of the points we have... for (nIndex = 0; nIndex < nCount; nIndex++) { switch (pTypes[nIndex]) { // React to information from the path by drawing the data // we received. For each of the points, record our own // "last active point" so we can close figures, lines, and // Beziers. case PathPointTypeStart: if (pptLastMoveTo != NULL && nIndex > 0) pDC->LineTo(pptLastMoveTo->X, pptLastMoveTo->Y); pDC->MoveTo(lppt[nIndex].X, lppt[nIndex].Y); pptLastMoveTo = &lppt[nIndex]; break; case PathPointTypeLine | PathPointTypeCloseSubpath: pDC->LineTo(lppt[nIndex].X, lppt[nIndex].Y); if (pptLastMoveTo != NULL) pDC->LineTo(pptLastMoveTo->X, pptLastMoveTo->Y); pptLastMoveTo = NULL; break; case PathPointTypeLine: pDC->LineTo(lppt[nIndex].X, lppt[nIndex].Y); break; case PathPointTypeBezier | PathPointTypeCloseSubpath: _ASSERTE(nIndex + 2 <= nCount); pDC->PolyBezierTo((POINT*)&lppt[nIndex], 3); nIndex += 2; if (pptLastMoveTo != NULL) pDC->LineTo(pptLastMoveTo->X, pptLastMoveTo->Y); pptLastMoveTo = NULL; break; case PathPointTypeBezier: _ASSERTE(nIndex + 2 <= nCount); pDC->PolyBezierTo((POINT*)&lppt[nIndex], 3); nIndex += 2; break; } } delete[] lppt; delete[] pTypes; SelectObject(m_hDC, hOldPen); } void CXTPFlowGraphDrawContext::Ellipse(LPCRECT lpRect) { HBRUSH hOldBrush = 0; HPEN hOldPen = 0; if (m_hActiveBrush) { hOldBrush = (HBRUSH)SelectObject(m_hDC, m_hActiveBrush); } if (m_hActivePen) { hOldPen = (HPEN)SelectObject(m_hDC, m_hActivePen); } else { hOldPen = (HPEN)SelectObject(m_hDC, GetStockObject(NULL_PEN)); } ::Ellipse(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); if (hOldBrush) { SelectObject(m_hDC, hOldBrush); } if (hOldPen) { SelectObject(m_hDC, hOldPen); } } void CXTPFlowGraphDrawContext::Line(float x1, float y1, float x2, float y2) { if (!m_hActivePen) return; HPEN hOldPen = 0; if (m_hActivePen) { hOldPen = (HPEN)SelectObject(m_hDC, m_hActivePen); } MoveToEx(m_hDC, (int)x1, (int)y1, 0); LineTo(m_hDC, (int)x2, (int)y2); if (hOldPen) { SelectObject(m_hDC, hOldPen); } } void CXTPFlowGraphDrawContext::Line(CPoint p1, CPoint p2) { Line((float)p1.x, (float)p1.y, (float)p2.x, (float)p2.y); } void CXTPFlowGraphDrawContext::SetBrush(COLORREF clr) { if (clr == (COLORREF)-1) m_hActiveBrush = 0; else m_hActiveBrush = m_arrBrushes.GetHandle(clr); } void CXTPFlowGraphDrawContext::SetPen(COLORREF clrPen, int nWidth, BOOL bDashed /*= FALSE*/) { if (m_hActivePen) { DeleteObject(m_hActivePen); m_hActivePen = 0; } if (nWidth) { m_hActivePen = ::CreatePen(bDashed ? PS_DASH : PS_SOLID, nWidth, clrPen); } } void CXTPFlowGraphDrawContext::SetTextColor(COLORREF clr) { ::SetTextColor(m_hDC, clr); } void CXTPFlowGraphDrawContext::SetFont(LOGFONT* lf) { if (!lf) { m_hActiveFont = 0; } else { m_hActiveFont = m_arrFonts.GetHandle(*lf); } } void CXTPFlowGraphDrawContext::DrawGrid(CRect rc, CPoint ptScrollOffset, double dZoomLevel, COLORREF clrGridColor) { double gap = 15.0 * dZoomLevel; double x = -ptScrollOffset.x * dZoomLevel; int cnt = int(x / gap); x -= cnt * gap; while (x < 0) x += gap; while (x > gap) x -= gap; for (x; x < rc.right; x += gap) { FillSolidRect((int)x, rc.top, 1, rc.Height(), clrGridColor); } double y = -ptScrollOffset.y * dZoomLevel; cnt = int(y / gap); y -= cnt * gap; while (y < 0) y += gap; while (y > gap) y -= gap; for (y; y < rc.bottom; y += gap) { FillSolidRect(rc.left, (int)y, rc.Width(), 1, clrGridColor); } } void CXTPFlowGraphDrawContext::GradientFill(CRect rc, COLORREF clrFrom, COLORREF clrTo, BOOL bHoriz) { XTPDrawHelpers()->GradientFill(CDC::FromHandle(m_hDC), rc, clrFrom, clrTo, bHoriz); } void CXTPFlowGraphDrawContext::DrawImage(CXTPFlowGraphImage* pImage, CRect rc) { CXTPImageManagerIcon* pIcon = pImage->GetIcon(); if (pIcon) { pIcon->Draw(CDC::FromHandle(m_hDC), rc.TopLeft(), rc.Size()); } } void CXTPFlowGraphDrawContext::DrawSelectionRect(CRect rcSelectedArea) { COLORREF clrSelectionFrame = GetSysColor(COLOR_HIGHLIGHT); COLORREF clrSelection = clrSelectionFrame | 0x88000000; FillSolidRect(rcSelectedArea, clrSelection); Draw3dRect(rcSelectedArea, clrSelectionFrame, clrSelectionFrame); } void CXTPFlowGraphDrawContext::FillPolygon(const POINT* pts, int nCount) { HBRUSH hOldBrush = 0; HPEN hOldPen = 0; if (m_hActiveBrush) { hOldBrush = (HBRUSH)SelectObject(m_hDC, m_hActiveBrush); } if (m_hActivePen) { hOldPen = (HPEN)SelectObject(m_hDC, m_hActivePen); } else { hOldPen = (HPEN)SelectObject(m_hDC, GetStockObject(NULL_PEN)); } ::Polygon(m_hDC, pts, nCount); if (hOldBrush) { SelectObject(m_hDC, hOldBrush); } if (hOldPen) { SelectObject(m_hDC, hOldPen); } }