/* -*- 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::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, u"0123456789"_ustr );
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,
tools::Long nTolerance ) 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 = nTolerance;
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, tools::Long nTolerance ) 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, nTolerance ) )
{
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, nTolerance ) )
{
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, false, RulerIndentStyle::Top, nTolerance ) )
{
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 = std::move(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, tools::Long nTolerance )
{
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, nTolerance ) )
{
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, nTolerance ) )
{
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;
}
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: */
↑ V1053 Calling the 'EnableRTL' virtual function indirectly in the constructor may lead to unexpected result at runtime. Check lines: 'ruler.cxx:276', 'ruler.cxx:184', 'window.hxx:1516'.
↑ V636 The '(nBottom - nTop) / 2' expression was implicitly cast from 'long' type to 'double' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(X) / Y;.
↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: mnStartDragPos.