/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "accessibleruler.hxx" #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::accessibility; #define RULER_OFF 3 #define RULER_RESIZE_OFF 4 #define RULER_MIN_SIZE 3 #define RULER_VAR_SIZE 8 #define RULER_UPDATE_LINES 0x01 #define RULER_CLIP 150 #define RULER_UNIT_MM 0 #define RULER_UNIT_CM 1 #define RULER_UNIT_M 2 #define RULER_UNIT_KM 3 #define RULER_UNIT_INCH 4 #define RULER_UNIT_FOOT 5 #define RULER_UNIT_MILE 6 #define RULER_UNIT_POINT 7 #define RULER_UNIT_PICA 8 #define RULER_UNIT_CHAR 9 #define RULER_UNIT_LINE 10 #define RULER_UNIT_COUNT 11 namespace { /** * Pre-calculates glyph items for rText on rRenderContext. Subsequent calls * avoid the calculation and just return a pointer to rTextGlyphs. */ SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext, const OUString& rText, SalLayoutGlyphs& rTextGlyphs) { if (rTextGlyphs.IsValid()) // Use pre-calculated result. return &rTextGlyphs; // Calculate glyph items. std::unique_ptr pLayout = rRenderContext.ImplLayout( rText, 0, rText.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); if (!pLayout) return nullptr; // Remember the calculation result. rTextGlyphs = pLayout->GetGlyphs(); return &rTextGlyphs; } } class ImplRulerData { friend class Ruler; private: std::vector pLines; std::vector pBorders; std::vector pIndents; std::vector pTabs; tools::Long nNullVirOff; tools::Long nRulVirOff; tools::Long nRulWidth; tools::Long nPageOff; tools::Long nPageWidth; tools::Long nNullOff; tools::Long nMargin1; tools::Long nMargin2; // In this context, "frame margin" means paragraph margins (indents) tools::Long nLeftFrameMargin; tools::Long nRightFrameMargin; RulerMarginStyle nMargin1Style; RulerMarginStyle nMargin2Style; bool bAutoPageWidth; bool bTextRTL; public: ImplRulerData(); }; ImplRulerData::ImplRulerData() : nNullVirOff (0), nRulVirOff (0), nRulWidth (0), nPageOff (0), nPageWidth (0), nNullOff (0), nMargin1 (0), nMargin2 (0), nLeftFrameMargin (0), nRightFrameMargin (0), nMargin1Style (RulerMarginStyle::NONE), nMargin2Style (RulerMarginStyle::NONE), bAutoPageWidth (true), // Page width == EditWin width bTextRTL (false) { } const RulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] = { { MapUnit::Map100thMM, 100, 25.0, 25.0, 50.0, 100.0, " mm" }, // MM { MapUnit::Map100thMM, 1000, 100.0, 500.0, 1000.0, 1000.0, " cm" }, // CM { MapUnit::MapMM, 1000, 10.0, 250.0, 500.0, 1000.0, " m" }, // M { MapUnit::MapCM, 100000, 12500.0, 25000.0, 50000.0, 100000.0, " km" }, // KM { MapUnit::Map1000thInch, 1000, 62.5, 125.0, 500.0, 1000.0, "\"" }, // INCH { MapUnit::Map100thInch, 1200, 120.0, 120.0, 600.0, 1200.0, "'" }, // FOOT { MapUnit::Map10thInch, 633600, 63360.0, 63360.0, 316800.0, 633600.0, " miles" }, // MILE { MapUnit::MapPoint, 1, 12.0, 12.0, 12.0, 36.0, " pt" }, // POINT { MapUnit::Map100thMM, 423, 423.0, 423.0, 423.0, 846.0, " pc" }, // PICA { MapUnit::Map100thMM, 371, 371.0, 371.0, 371.0, 743.0, " ch" }, // CHAR { MapUnit::Map100thMM, 551, 551.0, 551.0, 551.0, 1102.0, " li" } // LINE }; static RulerTabData ruler_tab = { 0, // DPIScaleFactor to be set 7, // ruler_tab_width 6, // ruler_tab_height 2, // ruler_tab_height2 2, // ruler_tab_width2 8, // ruler_tab_cwidth 4, // ruler_tab_cwidth2 4, // ruler_tab_cwidth3 2, // ruler_tab_cwidth4 4, // ruler_tab_dheight 1, // ruler_tab_dheight2 5, // ruler_tab_dwidth 3, // ruler_tab_dwidth2 3, // ruler_tab_dwidth3 1, // ruler_tab_dwidth4 5 // ruler_tab_textoff }; void Ruler::ImplInit( WinBits nWinBits ) { // Set default WinBits if ( !(nWinBits & WB_VERT) ) { nWinBits |= WB_HORZ; // RTL: no UI mirroring for horizontal rulers, because // the document is also not mirrored EnableRTL( false ); } // Initialize variables mnWinStyle = nWinBits; // Window-Style mnBorderOff = 0; // Border-Offset mnWinOff = 0; // EditWinOffset mnWinWidth = 0; // EditWinWidth mnWidth = 0; // Window width mnHeight = 0; // Window height mnVirOff = 0; // Offset of VirtualDevice from top-left corner mnVirWidth = 0; // width or height from VirtualDevice mnVirHeight = 0; // height of width from VirtualDevice mnDragPos = 0; // Drag-Position (Null point) mnDragAryPos = 0; // Drag-Array-Index mnDragSize = RulerDragSize::Move; // Did size change at dragging mnDragModifier = 0; // Modifier key at dragging mnExtraStyle = 0; // Style of Extra field mnCharWidth = 371; mnLineHeight = 551; mbCalc = true; // Should recalculate page width mbFormat = true; // Should redraw mbDrag = false; // Currently at dragging mbDragDelete = false; // Has mouse left the dragging area mbDragCanceled = false; // Dragging cancelled? mbAutoWinWidth = true; // EditWinWidth == RulerWidth mbActive = true; // Is ruler active mnUpdateFlags = 0; // What needs to be updated mpData = mpSaveData.get(); // Pointer to normal data meExtraType = RulerExtra::DontKnow; // What is in extra field meDragType = RulerType::DontKnow; // Which element is dragged // Initialize Units mnUnitIndex = RULER_UNIT_CM; meUnit = FieldUnit::CM; maZoom = Fraction( 1, 1 ); // Recalculate border widths if ( nWinBits & WB_BORDER ) mnBorderWidth = 1; else mnBorderWidth = 0; // Settings ImplInitSettings( true, true, true ); // Setup the default size tools::Rectangle aRect; GetOutDev()->GetTextBoundRect( aRect, "0123456789" ); tools::Long nDefHeight = aRect.GetHeight() + RULER_OFF * 2 + ruler_tab.textoff * 2 + mnBorderWidth; Size aDefSize; if ( nWinBits & WB_HORZ ) aDefSize.setHeight( nDefHeight ); else aDefSize.setWidth( nDefHeight ); SetOutputSizePixel( aDefSize ); SetType(WindowType::RULER); } Ruler::Ruler( vcl::Window* pParent, WinBits nWinStyle ) : Window( pParent, nWinStyle & WB_3DLOOK ), maVirDev( VclPtr::Create(*GetOutDev()) ), maMapMode( MapUnit::Map100thMM ), mpSaveData(new ImplRulerData), mpData(nullptr), mpDragData(new ImplRulerData) { // Check to see if the ruler constructor has // already been called before otherwise // we end up with over-scaled elements if (ruler_tab.DPIScaleFactor == 0) { ruler_tab.DPIScaleFactor = GetDPIScaleFactor(); ruler_tab.width *= ruler_tab.DPIScaleFactor; ruler_tab.height *= ruler_tab.DPIScaleFactor; ruler_tab.height2 *= ruler_tab.DPIScaleFactor; ruler_tab.width2 *= ruler_tab.DPIScaleFactor; ruler_tab.cwidth *= ruler_tab.DPIScaleFactor; ruler_tab.cwidth2 *= ruler_tab.DPIScaleFactor; ruler_tab.cwidth3 *= ruler_tab.DPIScaleFactor; ruler_tab.cwidth4 *= ruler_tab.DPIScaleFactor; ruler_tab.dheight *= ruler_tab.DPIScaleFactor; ruler_tab.dheight2 *= ruler_tab.DPIScaleFactor; ruler_tab.dwidth *= ruler_tab.DPIScaleFactor; ruler_tab.dwidth2 *= ruler_tab.DPIScaleFactor; ruler_tab.dwidth3 *= ruler_tab.DPIScaleFactor; ruler_tab.dwidth4 *= ruler_tab.DPIScaleFactor; ruler_tab.textoff *= ruler_tab.DPIScaleFactor; } ImplInit( nWinStyle ); } Ruler::~Ruler() { disposeOnce(); } void Ruler::dispose() { mpSaveData.reset(); mpDragData.reset(); mxAccContext.clear(); Window::dispose(); } void Ruler::ImplVDrawLine(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) { if ( nX1 < -RULER_CLIP ) { nX1 = -RULER_CLIP; if ( nX2 < -RULER_CLIP ) return; } tools::Long nClip = mnVirWidth + RULER_CLIP; if ( nX2 > nClip ) { nX2 = nClip; if ( nX1 > nClip ) return; } if ( mnWinStyle & WB_HORZ ) rRenderContext.DrawLine( Point( nX1, nY1 ), Point( nX2, nY2 ) ); else rRenderContext.DrawLine( Point( nY1, nX1 ), Point( nY2, nX2 ) ); } void Ruler::ImplVDrawRect(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) { if ( nX1 < -RULER_CLIP ) { nX1 = -RULER_CLIP; if ( nX2 < -RULER_CLIP ) return; } tools::Long nClip = mnVirWidth + RULER_CLIP; if ( nX2 > nClip ) { nX2 = nClip; if ( nX1 > nClip ) return; } if ( mnWinStyle & WB_HORZ ) rRenderContext.DrawRect(tools::Rectangle(nX1, nY1, nX2, nY2)); else rRenderContext.DrawRect(tools::Rectangle(nY1, nX1, nY2, nX2)); } void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, tools::Long nY, const OUString& rText, tools::Long nMin, tools::Long nMax) { tools::Rectangle aRect; SalLayoutGlyphs* pTextLayout = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]); rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, {}, pTextLayout); tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left(); tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top(); if ( (nX > -RULER_CLIP) && (nX < mnVirWidth + RULER_CLIP) && ( nX < nMax - nShiftX ) && ( nX > nMin + nShiftX ) ) { if ( mnWinStyle & WB_HORZ ) rRenderContext.DrawText(Point(nX - nShiftX, nY - nShiftY), rText, 0, -1, nullptr, nullptr, pTextLayout); else rRenderContext.DrawText(Point(nY - nShiftX, nX - nShiftY), rText, 0, -1, nullptr, nullptr, pTextLayout); } } void Ruler::ImplInvertLines(vcl::RenderContext& rRenderContext) { // Position lines if (mpData->pLines.empty() || !mbActive || mbDrag || mbFormat || (mnUpdateFlags & RULER_UPDATE_LINES) ) return; tools::Long nNullWinOff = mpData->nNullVirOff + mnVirOff; tools::Long nRulX1 = mpData->nRulVirOff + mnVirOff; tools::Long nRulX2 = nRulX1 + mpData->nRulWidth; tools::Long nY = (RULER_OFF * 2) + mnVirHeight - 1; // Calculate rectangle tools::Rectangle aRect; if (mnWinStyle & WB_HORZ) aRect.SetBottom( nY ); else aRect.SetRight( nY ); // Draw lines for (const RulerLine & rLine : mpData->pLines) { const tools::Long n = rLine.nPos + nNullWinOff; if ((n >= nRulX1) && (n < nRulX2)) { if (mnWinStyle & WB_HORZ ) { aRect.SetLeft( n ); aRect.SetRight( n ); } else { aRect.SetTop( n ); aRect.SetBottom( n ); } tools::Rectangle aTempRect = aRect; if (mnWinStyle & WB_HORZ) aTempRect.SetBottom( RULER_OFF - 1 ); else aTempRect.SetRight( RULER_OFF - 1 ); rRenderContext.Erase(aTempRect); if (mnWinStyle & WB_HORZ) { aTempRect.SetBottom( aRect.Bottom() ); aTempRect.SetTop( aTempRect.Bottom() - RULER_OFF + 1 ); } else { aTempRect.SetRight( aRect.Right() ); aTempRect.SetLeft( aTempRect.Right() - RULER_OFF + 1 ); } rRenderContext.Erase(aTempRect); GetOutDev()->Invert(aRect); } } mnUpdateFlags = 0; } void Ruler::ImplDrawTicks(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nStart, tools::Long nTop, tools::Long nBottom) { const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); double nCenter = nTop + ((nBottom - nTop) / 2); tools::Long nTickLength3 = (nBottom - nTop) * 0.5; tools::Long nTickLength2 = nTickLength3 * 0.66; tools::Long nTickLength1 = nTickLength2 * 0.66; tools::Long nScale = ruler_tab.DPIScaleFactor; tools::Long DPIOffset = nScale - 1; double nTick4 = aImplRulerUnitTab[mnUnitIndex].nTick4; double nTick2 = 0; double nTickCount = aImplRulerUnitTab[mnUnitIndex].nTick1 / nScale; double nTickUnit = 0; tools::Long nTickWidth; bool bNoTicks = false; Size aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode); if (mnUnitIndex == RULER_UNIT_CHAR) { if (mnCharWidth == 0) mnCharWidth = 371; nTick4 = mnCharWidth * 2; nTick2 = mnCharWidth; nTickCount = mnCharWidth; nTickUnit = mnCharWidth; } else if (mnUnitIndex == RULER_UNIT_LINE) { if (mnLineHeight == 0) mnLineHeight = 551; nTick4 = mnLineHeight * 2; nTick2 = mnLineHeight; nTickUnit = mnLineHeight; nTickCount = mnLineHeight; } if (mnWinStyle & WB_HORZ) { nTickWidth = aPixSize.Width(); } else { vcl::Font aFont = rRenderContext.GetFont(); if (mnWinStyle & WB_RIGHT_ALIGNED) aFont.SetOrientation(2700_deg10); else aFont.SetOrientation(900_deg10); rRenderContext.SetFont(aFont); nTickWidth = aPixSize.Height(); } tools::Long nMaxWidth = rRenderContext.PixelToLogic(Size(mpData->nPageWidth, 0), maMapMode).Width(); if (nMaxWidth < 0) nMaxWidth = -nMaxWidth; if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE)) nMaxWidth /= nTickUnit; else nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit; OUString aNumString = OUString::number(nMaxWidth); tools::Long nTxtWidth = rRenderContext.GetTextWidth( aNumString ); const tools::Long nTextOff = 4; // Determine the number divider for ruler drawn numbers - means which numbers // should be shown on the ruler and which should be skipped because the ruler // is not big enough to draw them if (nTickWidth < nTxtWidth + nTextOff) { // Calculate the scale of the ruler tools::Long nMulti = 1; tools::Long nOrgTick4 = nTick4; while (nTickWidth < nTxtWidth + nTextOff) { tools::Long nOldMulti = nMulti; if (nTickWidth == 0) nMulti *= 10; else if (nMulti < 10) nMulti++; else if (nMulti < 100) nMulti += 10; else if (nMulti < 1000) nMulti += 100; else nMulti += 1000; // Overflow - in this case don't draw ticks and exit if (nMulti < nOldMulti) { bNoTicks = true; break; } nTick4 = nOrgTick4 * nMulti; aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode); if (mnWinStyle & WB_HORZ) nTickWidth = aPixSize.Width(); else nTickWidth = aPixSize.Height(); } nTickCount = nTick4; } else { rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); } if (bNoTicks) return; tools::Long n = 0; double nTick = 0.0; double nTick3 = 0; if ((mnUnitIndex != RULER_UNIT_CHAR) && (mnUnitIndex != RULER_UNIT_LINE)) { nTick2 = aImplRulerUnitTab[mnUnitIndex].nTick2; nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3; } Size nTickGapSize; nTickGapSize = rRenderContext.LogicToPixel(Size(nTickCount, nTickCount), maMapMode); tools::Long nTickGap1 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height(); nTickGapSize = rRenderContext.LogicToPixel(Size(nTick2, nTick2), maMapMode); tools::Long nTickGap2 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height(); nTickGapSize = rRenderContext.LogicToPixel(Size(nTick3, nTick3), maMapMode); tools::Long nTickGap3 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height(); while (((nStart - n) >= nMin) || ((nStart + n) <= nMax)) { // Null point if (nTick == 0.0) { if (nStart > nMin) { // 0 is only painted when Margin1 is not equal to zero if ((mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin1 != 0)) { aNumString = "0"; ImplVDrawText(rRenderContext, nStart, nCenter, aNumString); } } } else { aPixSize = rRenderContext.LogicToPixel(Size(nTick, nTick), maMapMode); if (mnWinStyle & WB_HORZ) n = aPixSize.Width(); else n = aPixSize.Height(); // Tick4 - Output (Text) double aStep = nTick / nTick4; double aRest = std::abs(aStep - std::floor(aStep)); double nAcceptanceDelta = 0.0001; rRenderContext.SetFillColor(rStyleSettings.GetShadowColor()); if (aRest < nAcceptanceDelta) { if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE)) aNumString = OUString::number(nTick / nTickUnit); else aNumString = OUString::number(nTick / aImplRulerUnitTab[mnUnitIndex].nTickUnit); tools::Long nHorizontalLocation = nStart + n; ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax); if (nMin < nHorizontalLocation && nHorizontalLocation < nMax) { ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom - 1 * nScale, nHorizontalLocation + DPIOffset, nBottom); ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop, nHorizontalLocation + DPIOffset, nTop + 1 * nScale); } nHorizontalLocation = nStart - n; ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax); if (nMin < nHorizontalLocation && nHorizontalLocation < nMax) { ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom, nHorizontalLocation + DPIOffset, nBottom - 1 * nScale); ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop, nHorizontalLocation + DPIOffset, nTop + 1 * nScale); } } // Tick/Tick2 - Output (Strokes) else { tools::Long nTickLength = nTickLength1; aStep = (nTick / nTick2); aRest = std::abs(aStep - std::floor(aStep)); if (aRest < nAcceptanceDelta) nTickLength = nTickLength2; aStep = (nTick / nTick3); aRest = std::abs(aStep - std::floor(aStep)); if (aRest < nAcceptanceDelta ) nTickLength = nTickLength3; if ((nTickLength == nTickLength1 && nTickGap1 > 6) || (nTickLength == nTickLength2 && nTickGap2 > 6) || (nTickLength == nTickLength3 && nTickGap3 > 6)) { tools::Long nT1 = nCenter - (nTickLength / 2.0); tools::Long nT2 = nT1 + nTickLength - 1; tools::Long nT; nT = nStart + n; if (nT < nMax) ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2); nT = nStart - n; if (nT > nMin) ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2); } } } nTick += nTickCount; } } void Ruler::ImplDrawBorders(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom) { const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); tools::Long n; tools::Long n1; tools::Long n2; tools::Long nTemp1; tools::Long nTemp2; for (std::vector::size_type i = 0; i < mpData->pBorders.size(); i++) { if (mpData->pBorders[i].nStyle & RulerBorderStyle::Invisible) continue; n1 = mpData->pBorders[i].nPos + mpData->nNullVirOff; n2 = n1 + mpData->pBorders[i].nWidth; if (((n1 >= nMin) && (n1 <= nMax)) || ((n2 >= nMin) && (n2 <= nMax))) { if ((n2 - n1) > 3) { rRenderContext.SetLineColor(); rRenderContext.SetFillColor(rStyleSettings.GetFaceColor()); ImplVDrawRect(rRenderContext, n1, nVirTop, n2, nVirBottom); rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); ImplVDrawLine(rRenderContext, n1 + 1, nVirTop, n1 + 1, nVirBottom); ImplVDrawLine(rRenderContext, n1, nVirTop, n2, nVirTop); rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); ImplVDrawLine(rRenderContext, n1, nVirTop, n1, nVirBottom); ImplVDrawLine(rRenderContext, n1, nVirBottom, n2, nVirBottom); ImplVDrawLine(rRenderContext, n2 - 1, nVirTop, n2 - 1, nVirBottom); rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor()); ImplVDrawLine(rRenderContext, n2, nVirTop, n2, nVirBottom); if (mpData->pBorders[i].nStyle & RulerBorderStyle::Variable) { if (n2 - n1 > RULER_VAR_SIZE + 4) { nTemp1 = n1 + (((n2 - n1 + 1) - RULER_VAR_SIZE) / 2); nTemp2 = nVirTop + (((nVirBottom - nVirTop + 1) - RULER_VAR_SIZE) / 2); tools::Long nTemp3 = nTemp1 + RULER_VAR_SIZE - 1; tools::Long nTemp4 = nTemp2 + RULER_VAR_SIZE - 1; tools::Long nTempY = nTemp2; rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); while (nTempY <= nTemp4) { ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY); nTempY += 2; } nTempY = nTemp2 + 1; rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); while (nTempY <= nTemp4) { ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY); nTempY += 2; } } } if (mpData->pBorders[i].nStyle & RulerBorderStyle::Sizeable) { if (n2 - n1 > RULER_VAR_SIZE + 10) { rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); ImplVDrawLine(rRenderContext, n1 + 4, nVirTop + 3, n1 + 4, nVirBottom - 3); ImplVDrawLine(rRenderContext, n2 - 5, nVirTop + 3, n2 - 5, nVirBottom - 3); rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); ImplVDrawLine(rRenderContext, n1 + 5, nVirTop + 3, n1 + 5, nVirBottom - 3); ImplVDrawLine(rRenderContext, n2 - 4, nVirTop + 3, n2 - 4, nVirBottom - 3); } } } else { n = n1 + ((n2 - n1) / 2); rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); ImplVDrawLine(rRenderContext, n - 1, nVirTop, n - 1, nVirBottom); ImplVDrawLine(rRenderContext, n + 1, nVirTop, n + 1, nVirBottom); rRenderContext.SetLineColor(); rRenderContext.SetFillColor(rStyleSettings.GetWindowColor()); ImplVDrawRect(rRenderContext, n, nVirTop, n, nVirBottom); } } } } void Ruler::ImplDrawIndent(vcl::RenderContext& rRenderContext, const tools::Polygon& rPoly, bool bIsHit) { const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor()); rRenderContext.SetFillColor(bIsHit ? rStyleSettings.GetDarkShadowColor() : rStyleSettings.GetWorkspaceColor()); tools::Polygon aPolygon(rPoly); aPolygon.Optimize(PolyOptimizeFlags::CLOSE); rRenderContext.DrawPolygon(aPolygon); } void Ruler::ImplDrawIndents(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom) { tools::Long n; tools::Long nIndentHeight = (mnVirHeight / 2) - 1; tools::Long nIndentWidth2 = nIndentHeight-3; tools::Polygon aPoly(5); for (std::vector::size_type j = 0; j < mpData->pIndents.size(); j++) { if (mpData->pIndents[j].bInvisible) continue; RulerIndentStyle nIndentStyle = mpData->pIndents[j].nStyle; n = mpData->pIndents[j].nPos+mpData->nNullVirOff; if ((n >= nMin) && (n <= nMax)) { if (nIndentStyle == RulerIndentStyle::Bottom) { aPoly.SetPoint(Point(n + 0, nVirBottom - nIndentHeight), 0); aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom - 3), 1); aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom), 2); aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom), 3); aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom - 3), 4); } else { aPoly.SetPoint(Point(n + 0, nVirTop + nIndentHeight), 0); aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop + 3), 1); aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop), 2); aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop), 3); aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop + 3), 4); } if (0 == (mnWinStyle & WB_HORZ)) { Point aTmp; for (sal_uInt16 i = 0; i < 5; i++) { aTmp = aPoly[i]; Point aSet(nVirBottom - aTmp.Y(), aTmp.X()); aPoly[i] = aSet; } } bool bIsHit = false; if (mxCurrentHitTest != nullptr && mxCurrentHitTest->eType == RulerType::Indent) { bIsHit = mxCurrentHitTest->nAryPos == j; } else if(mbDrag && meDragType == RulerType::Indent) { bIsHit = mnDragAryPos == j; } ImplDrawIndent(rRenderContext, aPoly, bIsHit); } } } static void ImplCenterTabPos(Point& rPos, sal_uInt16 nTabStyle) { bool bRTL = 0 != (nTabStyle & RULER_TAB_RTL); nTabStyle &= RULER_TAB_STYLE; rPos.AdjustY(ruler_tab.height/2 ); if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) || ( bRTL && nTabStyle == RULER_TAB_RIGHT) ) { rPos.AdjustX( -(ruler_tab.width / 2) ); } else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) || ( bRTL && nTabStyle == RULER_TAB_LEFT) ) { rPos.AdjustX(ruler_tab.width / 2 ); } } static void lcl_RotateRect_Impl(tools::Rectangle& rRect, const tools::Long nReference, bool bRightAligned) { if (rRect.IsEmpty()) return; tools::Rectangle aTmp(rRect); rRect.SetTop( aTmp.Left() ); rRect.SetBottom( aTmp.Right() ); rRect.SetLeft( aTmp.Top() ); rRect.SetRight( aTmp.Bottom() ); if (bRightAligned) { tools::Long nRef = 2 * nReference; rRect.SetLeft( nRef - rRect.Left() ); rRect.SetRight( nRef - rRect.Right() ); } } static void ImplDrawRulerTab(vcl::RenderContext& rRenderContext, const Point& rPos, sal_uInt16 nStyle, WinBits nWinBits) { if (nStyle & RULER_STYLE_INVISIBLE) return; sal_uInt16 nTabStyle = nStyle & RULER_TAB_STYLE; bool bRTL = 0 != (nStyle & RULER_TAB_RTL); // Scale by the screen DPI scaling factor // However when doing this some of the rectangles // drawn become asymmetric due to the +1 offsets sal_uInt16 DPIOffset = rRenderContext.GetDPIScaleFactor() - 1; // A tabstop is drawn using three rectangles tools::Rectangle aRect1; // A horizontal short line tools::Rectangle aRect2; // A vertical short line tools::Rectangle aRect3; // A small square aRect3.SetEmpty(); if (nTabStyle == RULER_TAB_DEFAULT) { aRect1.SetLeft( rPos.X() - ruler_tab.dwidth2 + 1 ); aRect1.SetTop( rPos.Y() - ruler_tab.dheight2 + 1 ); aRect1.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth + DPIOffset ); aRect1.SetBottom( rPos.Y() ); aRect2.SetLeft( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 ); aRect2.SetTop( rPos.Y() - ruler_tab.dheight + 1 ); aRect2.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 + ruler_tab.dwidth4 - 1 ); aRect2.SetBottom( rPos.Y() ); } else if ((!bRTL && nTabStyle == RULER_TAB_LEFT) || (bRTL && nTabStyle == RULER_TAB_RIGHT)) { aRect1.SetLeft( rPos.X() ); aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 ); aRect1.SetRight( rPos.X() + ruler_tab.width - 1 ); aRect1.SetBottom( rPos.Y() ); aRect2.SetLeft( rPos.X() ); aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 ); aRect2.SetRight( rPos.X() + ruler_tab.width2 - 1 ); aRect2.SetBottom( rPos.Y() ); } else if ((!bRTL && nTabStyle == RULER_TAB_RIGHT) || (bRTL && nTabStyle == RULER_TAB_LEFT)) { aRect1.SetLeft( rPos.X() - ruler_tab.width + 1 ); aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 ); aRect1.SetRight( rPos.X() ); aRect1.SetBottom( rPos.Y() ); aRect2.SetLeft( rPos.X() - ruler_tab.width2 + 1 ); aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 ); aRect2.SetRight( rPos.X() ); aRect2.SetBottom( rPos.Y() ); } else { aRect1.SetLeft( rPos.X() - ruler_tab.cwidth2 + 1 ); aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 ); aRect1.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset ); aRect1.SetBottom( rPos.Y() ); aRect2.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 ); aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 ); aRect2.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 + ruler_tab.cwidth4 - 1 ); aRect2.SetBottom( rPos.Y() ); if (nTabStyle == RULER_TAB_DECIMAL) { aRect3.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth - 1 ); aRect3.SetTop( rPos.Y() - ruler_tab.height + 1 + 1 - DPIOffset ); aRect3.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset ); aRect3.SetBottom( rPos.Y() - ruler_tab.height + 1 + 2 ); } } if (0 == (nWinBits & WB_HORZ)) { bool bRightAligned = 0 != (nWinBits & WB_RIGHT_ALIGNED); lcl_RotateRect_Impl(aRect1, rPos.Y(), bRightAligned); lcl_RotateRect_Impl(aRect2, rPos.Y(), bRightAligned); lcl_RotateRect_Impl(aRect3, rPos.Y(), bRightAligned); } rRenderContext.DrawRect(aRect1); rRenderContext.DrawRect(aRect2); if (!aRect3.IsEmpty()) rRenderContext.DrawRect(aRect3); } void Ruler::ImplDrawTab(vcl::RenderContext& rRenderContext, const Point& rPos, sal_uInt16 nStyle) { if (nStyle & RULER_STYLE_INVISIBLE) return; rRenderContext.SetLineColor(); if (nStyle & RULER_STYLE_DONTKNOW) rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceColor()); else rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor()); if (mpData->bTextRTL) nStyle |= RULER_TAB_RTL; ImplDrawRulerTab(rRenderContext, rPos, nStyle, GetStyle()); } void Ruler::ImplDrawTabs(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom) { for (const RulerTab & rTab : mpData->pTabs) { if (rTab.nStyle & RULER_STYLE_INVISIBLE) continue; tools::Long aPosition; aPosition = rTab.nPos; aPosition += +mpData->nNullVirOff; tools::Long nTopBottom = (GetStyle() & WB_RIGHT_ALIGNED) ? nVirTop : nVirBottom; if (nMin <= aPosition && aPosition <= nMax) ImplDrawTab(rRenderContext, Point( aPosition, nTopBottom ), rTab.nStyle); } } static int adjustSize(int nOrig) { if (nOrig <= 0) return 0; // make sure we return an odd number, that looks better in the ruler return ( (3*nOrig) / 8) * 2 + 1; } void Ruler::ApplySettings(vcl::RenderContext& rRenderContext) { const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); vcl::Font aFont = rStyleSettings.GetToolFont(); // make the font a bit smaller than default Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height())); aFont.SetFontSize(aSize); ApplyControlFont(rRenderContext, aFont); ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor()); SetTextFillColor(); Color aColor; svtools::ColorConfig aColorConfig; aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor; ApplyControlBackground(rRenderContext, aColor); // A hack to get it to change the non-ruler application background to change immediately if (aColor != maVirDev->GetBackground().GetColor()) { maVirDev->SetBackground(aColor); Resize(); } } void Ruler::ImplInitSettings(bool bFont, bool bForeground, bool bBackground) { const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); if (bFont) { vcl::Font aFont = rStyleSettings.GetToolFont(); // make the font a bit smaller than default Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height())); aFont.SetFontSize(aSize); ApplyControlFont(*GetOutDev(), aFont); } if (bForeground || bFont) { ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor()); SetTextFillColor(); } if (bBackground) { Color aColor; svtools::ColorConfig aColorConfig; aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor; ApplyControlBackground(*GetOutDev(), aColor); } maVirDev->SetSettings( GetSettings() ); maVirDev->SetBackground( GetBackground() ); vcl::Font aFont = GetFont(); if (mnWinStyle & WB_VERT) aFont.SetOrientation(900_deg10); maVirDev->SetFont(aFont); maVirDev->SetTextColor(GetTextColor()); maVirDev->SetTextFillColor(GetTextFillColor()); } void Ruler::ImplCalc() { // calculate offset mpData->nRulVirOff = mnWinOff + mpData->nPageOff; if ( mpData->nRulVirOff > mnVirOff ) mpData->nRulVirOff -= mnVirOff; else mpData->nRulVirOff = 0; tools::Long nRulWinOff = mpData->nRulVirOff+mnVirOff; // calculate non-visual part of the page tools::Long nNotVisPageWidth; if ( mpData->nPageOff < 0 ) { nNotVisPageWidth = -(mpData->nPageOff); if ( nRulWinOff < mnWinOff ) nNotVisPageWidth -= mnWinOff-nRulWinOff; } else nNotVisPageWidth = 0; // calculate width if ( mnWinStyle & WB_HORZ ) { if ( mbAutoWinWidth ) mnWinWidth = mnWidth - mnVirOff; if ( mpData->bAutoPageWidth ) mpData->nPageWidth = mnWinWidth; mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth ); if ( nRulWinOff+mpData->nRulWidth > mnWidth ) mpData->nRulWidth = mnWidth-nRulWinOff; } else { if ( mbAutoWinWidth ) mnWinWidth = mnHeight - mnVirOff; if ( mpData->bAutoPageWidth ) mpData->nPageWidth = mnWinWidth; mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth ); if ( nRulWinOff+mpData->nRulWidth > mnHeight ) mpData->nRulWidth = mnHeight-nRulWinOff; } mbCalc = false; } void Ruler::ImplFormat(vcl::RenderContext const & rRenderContext) { // if already formatted, don't do it again if (!mbFormat) return; // don't do anything if the window still has no size if (!mnVirWidth) return; const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); tools::Long nP1; // pixel position of Page1 tools::Long nP2; // pixel position of Page2 tools::Long nM1; // pixel position of Margin1 tools::Long nM2; // pixel position of Margin2 tools::Long nVirTop; // top/left corner tools::Long nVirBottom; // bottom/right corner tools::Long nVirLeft; // left/top corner tools::Long nVirRight; // right/bottom corner tools::Long nNullVirOff; // for faster calculation // calculate values if (mbCalc) ImplCalc(); mpData->nNullVirOff = mnWinOff + mpData->nPageOff + mpData->nNullOff - mnVirOff; nNullVirOff = mpData->nNullVirOff; nVirLeft = mpData->nRulVirOff; nVirRight = nVirLeft + mpData->nRulWidth - 1; nVirTop = 0; nVirBottom = mnVirHeight - 1; if (!IsReallyVisible()) return; Size aVirDevSize; // initialize VirtualDevice if (mnWinStyle & WB_HORZ) { aVirDevSize.setWidth( mnVirWidth ); aVirDevSize.setHeight( mnVirHeight ); } else { aVirDevSize.setHeight( mnVirWidth ); aVirDevSize.setWidth( mnVirHeight ); } if (aVirDevSize != maVirDev->GetOutputSizePixel()) maVirDev->SetOutputSizePixel(aVirDevSize); else maVirDev->Erase(); // calculate margins if (!(mpData->nMargin1Style & RulerMarginStyle::Invisible)) { nM1 = mpData->nMargin1 + nNullVirOff; if (mpData->bAutoPageWidth) { nP1 = nVirLeft; if (nM1 < nVirLeft) nP1--; } else nP1 = nNullVirOff - mpData->nNullOff; } else { nM1 = nVirLeft-1; nP1 = nM1; } if (!(mpData->nMargin2Style & RulerMarginStyle::Invisible)) { nM2 = mpData->nMargin2 + nNullVirOff; if (mpData->bAutoPageWidth) { nP2 = nVirRight; if (nM2 > nVirRight) nP2++; } else nP2 = nNullVirOff - mpData->nNullOff + mpData->nPageWidth; if (nM2 > nP2) nM2 = nP2; } else { nM2 = nVirRight+1; nP2 = nM2; } // top/bottom border maVirDev->SetLineColor(rStyleSettings.GetShadowColor()); ImplVDrawLine(*maVirDev, nVirLeft, nVirTop + 1, nM1, nVirTop + 1); //top left line ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nP2 - 1, nVirTop + 1); //top right line nVirTop++; nVirBottom--; // draw margin1, margin2 and in-between maVirDev->SetLineColor(); maVirDev->SetFillColor(rStyleSettings.GetDialogColor()); if (nM1 > nVirLeft) ImplVDrawRect(*maVirDev, nP1, nVirTop + 1, nM1, nVirBottom); //left gray rectangle if (nM2 < nP2) ImplVDrawRect(*maVirDev, nM2, nVirTop + 1, nP2, nVirBottom); //right gray rectangle if (nM2 - nM1 > 0) { maVirDev->SetFillColor(rStyleSettings.GetWindowColor()); ImplVDrawRect(*maVirDev, nM1 + 1, nVirTop, nM2 - 1, nVirBottom); //center rectangle } maVirDev->SetLineColor(rStyleSettings.GetShadowColor()); if (nM1 > nVirLeft) { ImplVDrawLine(*maVirDev, nM1, nVirTop + 1, nM1, nVirBottom); //right line of the left rectangle ImplVDrawLine(*maVirDev, nP1, nVirBottom, nM1, nVirBottom); //bottom line of the left rectangle if (nP1 >= nVirLeft) { ImplVDrawLine(*maVirDev, nP1, nVirTop + 1, nP1, nVirBottom); //left line of the left rectangle ImplVDrawLine(*maVirDev, nP1, nVirBottom, nP1 + 1, nVirBottom); //? } } if (nM2 < nP2) { ImplVDrawLine(*maVirDev, nM2, nVirBottom, nP2 - 1, nVirBottom); //bottom line of the right rectangle ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nM2, nVirBottom); //left line of the right rectangle if (nP2 <= nVirRight + 1) ImplVDrawLine(*maVirDev, nP2 - 1, nVirTop + 1, nP2 - 1, nVirBottom); //right line of the right rectangle } tools::Long nMin = nVirLeft; tools::Long nMax = nP2; tools::Long nStart = 0; if (mpData->bTextRTL) nStart = mpData->nRightFrameMargin + nNullVirOff; else nStart = mpData->nLeftFrameMargin + nNullVirOff; if (nP1 > nVirLeft) nMin++; if (nP2 < nVirRight) nMax--; // Draw captions ImplDrawTicks(*maVirDev, nMin, nMax, nStart, nVirTop, nVirBottom); // Draw borders if (!mpData->pBorders.empty()) ImplDrawBorders(*maVirDev, nVirLeft, nP2, nVirTop, nVirBottom); // Draw indents if (!mpData->pIndents.empty()) ImplDrawIndents(*maVirDev, nVirLeft, nP2, nVirTop - 1, nVirBottom + 1); // Tabs if (!mpData->pTabs.empty()) ImplDrawTabs(*maVirDev, nVirLeft, nP2, nVirTop-1, nVirBottom + 1); mbFormat = false; } void Ruler::ImplInitExtraField( bool bUpdate ) { Size aWinSize = GetOutputSizePixel(); // extra field evaluate if ( mnWinStyle & WB_EXTRAFIELD ) { maExtraRect.SetLeft( RULER_OFF ); maExtraRect.SetTop( RULER_OFF ); maExtraRect.SetRight( RULER_OFF + mnVirHeight - 1 ); maExtraRect.SetBottom( RULER_OFF + mnVirHeight - 1 ); if(mpData->bTextRTL) { if(mnWinStyle & WB_HORZ) maExtraRect.Move(aWinSize.Width() - maExtraRect.GetWidth() - maExtraRect.Left(), 0); else maExtraRect.Move(0, aWinSize.Height() - maExtraRect.GetHeight() - maExtraRect.Top()); mnVirOff = 0; } else mnVirOff = maExtraRect.Right()+1; } else { maExtraRect.SetEmpty(); mnVirOff = 0; } // mnVirWidth depends on mnVirOff if ( (mnVirWidth > RULER_MIN_SIZE) || ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) ) { if ( mnWinStyle & WB_HORZ ) mnVirWidth = aWinSize.Width()-mnVirOff; else mnVirWidth = aWinSize.Height()-mnVirOff; if ( mnVirWidth < RULER_MIN_SIZE ) mnVirWidth = 0; } if ( bUpdate ) { mbCalc = true; mbFormat = true; Invalidate(); } } void Ruler::ImplDraw(vcl::RenderContext& rRenderContext) { if (mbFormat) { ImplFormat(rRenderContext); } if (!IsReallyVisible()) return; // output the ruler to the virtual device Point aOffPos; Size aVirDevSize = maVirDev->GetOutputSizePixel(); if (mnWinStyle & WB_HORZ) { aOffPos.setX( mnVirOff ); if (mpData->bTextRTL) aVirDevSize.AdjustWidth( -(maExtraRect.GetWidth()) ); aOffPos.setY( RULER_OFF ); } else { aOffPos.setX( RULER_OFF ); aOffPos.setY( mnVirOff ); } rRenderContext.DrawOutDev(aOffPos, aVirDevSize, Point(), aVirDevSize, *maVirDev); // redraw positionlines ImplInvertLines(rRenderContext); } void Ruler::ImplDrawExtra(vcl::RenderContext& rRenderContext) { const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); tools::Rectangle aRect = maExtraRect; bool bEraseRect = false; aRect.AdjustLeft(2 ); aRect.AdjustTop(2 ); aRect.AdjustRight( -2 ); aRect.AdjustBottom( -2 ); if (mnExtraStyle & RULER_STYLE_HIGHLIGHT) { rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor()); bEraseRect = true; } if (bEraseRect) { rRenderContext.SetLineColor(); rRenderContext.DrawRect(aRect); } // output content if (meExtraType == RulerExtra::NullOffset) { rRenderContext.SetLineColor(rStyleSettings.GetButtonTextColor()); rRenderContext.DrawLine(Point(aRect.Left() + 1, aRect.Top() + 4), Point(aRect.Right() - 1, aRect.Top() + 4)); rRenderContext.DrawLine(Point(aRect.Left() + 4, aRect.Top() + 1), Point(aRect.Left() + 4, aRect.Bottom() - 1)); } else if (meExtraType == RulerExtra::Tab) { sal_uInt16 nTabStyle = mnExtraStyle & RULER_TAB_STYLE; if (mpData->bTextRTL) nTabStyle |= RULER_TAB_RTL; Point aCenter = aRect.Center(); Point aDraw(aCenter); ImplCenterTabPos(aDraw, nTabStyle); WinBits nWinBits = GetStyle(); if (0 == (nWinBits & WB_HORZ)) { if ((nWinBits & WB_RIGHT_ALIGNED) != 0) aDraw.setY( 2 * aCenter.Y() - aDraw.Y() ); if (mpData->bTextRTL) { tools::Long nTemp = aDraw.X(); aDraw.setX( aDraw.Y() ); aDraw.setY( nTemp ); } } ImplDrawTab(rRenderContext, aDraw, nTabStyle); } } void Ruler::ImplUpdate( bool bMustCalc ) { // clear lines in this place so they aren't considered at recalculation if (!mbFormat) Invalidate(InvalidateFlags::NoErase); // set flags if (bMustCalc) mbCalc = true; mbFormat = true; // abort if we are dragging as drag-handler will update the ruler after drag is finished if (mbDrag) return; // otherwise trigger update if (IsReallyVisible() && IsUpdateMode()) { Invalidate(InvalidateFlags::NoErase); } } bool Ruler::ImplDoHitTest( const Point& rPos, RulerSelection* pHitTest, bool bRequireStyle, RulerIndentStyle nRequiredStyle ) const { sal_Int32 i; sal_uInt16 nStyle; tools::Long nHitBottom; tools::Long nX; tools::Long nY; tools::Long n1; if ( !mbActive ) return false; // determine positions bool bIsHori = 0 != (mnWinStyle & WB_HORZ); if ( bIsHori ) { nX = rPos.X(); nY = rPos.Y(); } else { nX = rPos.Y(); nY = rPos.X(); } nHitBottom = mnVirHeight + (RULER_OFF * 2); // #i32608# pHitTest->nAryPos = 0; pHitTest->mnDragSize = RulerDragSize::Move; pHitTest->bSize = false; pHitTest->bSizeBar = false; // so that leftover tabs and indents are taken into account tools::Long nXExtraOff; if ( !mpData->pTabs.empty() || !mpData->pIndents.empty() ) nXExtraOff = (mnVirHeight / 2) - 4; else nXExtraOff = 0; // test if outside nX -= mnVirOff; if ( (nX < mpData->nRulVirOff - nXExtraOff) || (nX > mpData->nRulVirOff + mpData->nRulWidth + nXExtraOff) || (nY < 0) || (nY > nHitBottom) ) { pHitTest->nPos = 0; pHitTest->eType = RulerType::Outside; return false; } nX -= mpData->nNullVirOff; pHitTest->nPos = nX; pHitTest->eType = RulerType::DontKnow; // first test the tabs tools::Rectangle aRect; if ( !mpData->pTabs.empty() ) { aRect.SetBottom( nHitBottom ); aRect.SetTop( aRect.Bottom() - ruler_tab.height - RULER_OFF ); for ( i = mpData->pTabs.size() - 1; i >= 0; i-- ) { nStyle = mpData->pTabs[i].nStyle; if ( !(nStyle & RULER_STYLE_INVISIBLE) ) { nStyle &= RULER_TAB_STYLE; // default tabs are only shown (no action) if ( nStyle != RULER_TAB_DEFAULT ) { n1 = mpData->pTabs[i].nPos; if ( nStyle == RULER_TAB_LEFT ) { aRect.SetLeft( n1 ); aRect.SetRight( n1 + ruler_tab.width - 1 ); } else if ( nStyle == RULER_TAB_RIGHT ) { aRect.SetRight( n1 ); aRect.SetLeft( n1 - ruler_tab.width - 1 ); } else { aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 ); aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth ); } if ( aRect.Contains( Point( nX, nY ) ) ) { pHitTest->eType = RulerType::Tab; pHitTest->nAryPos = i; return true; } } } } } // Indents if ( !mpData->pIndents.empty() ) { tools::Long nIndentHeight = (mnVirHeight / 2) - 1; tools::Long nIndentWidth2 = nIndentHeight - 3; for ( i = mpData->pIndents.size(); i; i-- ) { RulerIndentStyle nIndentStyle = mpData->pIndents[i-1].nStyle; if ( (! bRequireStyle || nIndentStyle == nRequiredStyle) && !mpData->pIndents[i-1].bInvisible ) { n1 = mpData->pIndents[i-1].nPos; if ( (nIndentStyle == RulerIndentStyle::Bottom) != !bIsHori ) { aRect.SetLeft( n1-nIndentWidth2 ); aRect.SetRight( n1+nIndentWidth2 ); aRect.SetTop( nHitBottom-nIndentHeight-RULER_OFF+1 ); aRect.SetBottom( nHitBottom ); } else { aRect.SetLeft( n1-nIndentWidth2 ); aRect.SetRight( n1+nIndentWidth2 ); aRect.SetTop( 0 ); aRect.SetBottom( nIndentHeight+RULER_OFF-1 ); } if ( aRect.Contains( Point( nX, nY ) ) ) { pHitTest->eType = RulerType::Indent; pHitTest->nAryPos = i-1; return true; } } } } // test the borders int nBorderTolerance = 1; if(pHitTest->bExpandTest) { nBorderTolerance++; } for ( i = mpData->pBorders.size(); i; i-- ) { n1 = mpData->pBorders[i-1].nPos; tools::Long n2 = n1 + mpData->pBorders[i-1].nWidth; // borders have at least 3 pixel padding if ( !mpData->pBorders[i-1].nWidth ) { n1 -= nBorderTolerance; n2 += nBorderTolerance; } if ( (nX >= n1) && (nX <= n2) ) { RulerBorderStyle nBorderStyle = mpData->pBorders[i-1].nStyle; if ( !(nBorderStyle & RulerBorderStyle::Invisible) ) { pHitTest->eType = RulerType::Border; pHitTest->nAryPos = i-1; if ( !(nBorderStyle & RulerBorderStyle::Sizeable) ) { if ( nBorderStyle & RulerBorderStyle::Moveable ) { pHitTest->bSizeBar = true; pHitTest->mnDragSize = RulerDragSize::Move; } } else { tools::Long nMOff = RULER_MOUSE_BORDERWIDTH; while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) ) { if ( nMOff < 2 ) { nMOff = 0; break; } else nMOff--; } if ( nX <= n1+nMOff ) { pHitTest->bSize = true; pHitTest->mnDragSize = RulerDragSize::N1; } else if ( nX >= n2-nMOff ) { pHitTest->bSize = true; pHitTest->mnDragSize = RulerDragSize::N2; } else { if ( nBorderStyle & RulerBorderStyle::Moveable ) { pHitTest->bSizeBar = true; pHitTest->mnDragSize = RulerDragSize::Move; } } } return true; } } } // Margins int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH; if ( (mpData->nMargin1Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable ) { n1 = mpData->nMargin1; if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) ) { pHitTest->eType = RulerType::Margin1; pHitTest->bSize = true; return true; } } if ( (mpData->nMargin2Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable ) { n1 = mpData->nMargin2; if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) ) { pHitTest->eType = RulerType::Margin2; pHitTest->bSize = true; return true; } } // test tabs again if ( !mpData->pTabs.empty() ) { aRect.SetTop( RULER_OFF ); aRect.SetBottom( nHitBottom ); for ( i = mpData->pTabs.size() - 1; i >= 0; i-- ) { nStyle = mpData->pTabs[i].nStyle; if ( !(nStyle & RULER_STYLE_INVISIBLE) ) { nStyle &= RULER_TAB_STYLE; // default tabs are only shown (no action) if ( nStyle != RULER_TAB_DEFAULT ) { n1 = mpData->pTabs[i].nPos; if ( nStyle == RULER_TAB_LEFT ) { aRect.SetLeft( n1 ); aRect.SetRight( n1 + ruler_tab.width - 1 ); } else if ( nStyle == RULER_TAB_RIGHT ) { aRect.SetRight( n1 ); aRect.SetLeft( n1 - ruler_tab.width - 1 ); } else { aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 ); aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth ); } aRect.AdjustLeft( -1 ); aRect.AdjustRight( 1 ); if ( aRect.Contains( Point( nX, nY ) ) ) { pHitTest->eType = RulerType::Tab; pHitTest->nAryPos = i; return true; } } } } } return false; } bool Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType, RulerSelection* pHitTest ) const { Point aPos = rPos; bool bRequiredStyle = false; RulerIndentStyle nRequiredStyle = RulerIndentStyle::Top; if (eDragType == RulerType::Indent) { bRequiredStyle = true; nRequiredStyle = RulerIndentStyle::Bottom; } if ( mnWinStyle & WB_HORZ ) aPos.AdjustX(mnWinOff ); else aPos.AdjustY(mnWinOff ); if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::DontKnow) ) { if ( mnWinStyle & WB_HORZ ) aPos.setY( RULER_OFF + 1 ); else aPos.setX( RULER_OFF + 1 ); if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) ) { if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) ) return true; } } if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::Tab) || (eDragType == RulerType::DontKnow) ) { if ( mnWinStyle & WB_HORZ ) aPos.setY( mnHeight - RULER_OFF - 1 ); else aPos.setX( mnWidth - RULER_OFF - 1 ); if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) ) { if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) ) return true; } } if ( (eDragType == RulerType::Margin1) || (eDragType == RulerType::Margin2) || (eDragType == RulerType::Border) || (eDragType == RulerType::DontKnow) ) { if ( mnWinStyle & WB_HORZ ) aPos.setY( RULER_OFF + (mnVirHeight / 2) ); else aPos.setX( RULER_OFF + (mnVirHeight / 2) ); if ( ImplDoHitTest( aPos, pHitTest ) ) { if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) ) return true; } } pHitTest->eType = RulerType::DontKnow; return false; } bool Ruler::ImplStartDrag( RulerSelection const * pHitTest, sal_uInt16 nModifier ) { // don't trigger drag if a border that was clicked can not be changed if ( (pHitTest->eType == RulerType::Border) && !pHitTest->bSize && !pHitTest->bSizeBar ) return false; // Set drag data meDragType = pHitTest->eType; mnDragPos = pHitTest->nPos; mnDragAryPos = pHitTest->nAryPos; mnDragSize = pHitTest->mnDragSize; mnDragModifier = nModifier; *mpDragData = *mpSaveData; mpData = mpDragData.get(); // call handler if (StartDrag()) { // if the handler allows dragging, initialize dragging mbDrag = true; mnStartDragPos = mnDragPos; StartTracking(); Invalidate(InvalidateFlags::NoErase); return true; } else { // otherwise reset the data meDragType = RulerType::DontKnow; mnDragPos = 0; mnDragAryPos = 0; mnDragSize = RulerDragSize::Move; mnDragModifier = 0; mpData = mpSaveData.get(); } return false; } void Ruler::ImplDrag( const Point& rPos ) { tools::Long nX; tools::Long nY; tools::Long nOutHeight; if ( mnWinStyle & WB_HORZ ) { nX = rPos.X(); nY = rPos.Y(); nOutHeight = mnHeight; } else { nX = rPos.Y(); nY = rPos.X(); nOutHeight = mnWidth; } // calculate and fit X nX -= mnVirOff; if ( nX < mpData->nRulVirOff ) { nX = mpData->nRulVirOff; } else if ( nX > mpData->nRulVirOff+mpData->nRulWidth ) { nX = mpData->nRulVirOff+mpData->nRulWidth; } nX -= mpData->nNullVirOff; // if upper or left from ruler, then consider old values mbDragDelete = false; if ( nY < 0 ) { if ( !mbDragCanceled ) { // reset the data mbDragCanceled = true; ImplRulerData aTempData = *mpDragData; *mpDragData = *mpSaveData; mbCalc = true; mbFormat = true; // call handler mnDragPos = mnStartDragPos; Drag(); // and redraw Invalidate(InvalidateFlags::NoErase); // reset the data as before cancel *mpDragData = aTempData; } } else { mbDragCanceled = false; // +2, so the tabs are not cleared too quickly if ( nY > nOutHeight + 2 ) mbDragDelete = true; mnDragPos = nX; // call handler Drag(); // redraw if (mbFormat) Invalidate(InvalidateFlags::NoErase); } } void Ruler::ImplEndDrag() { // get values if ( mbDragCanceled ) *mpDragData = *mpSaveData; else *mpSaveData = *mpDragData; mpData = mpSaveData.get(); mbDrag = false; // call handler EndDrag(); // reset drag values meDragType = RulerType::DontKnow; mnDragPos = 0; mnDragAryPos = 0; mnDragSize = RulerDragSize::Move; mbDragCanceled = false; mbDragDelete = false; mnDragModifier = 0; mnStartDragPos = 0; // redraw Invalidate(InvalidateFlags::NoErase); } void Ruler::MouseButtonDown( const MouseEvent& rMEvt ) { if ( !rMEvt.IsLeft() || IsTracking() ) return; Point aMousePos = rMEvt.GetPosPixel(); sal_uInt16 nMouseClicks = rMEvt.GetClicks(); sal_uInt16 nMouseModifier = rMEvt.GetModifier(); // update ruler if ( mbFormat ) { Invalidate(InvalidateFlags::NoErase); } if ( maExtraRect.Contains( aMousePos ) ) { ExtraDown(); } else { RulerSelection aHitTest; bool bHitTestResult = ImplDoHitTest(aMousePos, &aHitTest); if ( nMouseClicks == 1 ) { if ( bHitTestResult ) { ImplStartDrag( &aHitTest, nMouseModifier ); } else { // calculate position inside of ruler area if ( aHitTest.eType == RulerType::DontKnow ) { mnDragPos = aHitTest.nPos; Click(); mnDragPos = 0; // call HitTest again as a click, for example, could set a new tab if ( ImplDoHitTest(aMousePos, &aHitTest) ) ImplStartDrag(&aHitTest, nMouseModifier); } } } else { if (bHitTestResult) { mnDragPos = aHitTest.nPos; mnDragAryPos = aHitTest.nAryPos; } meDragType = aHitTest.eType; DoubleClick(); meDragType = RulerType::DontKnow; mnDragPos = 0; mnDragAryPos = 0; } } } void Ruler::MouseMove( const MouseEvent& rMEvt ) { PointerStyle ePtrStyle = PointerStyle::Arrow; mxPreviousHitTest.swap(mxCurrentHitTest); mxCurrentHitTest.reset(new RulerSelection); maHoverSelection.eType = RulerType::DontKnow; if (ImplDoHitTest( rMEvt.GetPosPixel(), mxCurrentHitTest.get() )) { maHoverSelection = *mxCurrentHitTest; if (mxCurrentHitTest->bSize) { if (mnWinStyle & WB_HORZ) { if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1) ePtrStyle = PointerStyle::TabSelectW; else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2) ePtrStyle = PointerStyle::TabSelectE; else ePtrStyle = PointerStyle::ESize; } else { if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1) ePtrStyle = PointerStyle::WindowNSize; else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2) ePtrStyle = PointerStyle::WindowSSize; else ePtrStyle = PointerStyle::SSize; } } else if (mxCurrentHitTest->bSizeBar) { if (mnWinStyle & WB_HORZ) ePtrStyle = PointerStyle::HSizeBar; else ePtrStyle = PointerStyle::VSizeBar; } } if (mxPreviousHitTest != nullptr && mxPreviousHitTest->eType != mxCurrentHitTest->eType) { mbFormat = true; } SetPointer( ePtrStyle ); if (mbFormat) { Invalidate(InvalidateFlags::NoErase); } } void Ruler::Tracking( const TrackingEvent& rTEvt ) { if ( rTEvt.IsTrackingEnded() ) { // reset the old state at cancel if ( rTEvt.IsTrackingCanceled() ) { mbDragCanceled = true; mbFormat = true; } ImplEndDrag(); } else ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() ); } void Ruler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) { ImplDraw(rRenderContext); // consider extra field if (mnWinStyle & WB_EXTRAFIELD) ImplDrawExtra(rRenderContext); } void Ruler::Resize() { Size aWinSize = GetOutputSizePixel(); tools::Long nNewHeight; if ( mnWinStyle & WB_HORZ ) { if ( aWinSize.Height() != mnHeight ) nNewHeight = aWinSize.Height(); else nNewHeight = 0; } else { if ( aWinSize.Width() != mnWidth ) nNewHeight = aWinSize.Width(); else nNewHeight = 0; } mbFormat = true; // clear lines bool bVisible = IsReallyVisible(); if ( bVisible && !mpData->pLines.empty() ) { mnUpdateFlags |= RULER_UPDATE_LINES; Invalidate(InvalidateFlags::NoErase); } // recalculate some values if the height/width changes // extra field should always be updated ImplInitExtraField( mpData->bTextRTL ); if ( nNewHeight ) { mbCalc = true; mnVirHeight = nNewHeight - mnBorderWidth - ( RULER_OFF * 2 ); } else { if ( mpData->bAutoPageWidth ) ImplUpdate( true ); else if ( mbAutoWinWidth ) mbCalc = true; } // clear part of the border if ( bVisible ) { if ( nNewHeight ) Invalidate(InvalidateFlags::NoErase); else if ( mpData->bAutoPageWidth ) { // only at AutoPageWidth do we need to redraw tools::Rectangle aRect; if ( mnWinStyle & WB_HORZ ) { if ( mnWidth < aWinSize.Width() ) aRect.SetLeft( mnWidth - RULER_RESIZE_OFF ); else aRect.SetLeft( aWinSize.Width() - RULER_RESIZE_OFF ); aRect.SetRight( aRect.Left() + RULER_RESIZE_OFF ); aRect.SetTop( RULER_OFF ); aRect.SetBottom( RULER_OFF + mnVirHeight ); } else { if ( mnHeight < aWinSize.Height() ) aRect.SetTop( mnHeight-RULER_RESIZE_OFF ); else aRect.SetTop( aWinSize.Height()-RULER_RESIZE_OFF ); aRect.SetBottom( aRect.Top() + RULER_RESIZE_OFF ); aRect.SetLeft( RULER_OFF ); aRect.SetRight( RULER_OFF + mnVirHeight ); } Invalidate(aRect, InvalidateFlags::NoErase); } } mnWidth = aWinSize.Width(); mnHeight = aWinSize.Height(); } void Ruler::StateChanged( StateChangedType nType ) { Window::StateChanged( nType ); if ( nType == StateChangedType::InitShow ) Invalidate(); else if ( nType == StateChangedType::UpdateMode ) { if ( IsReallyVisible() && IsUpdateMode() ) Invalidate(); } else if ( (nType == StateChangedType::Zoom) || (nType == StateChangedType::ControlFont) ) { ImplInitSettings( true, false, false ); Invalidate(); } else if ( nType == StateChangedType::ControlForeground ) { ImplInitSettings( false, true, false ); Invalidate(); } else if ( nType == StateChangedType::ControlBackground ) { ImplInitSettings( false, false, true ); Invalidate(); } } void Ruler::DataChanged( const DataChangedEvent& rDCEvt ) { Window::DataChanged( rDCEvt ); if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || (rDCEvt.GetType() == DataChangedEventType::DISPLAY) || (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) { mbFormat = true; ImplInitSettings( true, true, true ); Invalidate(); } } bool Ruler::StartDrag() { return false; } void Ruler::Drag() { } void Ruler::EndDrag() { } void Ruler::Click() { } void Ruler::DoubleClick() { maDoubleClickHdl.Call( this ); } void Ruler::ExtraDown() { } void Ruler::Activate() { mbActive = true; // update positionlines - draw is delayed mnUpdateFlags |= RULER_UPDATE_LINES; Invalidate(InvalidateFlags::NoErase); } void Ruler::Deactivate() { // clear positionlines Invalidate(InvalidateFlags::NoErase); mbActive = false; } bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType ) { if ( !mbDrag ) { Point aMousePos = rMEvt.GetPosPixel(); sal_uInt16 nMouseClicks = rMEvt.GetClicks(); sal_uInt16 nMouseModifier = rMEvt.GetModifier(); RulerSelection aHitTest; if(eDragType != RulerType::DontKnow) aHitTest.bExpandTest = true; // update ruler if ( mbFormat ) { if (!IsReallyVisible()) { // set mpData for ImplDocHitTest() ImplFormat(*GetOutDev()); } Invalidate(InvalidateFlags::NoErase); } if ( nMouseClicks == 1 ) { if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) ) { PointerStyle aPtr = PointerStyle::Arrow; if ( aHitTest.bSize ) { if ( mnWinStyle & WB_HORZ ) aPtr = PointerStyle::ESize; else aPtr = PointerStyle::SSize; } else if ( aHitTest.bSizeBar ) { if ( mnWinStyle & WB_HORZ ) aPtr = PointerStyle::HSizeBar; else aPtr = PointerStyle::VSizeBar; } SetPointer( aPtr ); return ImplStartDrag( &aHitTest, nMouseModifier ); } } else if ( nMouseClicks == 2 ) { if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) ) { mnDragPos = aHitTest.nPos; mnDragAryPos = aHitTest.nAryPos; } DoubleClick(); mnDragPos = 0; mnDragAryPos = 0; return true; } } return false; } void Ruler::CancelDrag() { if ( mbDrag ) { ImplDrag( Point( -1, -1 ) ); ImplEndDrag(); } } RulerType Ruler::GetRulerType( const Point& rPos, sal_uInt16* pAryPos ) { RulerSelection aHitTest; // update ruler if ( IsReallyVisible() && mbFormat ) { Invalidate(InvalidateFlags::NoErase); } (void)ImplDoHitTest(rPos, &aHitTest); // return values if ( pAryPos ) *pAryPos = aHitTest.nAryPos; return aHitTest.eType; } void Ruler::SetWinPos( tools::Long nNewOff, tools::Long nNewWidth ) { // should widths be automatically calculated if ( !nNewWidth ) mbAutoWinWidth = true; else mbAutoWinWidth = false; mnWinOff = nNewOff; mnWinWidth = nNewWidth; ImplUpdate( true ); } void Ruler::SetPagePos( tools::Long nNewOff, tools::Long nNewWidth ) { // should we do anything? if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) ) return; // should widths be automatically calculated if ( !nNewWidth ) mpData->bAutoPageWidth = true; else mpData->bAutoPageWidth = false; mpData->nPageOff = nNewOff; mpData->nPageWidth = nNewWidth; ImplUpdate( true ); } void Ruler::SetBorderPos( tools::Long nOff ) { if ( mnWinStyle & WB_BORDER ) { if ( mnBorderOff != nOff ) { mnBorderOff = nOff; if ( IsReallyVisible() && IsUpdateMode() ) Invalidate(InvalidateFlags::NoErase); } } } void Ruler::SetUnit( FieldUnit eNewUnit ) { if ( meUnit == eNewUnit ) return; meUnit = eNewUnit; switch ( meUnit ) { case FieldUnit::MM: mnUnitIndex = RULER_UNIT_MM; break; case FieldUnit::CM: mnUnitIndex = RULER_UNIT_CM; break; case FieldUnit::M: mnUnitIndex = RULER_UNIT_M; break; case FieldUnit::KM: mnUnitIndex = RULER_UNIT_KM; break; case FieldUnit::INCH: mnUnitIndex = RULER_UNIT_INCH; break; case FieldUnit::FOOT: mnUnitIndex = RULER_UNIT_FOOT; break; case FieldUnit::MILE: mnUnitIndex = RULER_UNIT_MILE; break; case FieldUnit::POINT: mnUnitIndex = RULER_UNIT_POINT; break; case FieldUnit::PICA: mnUnitIndex = RULER_UNIT_PICA; break; case FieldUnit::CHAR: mnUnitIndex = RULER_UNIT_CHAR; break; case FieldUnit::LINE: mnUnitIndex = RULER_UNIT_LINE; break; default: SAL_WARN( "svtools.control", "Ruler::SetUnit() - Wrong Unit" ); break; } maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit ); ImplUpdate(); } void Ruler::SetZoom( const Fraction& rNewZoom ) { DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" ); if ( maZoom != rNewZoom ) { maZoom = rNewZoom; maMapMode.SetScaleX( maZoom ); maMapMode.SetScaleY( maZoom ); ImplUpdate(); } } void Ruler::SetExtraType( RulerExtra eNewExtraType, sal_uInt16 nStyle ) { if ( mnWinStyle & WB_EXTRAFIELD ) { meExtraType = eNewExtraType; mnExtraStyle = nStyle; if (IsReallyVisible() && IsUpdateMode()) Invalidate(); } } void Ruler::SetNullOffset( tools::Long nPos ) { if ( mpData->nNullOff != nPos ) { mpData->nNullVirOff += nPos - mpData->nNullOff; mpData->nNullOff = nPos; ImplUpdate(); } } void Ruler::SetLeftFrameMargin( tools::Long nPos ) { if ( mpData->nLeftFrameMargin != nPos ) { mpData->nLeftFrameMargin = nPos; ImplUpdate(); } } void Ruler::SetRightFrameMargin( tools::Long nPos ) { if ( mpData->nRightFrameMargin != nPos ) { mpData->nRightFrameMargin = nPos; ImplUpdate(); } } void Ruler::SetMargin1( tools::Long nPos, RulerMarginStyle nMarginStyle ) { if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) ) { mpData->nMargin1 = nPos; mpData->nMargin1Style = nMarginStyle; ImplUpdate(); } } void Ruler::SetMargin2( tools::Long nPos, RulerMarginStyle nMarginStyle ) { DBG_ASSERT( (nPos >= mpData->nMargin1) || (mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin2Style & RulerMarginStyle::Invisible), "Ruler::SetMargin2() - Margin2 < Margin1" ); if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) ) { mpData->nMargin2 = nPos; mpData->nMargin2Style = nMarginStyle; ImplUpdate(); } } void Ruler::SetLines( sal_uInt32 aLineArraySize, const RulerLine* pLineArray ) { // To determine if what has changed if ( mpData->pLines.size() == aLineArraySize ) { sal_uInt32 i = aLineArraySize; std::vector::const_iterator aItr1 = mpData->pLines.begin(); const RulerLine* pAry2 = pLineArray; while ( i ) { if ( aItr1->nPos != pAry2->nPos ) break; ++aItr1; ++pAry2; i--; } if ( !i ) return; } // New values and new share issue bool bMustUpdate; bMustUpdate = IsReallyVisible() && IsUpdateMode(); // Delete old lines if ( bMustUpdate ) Invalidate(InvalidateFlags::NoErase); // New data set if ( !aLineArraySize || !pLineArray ) { if ( mpData->pLines.empty() ) return; mpData->pLines.clear(); } else { if ( mpData->pLines.size() != aLineArraySize ) { mpData->pLines.resize(aLineArraySize); } std::copy( pLineArray, pLineArray + aLineArraySize, mpData->pLines.begin() ); if ( bMustUpdate ) Invalidate(InvalidateFlags::NoErase); } } void Ruler::SetBorders( sal_uInt32 aBorderArraySize, const RulerBorder* pBorderArray ) { if ( !aBorderArraySize || !pBorderArray ) { if ( mpData->pBorders.empty() ) return; mpData->pBorders.clear(); } else { if ( mpData->pBorders.size() != aBorderArraySize ) { mpData->pBorders.resize(aBorderArraySize); } else { sal_uInt32 i = aBorderArraySize; const RulerBorder* pAry1 = mpData->pBorders.data(); const RulerBorder* pAry2 = pBorderArray; while ( i ) { if ( (pAry1->nPos != pAry2->nPos) || (pAry1->nWidth != pAry2->nWidth) || (pAry1->nStyle != pAry2->nStyle) ) break; pAry1++; pAry2++; i--; } if ( !i ) return; } std::copy( pBorderArray, pBorderArray + aBorderArraySize, mpData->pBorders.begin() ); } ImplUpdate(); } void Ruler::SetIndents( sal_uInt32 aIndentArraySize, const RulerIndent* pIndentArray ) { if ( !aIndentArraySize || !pIndentArray ) { if ( mpData->pIndents.empty() ) return; mpData->pIndents.clear(); } else { if ( mpData->pIndents.size() != aIndentArraySize ) { mpData->pIndents.resize(aIndentArraySize); } else { sal_uInt32 i = aIndentArraySize; const RulerIndent* pAry1 = mpData->pIndents.data(); const RulerIndent* pAry2 = pIndentArray; while ( i ) { if ( (pAry1->nPos != pAry2->nPos) || (pAry1->nStyle != pAry2->nStyle) ) break; pAry1++; pAry2++; i--; } if ( !i ) return; } std::copy( pIndentArray, pIndentArray + aIndentArraySize, mpData->pIndents.begin() ); } ImplUpdate(); } void Ruler::SetTabs( sal_uInt32 aTabArraySize, const RulerTab* pTabArray ) { if ( aTabArraySize == 0 || pTabArray == nullptr ) { if ( mpData->pTabs.empty() ) return; mpData->pTabs.clear(); } else { if ( mpData->pTabs.size() != aTabArraySize ) { mpData->pTabs.resize(aTabArraySize); } else { sal_uInt32 i = aTabArraySize; std::vector::iterator aTabIterator = mpData->pTabs.begin(); const RulerTab* pInputArray = pTabArray; while ( i ) { RulerTab& aCurrent = *aTabIterator; if ( aCurrent.nPos != pInputArray->nPos || aCurrent.nStyle != pInputArray->nStyle ) { break; } ++aTabIterator; pInputArray++; i--; } if ( !i ) return; } std::copy(pTabArray, pTabArray + aTabArraySize, mpData->pTabs.begin()); } ImplUpdate(); } const std::vector& Ruler::GetTabs() const { return mpData->pTabs; } void Ruler::SetStyle( WinBits nStyle ) { if ( mnWinStyle != nStyle ) { mnWinStyle = nStyle; ImplInitExtraField( true ); } } void Ruler::DrawTab(vcl::RenderContext& rRenderContext, const Color &rFillColor, const Point& rPos, sal_uInt16 nStyle) { Point aPos(rPos); sal_uInt16 nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL); rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR); rRenderContext.SetLineColor(); rRenderContext.SetFillColor(rFillColor); ImplCenterTabPos(aPos, nTabStyle); ImplDrawRulerTab(rRenderContext, aPos, nTabStyle, nStyle); rRenderContext.Pop(); } void Ruler::SetTextRTL(bool bRTL) { if(mpData->bTextRTL != bRTL) { mpData->bTextRTL = bRTL; if ( IsReallyVisible() && IsUpdateMode() ) ImplInitExtraField( true ); } } tools::Long Ruler::GetPageOffset() const { return mpData->nPageOff; } tools::Long Ruler::GetNullOffset() const { return mpData->nNullOff; } tools::Long Ruler::GetMargin1() const { return mpData->nMargin1; } tools::Long Ruler::GetMargin2() const { return mpData->nMargin2; } bool Ruler::GetTextRTL() const { return mpData->bTextRTL; } const RulerUnitData& Ruler::GetCurrentRulerUnit() const { return aImplRulerUnitTab[mnUnitIndex]; } void Ruler::DrawTicks() { mbFormat = true; Invalidate(InvalidateFlags::NoErase); } uno::Reference< XAccessible > Ruler::CreateAccessible() { vcl::Window* pParent = GetAccessibleParentWindow(); OSL_ENSURE( pParent, "-SvxRuler::CreateAccessible(): No Parent!" ); uno::Reference< XAccessible > xAccParent = pParent->GetAccessible(); if( xAccParent.is() ) { // MT: Fixed compiler issue because the address from a temporary object was used. // BUT: Should it really be a Pointer, instead of const&??? OUString aStr; if ( mnWinStyle & WB_HORZ ) { aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME); } else { aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME); } mxAccContext = new SvtRulerAccessible( xAccParent, *this, aStr ); SetAccessible(mxAccContext); return mxAccContext; } else return uno::Reference< XAccessible >(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */