📄 rulerdrawer.cpp
字号:
/* * * rulerdrawer.cpp * Copyright (C) 2006 Michael H. Overlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact at poster_printer@yahoo.com */#include "rulerdrawer.h"#include "fontkeeper.h"#include "mathutils.h"#include "utils.h"#include <windows.h>#include <strsafe.h>#include <vector>RulerDrawer::RulerDrawer( IN const std::vector<uint>& vTicks, IN uint uiMinTickPixelSeparation, IN uint uiMinLabelPixelSeparation, IN double dUnits, IN int iLabelMult, IN const tstring& tstrUnitLabel, IN int iStart, IN int iStop ) { m_vTicks = vTicks; m_uiMinTickPixelSeparation = uiMinTickPixelSeparation; m_uiMinLabelPixelSeparation = uiMinLabelPixelSeparation; m_dUnits = dUnits; m_iLabelMult = iLabelMult; m_tstrUnitLabel = tstrUnitLabel; m_iStart = iStart; m_iStop = iStop; m_hpen = (HPEN) ::GetStockObject(BLACK_PEN); m_cTicksPerDiv = 1; // CALCULATE THE TOTAL NUMBER OF TICKS // CALCULATE TOTAL NUMBER OF SMALLEST TICKS BETWEEN k'th TICK LEVEL m_vuiTickMults.insert(m_vuiTickMults.begin(), m_vTicks.size(), 0); for(uint k = 0; k < m_vTicks.size(); ++k) { m_cTicksPerDiv *= m_vTicks[m_vTicks.size() - k - 1]; //m_cTicksPerDiv *= m_vTicks[k]; m_vuiTickMults[m_vTicks.size() - k - 1] = m_cTicksPerDiv; } // WE HAVE ONE FINAL TICK FOR END POINT m_iStop SO "+1" m_cTicks = m_cTicksPerDiv * (m_iStop - m_iStart) + 1; // FOR EACH TICK, CALCULATE HOW BIG (WHICH LEVEL) IT IS m_viTickLevels.reserve(m_cTicks); for(uint k = 0; k < m_cTicks; ++k) { uint iLevel = 0; for(uint t = 0; t < m_vuiTickMults.size(); ++t) { iLevel += ( (k % m_vuiTickMults[t]) == 0 ? 1 : 0 ); } m_viTickLevels.push_back(iLevel); } // ALLOCATE SPACE FOR LABEL STRINGS FOR MAJOR TICKS // CALCULATE FOR BIGGEST TICK VALUE ITS NUMBER OF DIGITS // INITIALIZE TO ZERO, SO THAT LABELS USING LESS CHARACTERS // THAN THE MAXIMUM ARE EFFECTIVELY NULL-TERMINATED uint kLabelMax = max(abs(m_iStart), abs(m_iStop)) * iLabelMult; m_cMaxLabelDigits = 2; // +2 IN CASE WE NEED A "-" SIGN W/SPACE while(kLabelMax != 0) { kLabelMax /= 10; ++m_cMaxLabelDigits; } uint nLabels = m_iStop - m_iStart + 1; uint nLabelCch = m_cMaxLabelDigits * nLabels; m_ptstrLabels = new TCHAR[nLabelCch]; ZeroMemory(m_ptstrLabels, nLabelCch*sizeof(TCHAR)); // WRITE THE LABEL STRINGS m_vuiLabelSizes.reserve(nLabels); for(uint k = 0; k < nLabels; ++k) { StringCchPrintf( m_ptstrLabels + k*m_cMaxLabelDigits, m_cMaxLabelDigits, TEXT("%d"), (LONG) (m_iStart+k)*m_iLabelMult); int iLen = lstrlen(m_ptstrLabels + k*m_cMaxLabelDigits); m_vuiLabelSizes.push_back(iLen); }}RulerDrawer::~RulerDrawer() { // 7/4 // delete m_ptstrLabels; delete [] m_ptstrLabels;}BOOL RulerDrawer::CanDraw(IN const RulerPlacementSpec &rps, IN OUT LogFontKeeper& lfk) const { SIZE szDest = { RW(rps.m_rDest), RH(rps.m_rDest) }; double dTopLeft = rps.m_dTopLeft; double dBottomRight = rps.m_dBottomRight; RulerPlacementSpec::Direction dir = rps.m_dir; //double dExtSrc = dBottomRight - dTopLeft; double dExtSrc = (dBottomRight - dTopLeft) / m_dUnits; double dExtDest = 0; switch(dir) { case RulerPlacementSpec::eHorizontal: dExtDest = szDest.cx; break; case RulerPlacementSpec::eVertical: dExtDest = szDest.cy; break; default: ASSERTFAIL(); break; } double dTickSep = dExtDest / dExtSrc; BOOL bRetValue = (RoundToLong(dTickSep) >= m_uiMinLabelPixelSeparation); return bRetValue;}VOID RulerDrawer::Draw(OUT HDC hdc, IN const RulerPlacementSpec &rps, IN OUT LogFontKeeper& lfk) const { RECT rDest = rps.m_rDest; double dTopLeft = rps.m_dTopLeft; double dBottomRight = rps.m_dBottomRight; RulerPlacementSpec::Direction dir = rps.m_dir; dTopLeft /= m_dUnits; dBottomRight /= m_dUnits; double dSrcOrg = dTopLeft; double dExtSrc = dBottomRight - dTopLeft ; RECT rPaint = rDest; LONG lTickSpace; double dDestOrg; double dExtDest; switch(dir) { case RulerPlacementSpec::eHorizontal: dDestOrg = rDest.left; dExtDest = RW(rDest); //::InflateRect(&rPaint, 0,-2); lTickSpace = RH(rPaint); lfk.m_lfNew.lfEscapement = 0; break; case RulerPlacementSpec::eVertical: dDestOrg = rDest.top; dExtDest = RH(rDest); //::InflateRect(&rPaint, -2, 0); lTickSpace = RW(rPaint); lfk.m_lfNew.lfEscapement = 900; break; default: ASSERTFAIL(); break; } lfk.m_lfNew.lfHeight = lTickSpace / 2; //HBRUSH hBrushOld = (HBRUSH) ::SelectObject(hdc, ::GetStockObject(LTGRAY_BRUSH)); //::PatBlt(hdc, rDest.left, rDest.top, RW(rDest), RH(rDest), PATCOPY); //::SelectObject(hdc, hBrushOld); //::PatBlt(hdc, rPaint.left, rPaint.top, RW(rPaint), RH(rPaint), WHITENESS); double dScaleFactor = dExtDest / dExtSrc; uint uiMinTickLevel = 0; uint uiTickMults = m_cTicksPerDiv; for(; uiMinTickLevel < m_vTicks.size(); ++uiMinTickLevel) { double dTickSep = dScaleFactor / uiTickMults; uint uiMinSep = /*(uiMinTickLevel == m_vTicks.size() - 1) ? */ this->m_uiMinTickPixelSeparation/*: m_uiMinLabelPixelSeparation*/; if (RoundToLong(dTickSep) >= uiMinSep) { break; } uiTickMults /= m_vuiTickMults[m_vTicks.size() - uiMinTickLevel - 1]; } std::vector<int> viTickSize(m_vTicks.size()+1); for(uint k = 0; k < viTickSize.size(); ++k) { //viTickSize[viTickSize.size() - k - 1] = lTickSpace / (k+2); viTickSize[viTickSize.size() - k - 1] = lTickSpace / (1 << (k ? k : 1)); } LONG lTextDisp = lTickSpace / 2; //COLORREF clrBkOld = ::SetBkColor(hdc, COLOR_BTNFACE); COLORREF clrBkOld = ::SetBkColor(hdc, ::GetSysColor(COLOR_BTNFACE)); int iOldBkMode = /*::SetBkMode(hdc, TRANSPARENT);*/ ::SetBkMode(hdc, OPAQUE); HPEN hPenOld = (HPEN) SelectObject(hdc, m_hpen); HFONT hFontOld = (HFONT) SelectObject(hdc, lfk.GetFont()); UINT uiOldAlign = ::SetTextAlign(hdc, TA_CENTER | TA_BOTTOM ); //HRGN hRgnOld = ::CreateRectRgn(0,0,1,1); //int iClipCode = ::GetClipRgn(hdc, hRgnOld); //::IntersectClipRect(hdc, rPaint.left, rPaint.top, rPaint.right, rPaint.bottom); // I SHOULD CALCULATE WHICH TICKS ARE VISIBLE INSTEAD // MAYBE SHOULD NOT PRECALCULATE LABELS THE WAY I DO ALSO PTSTR ptstr = m_ptstrLabels; uint uiLabel = 0; for(uint k = 0; k < m_cTicks; ++k) { double dSrcTickPos = m_iStart + (double) k / m_cTicksPerDiv; double dDestTickPos = (dSrcTickPos - dSrcOrg) * dScaleFactor + dDestOrg; LONG lDestTickPos = RoundToLong(dDestTickPos); uint iTickLevel = m_viTickLevels[k]; //7/8 WANT THE LAST TICK //BOOL bDrawTick = // iTickLevel >= uiMinTickLevel && // ( (dir == RulerPlacementSpec::eHorizontal) ? // (rPaint.left <= lDestTickPos && lDestTickPos < rPaint.right) : // (rPaint.top <= lDestTickPos && lDestTickPos < rPaint.bottom) // ); BOOL bDrawTick = iTickLevel >= uiMinTickLevel && ( (dir == RulerPlacementSpec::eHorizontal) ? (rPaint.left <= lDestTickPos && lDestTickPos <= rPaint.right) : (rPaint.top <= lDestTickPos && lDestTickPos <= rPaint.bottom) ); if (bDrawTick) { uint iTickSize = k ? viTickSize[iTickLevel] : (lTickSpace * 2 / 3); POINT ptTickFrom, ptTickTo, ptText; switch(dir) { case RulerPlacementSpec::eHorizontal: ptTickFrom.x = ptTickTo.x = ptText.x = lDestTickPos; ptTickFrom.y = rPaint.bottom; ptTickTo.y = rPaint.bottom - iTickSize; //ptText.y = rPaint.bottom - lTextDisp; ptText.y = rPaint.bottom - lTextDisp / 3; if (k == 0) { ::MoveToEx(hdc, ptTickFrom.x+1, ptTickFrom.y, NULL); ::LineTo(hdc, ptTickTo.x+1, ptTickTo.y); } break; case RulerPlacementSpec::eVertical: ptTickFrom.y = ptTickTo.y = ptText.y = lDestTickPos; ptTickFrom.x = rPaint.right; ptTickTo.x = rPaint.right - iTickSize; //ptText.x = rPaint.right - lTextDisp; ptText.x = rPaint.right - lTextDisp / 3; if (k == 0) { ::MoveToEx(hdc, ptTickFrom.x, ptTickFrom.y+1, NULL); ::LineTo(hdc, ptTickTo.x, ptTickTo.y+1); } break; default: break; } ::MoveToEx(hdc, ptTickFrom.x, ptTickFrom.y, NULL); ::LineTo(hdc, ptTickTo.x, ptTickTo.y); if (iTickLevel == m_vTicks.size()) { uint uiLen = this->m_vuiLabelSizes[uiLabel ++]; // CHECK LABEL FULLY FALLS WITHIN THE CLIPPING REGION -- OTHERWISE LOOKS UGLY //DWORD dwExt = ::GetTabbedTextExtent(hdc, ptstr, uiLen, 0, NULL); //WORD cx = LOWORD(dwExt); //WORD cy = HIWORD(dwExt); //RECT rText = { ptText.x, ptText.y, ptText.x, ptText.y }; //::InflateRect(&rText, cx/2, cy/2); //RECT rTemp; //::IntersectRect(&rTemp, &rText, &rPaint); //if (::EqualRect(&rTemp, &rText)) { if (k!=0) { TextOut(hdc, ptText.x, ptText.y, ptstr, uiLen); } //} ptstr += m_cMaxLabelDigits; } } else if (iTickLevel == m_vTicks.size()) { ptstr += m_cMaxLabelDigits; ++uiLabel; } } //::SelectClipRgn(hdc, (iClipCode == 1) ? hRgnOld : NULL); //::DeleteObject(hRgnOld); ::SetTextAlign(hdc, uiOldAlign); ::SelectObject(hdc, hFontOld); ::SelectObject(hdc, hPenOld); ::SetBkColor(hdc, clrBkOld); //::SetBkColor(hdc, clrBkOld); ::SetBkMode(hdc, iOldBkMode);}// ********************************************************************************************************// ** class Ruler ***************************************************************************************// ********************************************************************************************************BOOL Ruler::Set(const RulerDrawer *prd, const RulerPlacementSpec& rps, LogFontKeeper *plfk) { BOOL bRetValue = FALSE; if (m_prd != prd || m_rps != rps || m_plfk != plfk) { bRetValue = TRUE; m_prd = prd; m_rps = rps; m_plfk = plfk; if (m_prd != NULL) { m_bCanDraw = m_prd->CanDraw(m_rps, *m_plfk); } else { m_bCanDraw = FALSE; } } return bRetValue;}void Ruler::Draw(OUT HDC hdc) { m_prd->Draw(hdc, m_rps, *m_plfk);}BOOL Ruler::operator !=(const Ruler &r) const { //return //m_bCanDraw ^ r.CanDraw() || //m_bCanDraw && r.CanDraw() && //( m_rps != r.GetPlacement() || // m_prd != r.m_prd || // m_plfk != r.m_plfk //); BOOL bRetValue = lxor(m_bCanDraw, r.CanDraw()) || m_bCanDraw && r.CanDraw() && ( m_rps != r.GetPlacement() || m_prd != r.m_prd || m_plfk != r.m_plfk ); return bRetValue;}// ********************************************************************************************************// ** MODULE PUBLIC ROUTINES ****************************************************************************// ********************************************************************************************************BOOL RulerUnitLabelChanged(const Ruler &rNew, const Ruler &rOld) { //return // rNew.CanDraw() ^ rOld.CanDraw() || // rNew.CanDraw() && rOld.CanDraw() && rNew.GetUnitLabel() != rOld.GetUnitLabel(); BOOL bRetValue = lxor(rNew.CanDraw(), rOld.CanDraw()) || rNew.CanDraw() && rOld.CanDraw() && rNew.GetUnitLabel() != rOld.GetUnitLabel(); return bRetValue;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -