diff options
Diffstat (limited to 'svtools/source/control/ruler.cxx')
-rw-r--r-- | svtools/source/control/ruler.cxx | 2778 |
1 files changed, 2778 insertions, 0 deletions
diff --git a/svtools/source/control/ruler.cxx b/svtools/source/control/ruler.cxx new file mode 100644 index 000000000..89164e6ed --- /dev/null +++ b/svtools/source/control/ruler.cxx @@ -0,0 +1,2778 @@ +/* -*- 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 <tools/debug.hxx> +#include <tools/poly.hxx> +#include <vcl/event.hxx> +#include <vcl/settings.hxx> +#include <vcl/vcllayout.hxx> +#include <vcl/virdev.hxx> +#include <vcl/ptrstyle.hxx> +#include <sal/log.hxx> + +#include <svtools/ruler.hxx> +#include <svtools/svtresid.hxx> +#include <svtools/strings.hrc> +#include <svtools/colorcfg.hxx> +#include "accessibleruler.hxx" + +#include <memory> +#include <vector> + +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<SalLayout> 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<RulerLine> pLines; + std::vector<RulerBorder> pBorders; + std::vector<RulerIndent> pIndents; + std::vector<RulerTab> 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<VirtualDevice>::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<RulerBorder>::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<RulerIndent>::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<RulerLine>::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<RulerTab>::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<RulerTab>& 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: */ |