/* -*- 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/themecolors.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
0 x01
#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& rRenderContex
t, 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();
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--;
Color aRulerColor;
Color aMarginRulerColor;
if (ThemeColors::IsThemeEnabled())
{
aRulerColor = ThemeColors::GetThemeColors().GetBaseColor();
aMarginRulerColor = ThemeColors::GetThemeColors().GetWindowColor();
}
else
{
aRulerColor = rStyleSettings.GetWindowColor();
aMarginRulerColor = rStyleSettings.GetDialogColor();
}
// draw margin1, margin2 and in-between
maVirDev->SetLineColor();
maVirDev->SetFillColor(aMarginRulerColor);
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(aRulerColor);
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()
{
uno::Reference<XAccessible> xAccParent = GetAccessibleParent();
if ( xAccParent.is() )
{
OUString aStr;
if ( mnWinStyle & WB_HORZ )
{
aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME);
}
else
{
aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME);
}
return new SvtRulerAccessible(xAccParent, *this , aStr);
}
else
return uno::Reference< XAccessible >();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=93 H=96 G=94
¤ Dauer der Verarbeitung: 0.266 Sekunden
(vorverarbeitet am 2026-06-06)
¤
*© Formatika GbR, Deutschland