use insert function instead of for loop
[LibreOffice.git] / svtools / source / control / ruler.cxx
blobd4f75c69bfceb3ecbeff311df6fb34585d59e980
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/debug.hxx>
21 #include <tools/poly.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/vcllayout.hxx>
25 #include <vcl/virdev.hxx>
26 #include <vcl/ptrstyle.hxx>
27 #include <sal/log.hxx>
29 #include <svtools/ruler.hxx>
30 #include <svtools/svtresid.hxx>
31 #include <svtools/strings.hrc>
32 #include <svtools/colorcfg.hxx>
33 #include "accessibleruler.hxx"
35 #include <memory>
36 #include <vector>
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::accessibility;
42 #define RULER_OFF 3
43 #define RULER_RESIZE_OFF 4
44 #define RULER_MIN_SIZE 3
46 #define RULER_VAR_SIZE 8
48 #define RULER_UPDATE_LINES 0x01
50 #define RULER_CLIP 150
52 #define RULER_UNIT_MM 0
53 #define RULER_UNIT_CM 1
54 #define RULER_UNIT_M 2
55 #define RULER_UNIT_KM 3
56 #define RULER_UNIT_INCH 4
57 #define RULER_UNIT_FOOT 5
58 #define RULER_UNIT_MILE 6
59 #define RULER_UNIT_POINT 7
60 #define RULER_UNIT_PICA 8
61 #define RULER_UNIT_CHAR 9
62 #define RULER_UNIT_LINE 10
63 #define RULER_UNIT_COUNT 11
65 namespace
67 /**
68 * Pre-calculates glyph items for rText on rRenderContext. Subsequent calls
69 * avoid the calculation and just return a pointer to rTextGlyphs.
71 SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext, const OUString& rText,
72 SalLayoutGlyphs& rTextGlyphs)
74 if (rTextGlyphs.IsValid())
75 // Use pre-calculated result.
76 return &rTextGlyphs;
78 // Calculate glyph items.
80 std::unique_ptr<SalLayout> pLayout = rRenderContext.ImplLayout(
81 rText, 0, rText.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly);
82 if (!pLayout)
83 return nullptr;
85 // Remember the calculation result.
86 rTextGlyphs = pLayout->GetGlyphs();
88 return &rTextGlyphs;
92 class ImplRulerData
94 friend class Ruler;
96 private:
97 std::vector<RulerLine> pLines;
98 std::vector<RulerBorder> pBorders;
99 std::vector<RulerIndent> pIndents;
100 std::vector<RulerTab> pTabs;
102 tools::Long nNullVirOff;
103 tools::Long nRulVirOff;
104 tools::Long nRulWidth;
105 tools::Long nPageOff;
106 tools::Long nPageWidth;
107 tools::Long nNullOff;
108 tools::Long nMargin1;
109 tools::Long nMargin2;
110 // In this context, "frame margin" means paragraph margins (indents)
111 tools::Long nLeftFrameMargin;
112 tools::Long nRightFrameMargin;
113 RulerMarginStyle nMargin1Style;
114 RulerMarginStyle nMargin2Style;
115 bool bAutoPageWidth;
116 bool bTextRTL;
118 public:
119 ImplRulerData();
122 ImplRulerData::ImplRulerData() :
123 nNullVirOff (0),
124 nRulVirOff (0),
125 nRulWidth (0),
126 nPageOff (0),
127 nPageWidth (0),
128 nNullOff (0),
129 nMargin1 (0),
130 nMargin2 (0),
131 nLeftFrameMargin (0),
132 nRightFrameMargin (0),
133 nMargin1Style (RulerMarginStyle::NONE),
134 nMargin2Style (RulerMarginStyle::NONE),
135 bAutoPageWidth (true), // Page width == EditWin width
136 bTextRTL (false)
140 const RulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] =
142 { MapUnit::Map100thMM, 100, 25.0, 25.0, 50.0, 100.0, " mm" }, // MM
143 { MapUnit::Map100thMM, 1000, 100.0, 500.0, 1000.0, 1000.0, " cm" }, // CM
144 { MapUnit::MapMM, 1000, 10.0, 250.0, 500.0, 1000.0, " m" }, // M
145 { MapUnit::MapCM, 100000, 12500.0, 25000.0, 50000.0, 100000.0, " km" }, // KM
146 { MapUnit::Map1000thInch, 1000, 62.5, 125.0, 500.0, 1000.0, "\"" }, // INCH
147 { MapUnit::Map100thInch, 1200, 120.0, 120.0, 600.0, 1200.0, "'" }, // FOOT
148 { MapUnit::Map10thInch, 633600, 63360.0, 63360.0, 316800.0, 633600.0, " miles" }, // MILE
149 { MapUnit::MapPoint, 1, 12.0, 12.0, 12.0, 36.0, " pt" }, // POINT
150 { MapUnit::Map100thMM, 423, 423.0, 423.0, 423.0, 846.0, " pc" }, // PICA
151 { MapUnit::Map100thMM, 371, 371.0, 371.0, 371.0, 743.0, " ch" }, // CHAR
152 { MapUnit::Map100thMM, 551, 551.0, 551.0, 551.0, 1102.0, " li" } // LINE
155 static RulerTabData ruler_tab =
157 0, // DPIScaleFactor to be set
158 7, // ruler_tab_width
159 6, // ruler_tab_height
160 2, // ruler_tab_height2
161 2, // ruler_tab_width2
162 8, // ruler_tab_cwidth
163 4, // ruler_tab_cwidth2
164 4, // ruler_tab_cwidth3
165 2, // ruler_tab_cwidth4
166 4, // ruler_tab_dheight
167 1, // ruler_tab_dheight2
168 5, // ruler_tab_dwidth
169 3, // ruler_tab_dwidth2
170 3, // ruler_tab_dwidth3
171 1, // ruler_tab_dwidth4
172 5 // ruler_tab_textoff
175 void Ruler::ImplInit( WinBits nWinBits )
177 // Set default WinBits
178 if ( !(nWinBits & WB_VERT) )
180 nWinBits |= WB_HORZ;
182 // RTL: no UI mirroring for horizontal rulers, because
183 // the document is also not mirrored
184 EnableRTL( false );
187 // Initialize variables
188 mnWinStyle = nWinBits; // Window-Style
189 mnBorderOff = 0; // Border-Offset
190 mnWinOff = 0; // EditWinOffset
191 mnWinWidth = 0; // EditWinWidth
192 mnWidth = 0; // Window width
193 mnHeight = 0; // Window height
194 mnVirOff = 0; // Offset of VirtualDevice from top-left corner
195 mnVirWidth = 0; // width or height from VirtualDevice
196 mnVirHeight = 0; // height of width from VirtualDevice
197 mnDragPos = 0; // Drag-Position (Null point)
198 mnDragAryPos = 0; // Drag-Array-Index
199 mnDragSize = RulerDragSize::Move; // Did size change at dragging
200 mnDragModifier = 0; // Modifier key at dragging
201 mnExtraStyle = 0; // Style of Extra field
202 mnCharWidth = 371;
203 mnLineHeight = 551;
204 mbCalc = true; // Should recalculate page width
205 mbFormat = true; // Should redraw
206 mbDrag = false; // Currently at dragging
207 mbDragDelete = false; // Has mouse left the dragging area
208 mbDragCanceled = false; // Dragging cancelled?
209 mbAutoWinWidth = true; // EditWinWidth == RulerWidth
210 mbActive = true; // Is ruler active
211 mnUpdateFlags = 0; // What needs to be updated
212 mpData = mpSaveData.get(); // Pointer to normal data
213 meExtraType = RulerExtra::DontKnow; // What is in extra field
214 meDragType = RulerType::DontKnow; // Which element is dragged
216 // Initialize Units
217 mnUnitIndex = RULER_UNIT_CM;
218 meUnit = FieldUnit::CM;
219 maZoom = Fraction( 1, 1 );
221 // Recalculate border widths
222 if ( nWinBits & WB_BORDER )
223 mnBorderWidth = 1;
224 else
225 mnBorderWidth = 0;
227 // Settings
228 ImplInitSettings( true, true, true );
230 // Setup the default size
231 tools::Rectangle aRect;
232 GetOutDev()->GetTextBoundRect( aRect, u"0123456789"_ustr );
233 tools::Long nDefHeight = aRect.GetHeight() + RULER_OFF * 2 + ruler_tab.textoff * 2 + mnBorderWidth;
235 Size aDefSize;
236 if ( nWinBits & WB_HORZ )
237 aDefSize.setHeight( nDefHeight );
238 else
239 aDefSize.setWidth( nDefHeight );
240 SetOutputSizePixel( aDefSize );
241 SetType(WindowType::RULER);
244 Ruler::Ruler( vcl::Window* pParent, WinBits nWinStyle ) :
245 Window( pParent, nWinStyle & WB_3DLOOK ),
246 maVirDev( VclPtr<VirtualDevice>::Create(*GetOutDev()) ),
247 maMapMode( MapUnit::Map100thMM ),
248 mpSaveData(new ImplRulerData),
249 mpData(nullptr),
250 mpDragData(new ImplRulerData)
252 // Check to see if the ruler constructor has
253 // already been called before otherwise
254 // we end up with over-scaled elements
255 if (ruler_tab.DPIScaleFactor == 0)
257 ruler_tab.DPIScaleFactor = GetDPIScaleFactor();
258 ruler_tab.width *= ruler_tab.DPIScaleFactor;
259 ruler_tab.height *= ruler_tab.DPIScaleFactor;
260 ruler_tab.height2 *= ruler_tab.DPIScaleFactor;
261 ruler_tab.width2 *= ruler_tab.DPIScaleFactor;
262 ruler_tab.cwidth *= ruler_tab.DPIScaleFactor;
263 ruler_tab.cwidth2 *= ruler_tab.DPIScaleFactor;
264 ruler_tab.cwidth3 *= ruler_tab.DPIScaleFactor;
265 ruler_tab.cwidth4 *= ruler_tab.DPIScaleFactor;
266 ruler_tab.dheight *= ruler_tab.DPIScaleFactor;
267 ruler_tab.dheight2 *= ruler_tab.DPIScaleFactor;
268 ruler_tab.dwidth *= ruler_tab.DPIScaleFactor;
269 ruler_tab.dwidth2 *= ruler_tab.DPIScaleFactor;
270 ruler_tab.dwidth3 *= ruler_tab.DPIScaleFactor;
271 ruler_tab.dwidth4 *= ruler_tab.DPIScaleFactor;
272 ruler_tab.textoff *= ruler_tab.DPIScaleFactor;
276 ImplInit( nWinStyle );
279 Ruler::~Ruler()
281 disposeOnce();
284 void Ruler::dispose()
286 mpSaveData.reset();
287 mpDragData.reset();
288 mxAccContext.clear();
289 Window::dispose();
292 void Ruler::ImplVDrawLine(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
294 if ( nX1 < -RULER_CLIP )
296 nX1 = -RULER_CLIP;
297 if ( nX2 < -RULER_CLIP )
298 return;
300 tools::Long nClip = mnVirWidth + RULER_CLIP;
301 if ( nX2 > nClip )
303 nX2 = nClip;
304 if ( nX1 > nClip )
305 return;
308 if ( mnWinStyle & WB_HORZ )
309 rRenderContext.DrawLine( Point( nX1, nY1 ), Point( nX2, nY2 ) );
310 else
311 rRenderContext.DrawLine( Point( nY1, nX1 ), Point( nY2, nX2 ) );
314 void Ruler::ImplVDrawRect(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
316 if ( nX1 < -RULER_CLIP )
318 nX1 = -RULER_CLIP;
319 if ( nX2 < -RULER_CLIP )
320 return;
322 tools::Long nClip = mnVirWidth + RULER_CLIP;
323 if ( nX2 > nClip )
325 nX2 = nClip;
326 if ( nX1 > nClip )
327 return;
330 if ( mnWinStyle & WB_HORZ )
331 rRenderContext.DrawRect(tools::Rectangle(nX1, nY1, nX2, nY2));
332 else
333 rRenderContext.DrawRect(tools::Rectangle(nY1, nX1, nY2, nX2));
336 void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, tools::Long nY, const OUString& rText, tools::Long nMin, tools::Long nMax)
338 tools::Rectangle aRect;
339 SalLayoutGlyphs* pTextLayout
340 = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]);
341 rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, {}, {}, pTextLayout);
343 tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left();
344 tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top();
346 if ( (nX > -RULER_CLIP) && (nX < mnVirWidth + RULER_CLIP) && ( nX < nMax - nShiftX ) && ( nX > nMin + nShiftX ) )
348 if ( mnWinStyle & WB_HORZ )
349 rRenderContext.DrawText(Point(nX - nShiftX, nY - nShiftY), rText, 0, -1, nullptr,
350 nullptr, pTextLayout);
351 else
352 rRenderContext.DrawText(Point(nY - nShiftX, nX - nShiftY), rText, 0, -1, nullptr,
353 nullptr, pTextLayout);
357 void Ruler::ImplInvertLines(vcl::RenderContext& rRenderContext)
359 // Position lines
360 if (mpData->pLines.empty() || !mbActive || mbDrag || mbFormat || (mnUpdateFlags & RULER_UPDATE_LINES) )
361 return;
363 tools::Long nNullWinOff = mpData->nNullVirOff + mnVirOff;
364 tools::Long nRulX1 = mpData->nRulVirOff + mnVirOff;
365 tools::Long nRulX2 = nRulX1 + mpData->nRulWidth;
366 tools::Long nY = (RULER_OFF * 2) + mnVirHeight - 1;
368 // Calculate rectangle
369 tools::Rectangle aRect;
370 if (mnWinStyle & WB_HORZ)
371 aRect.SetBottom( nY );
372 else
373 aRect.SetRight( nY );
375 // Draw lines
376 for (const RulerLine & rLine : mpData->pLines)
378 const tools::Long n = rLine.nPos + nNullWinOff;
379 if ((n >= nRulX1) && (n < nRulX2))
381 if (mnWinStyle & WB_HORZ )
383 aRect.SetLeft( n );
384 aRect.SetRight( n );
386 else
388 aRect.SetTop( n );
389 aRect.SetBottom( n );
391 tools::Rectangle aTempRect = aRect;
393 if (mnWinStyle & WB_HORZ)
394 aTempRect.SetBottom( RULER_OFF - 1 );
395 else
396 aTempRect.SetRight( RULER_OFF - 1 );
398 rRenderContext.Erase(aTempRect);
400 if (mnWinStyle & WB_HORZ)
402 aTempRect.SetBottom( aRect.Bottom() );
403 aTempRect.SetTop( aTempRect.Bottom() - RULER_OFF + 1 );
405 else
407 aTempRect.SetRight( aRect.Right() );
408 aTempRect.SetLeft( aTempRect.Right() - RULER_OFF + 1 );
410 rRenderContext.Erase(aTempRect);
411 GetOutDev()->Invert(aRect);
414 mnUpdateFlags = 0;
417 void Ruler::ImplDrawTicks(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nStart, tools::Long nTop, tools::Long nBottom)
419 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
420 double nCenter = nTop + ((nBottom - nTop) / 2);
422 tools::Long nTickLength3 = (nBottom - nTop) * 0.5;
423 tools::Long nTickLength2 = nTickLength3 * 0.66;
424 tools::Long nTickLength1 = nTickLength2 * 0.66;
426 tools::Long nScale = ruler_tab.DPIScaleFactor;
427 tools::Long DPIOffset = nScale - 1;
429 double nTick4 = aImplRulerUnitTab[mnUnitIndex].nTick4;
430 double nTick2 = 0;
431 double nTickCount = aImplRulerUnitTab[mnUnitIndex].nTick1 / nScale;
432 double nTickUnit = 0;
433 tools::Long nTickWidth;
434 bool bNoTicks = false;
436 Size aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
438 if (mnUnitIndex == RULER_UNIT_CHAR)
440 if (mnCharWidth == 0)
441 mnCharWidth = 371;
442 nTick4 = mnCharWidth * 2;
443 nTick2 = mnCharWidth;
444 nTickCount = mnCharWidth;
445 nTickUnit = mnCharWidth;
447 else if (mnUnitIndex == RULER_UNIT_LINE)
449 if (mnLineHeight == 0)
450 mnLineHeight = 551;
451 nTick4 = mnLineHeight * 2;
452 nTick2 = mnLineHeight;
453 nTickUnit = mnLineHeight;
454 nTickCount = mnLineHeight;
457 if (mnWinStyle & WB_HORZ)
459 nTickWidth = aPixSize.Width();
461 else
463 vcl::Font aFont = rRenderContext.GetFont();
464 if (mnWinStyle & WB_RIGHT_ALIGNED)
465 aFont.SetOrientation(2700_deg10);
466 else
467 aFont.SetOrientation(900_deg10);
468 rRenderContext.SetFont(aFont);
469 nTickWidth = aPixSize.Height();
472 tools::Long nMaxWidth = rRenderContext.PixelToLogic(Size(mpData->nPageWidth, 0), maMapMode).Width();
473 if (nMaxWidth < 0)
474 nMaxWidth = -nMaxWidth;
476 if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
477 nMaxWidth /= nTickUnit;
478 else
479 nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit;
481 OUString aNumString = OUString::number(nMaxWidth);
482 tools::Long nTxtWidth = rRenderContext.GetTextWidth( aNumString );
483 const tools::Long nTextOff = 4;
485 // Determine the number divider for ruler drawn numbers - means which numbers
486 // should be shown on the ruler and which should be skipped because the ruler
487 // is not big enough to draw them
488 if (nTickWidth < nTxtWidth + nTextOff)
490 // Calculate the scale of the ruler
491 tools::Long nMulti = 1;
492 tools::Long nOrgTick4 = nTick4;
494 while (nTickWidth < nTxtWidth + nTextOff)
496 tools::Long nOldMulti = nMulti;
497 if (nTickWidth == 0)
498 nMulti *= 10;
499 else if (nMulti < 10)
500 nMulti++;
501 else if (nMulti < 100)
502 nMulti += 10;
503 else if (nMulti < 1000)
504 nMulti += 100;
505 else
506 nMulti += 1000;
508 // Overflow - in this case don't draw ticks and exit
509 if (nMulti < nOldMulti)
511 bNoTicks = true;
512 break;
515 nTick4 = nOrgTick4 * nMulti;
516 aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
517 if (mnWinStyle & WB_HORZ)
518 nTickWidth = aPixSize.Width();
519 else
520 nTickWidth = aPixSize.Height();
522 nTickCount = nTick4;
524 else
526 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
529 if (bNoTicks)
530 return;
532 tools::Long n = 0;
533 double nTick = 0.0;
534 double nTick3 = 0;
536 if ((mnUnitIndex != RULER_UNIT_CHAR) && (mnUnitIndex != RULER_UNIT_LINE))
538 nTick2 = aImplRulerUnitTab[mnUnitIndex].nTick2;
539 nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3;
542 Size nTickGapSize;
544 nTickGapSize = rRenderContext.LogicToPixel(Size(nTickCount, nTickCount), maMapMode);
545 tools::Long nTickGap1 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
546 nTickGapSize = rRenderContext.LogicToPixel(Size(nTick2, nTick2), maMapMode);
547 tools::Long nTickGap2 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
548 nTickGapSize = rRenderContext.LogicToPixel(Size(nTick3, nTick3), maMapMode);
549 tools::Long nTickGap3 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
551 while (((nStart - n) >= nMin) || ((nStart + n) <= nMax))
553 // Null point
554 if (nTick == 0.0)
556 if (nStart > nMin)
558 // 0 is only painted when Margin1 is not equal to zero
559 if ((mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin1 != 0))
561 aNumString = "0";
562 ImplVDrawText(rRenderContext, nStart, nCenter, aNumString);
566 else
568 aPixSize = rRenderContext.LogicToPixel(Size(nTick, nTick), maMapMode);
570 if (mnWinStyle & WB_HORZ)
571 n = aPixSize.Width();
572 else
573 n = aPixSize.Height();
575 // Tick4 - Output (Text)
576 double aStep = nTick / nTick4;
577 double aRest = std::abs(aStep - std::floor(aStep));
578 double nAcceptanceDelta = 0.0001;
579 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
581 if (aRest < nAcceptanceDelta)
583 if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
584 aNumString = OUString::number(nTick / nTickUnit);
585 else
586 aNumString = OUString::number(nTick / aImplRulerUnitTab[mnUnitIndex].nTickUnit);
588 tools::Long nHorizontalLocation = nStart + n;
589 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
591 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
593 ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom - 1 * nScale, nHorizontalLocation + DPIOffset, nBottom);
594 ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop, nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
597 nHorizontalLocation = nStart - n;
598 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
600 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
602 ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom,
603 nHorizontalLocation + DPIOffset, nBottom - 1 * nScale);
604 ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop,
605 nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
608 // Tick/Tick2 - Output (Strokes)
609 else
611 tools::Long nTickLength = nTickLength1;
613 aStep = (nTick / nTick2);
614 aRest = std::abs(aStep - std::floor(aStep));
615 if (aRest < nAcceptanceDelta)
616 nTickLength = nTickLength2;
618 aStep = (nTick / nTick3);
619 aRest = std::abs(aStep - std::floor(aStep));
620 if (aRest < nAcceptanceDelta )
621 nTickLength = nTickLength3;
623 if ((nTickLength == nTickLength1 && nTickGap1 > 6) ||
624 (nTickLength == nTickLength2 && nTickGap2 > 6) ||
625 (nTickLength == nTickLength3 && nTickGap3 > 6))
627 tools::Long nT1 = nCenter - (nTickLength / 2.0);
628 tools::Long nT2 = nT1 + nTickLength - 1;
629 tools::Long nT;
631 nT = nStart + n;
633 if (nT < nMax)
634 ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2);
635 nT = nStart - n;
636 if (nT > nMin)
637 ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2);
641 nTick += nTickCount;
645 void Ruler::ImplDrawBorders(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
647 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
648 tools::Long n;
649 tools::Long n1;
650 tools::Long n2;
651 tools::Long nTemp1;
652 tools::Long nTemp2;
654 for (std::vector<RulerBorder>::size_type i = 0; i < mpData->pBorders.size(); i++)
656 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Invisible)
657 continue;
659 n1 = mpData->pBorders[i].nPos + mpData->nNullVirOff;
660 n2 = n1 + mpData->pBorders[i].nWidth;
662 if (((n1 >= nMin) && (n1 <= nMax)) || ((n2 >= nMin) && (n2 <= nMax)))
664 if ((n2 - n1) > 3)
666 rRenderContext.SetLineColor();
667 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
668 ImplVDrawRect(rRenderContext, n1, nVirTop, n2, nVirBottom);
670 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
671 ImplVDrawLine(rRenderContext, n1 + 1, nVirTop, n1 + 1, nVirBottom);
672 ImplVDrawLine(rRenderContext, n1, nVirTop, n2, nVirTop);
674 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
675 ImplVDrawLine(rRenderContext, n1, nVirTop, n1, nVirBottom);
676 ImplVDrawLine(rRenderContext, n1, nVirBottom, n2, nVirBottom);
677 ImplVDrawLine(rRenderContext, n2 - 1, nVirTop, n2 - 1, nVirBottom);
679 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
680 ImplVDrawLine(rRenderContext, n2, nVirTop, n2, nVirBottom);
682 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Variable)
684 if (n2 - n1 > RULER_VAR_SIZE + 4)
686 nTemp1 = n1 + (((n2 - n1 + 1) - RULER_VAR_SIZE) / 2);
687 nTemp2 = nVirTop + (((nVirBottom - nVirTop + 1) - RULER_VAR_SIZE) / 2);
688 tools::Long nTemp3 = nTemp1 + RULER_VAR_SIZE - 1;
689 tools::Long nTemp4 = nTemp2 + RULER_VAR_SIZE - 1;
690 tools::Long nTempY = nTemp2;
692 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
693 while (nTempY <= nTemp4)
695 ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
696 nTempY += 2;
699 nTempY = nTemp2 + 1;
700 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
701 while (nTempY <= nTemp4)
703 ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
704 nTempY += 2;
709 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Sizeable)
711 if (n2 - n1 > RULER_VAR_SIZE + 10)
713 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
714 ImplVDrawLine(rRenderContext, n1 + 4, nVirTop + 3, n1 + 4, nVirBottom - 3);
715 ImplVDrawLine(rRenderContext, n2 - 5, nVirTop + 3, n2 - 5, nVirBottom - 3);
716 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
717 ImplVDrawLine(rRenderContext, n1 + 5, nVirTop + 3, n1 + 5, nVirBottom - 3);
718 ImplVDrawLine(rRenderContext, n2 - 4, nVirTop + 3, n2 - 4, nVirBottom - 3);
722 else
724 n = n1 + ((n2 - n1) / 2);
725 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
727 ImplVDrawLine(rRenderContext, n - 1, nVirTop, n - 1, nVirBottom);
728 ImplVDrawLine(rRenderContext, n + 1, nVirTop, n + 1, nVirBottom);
729 rRenderContext.SetLineColor();
730 rRenderContext.SetFillColor(rStyleSettings.GetWindowColor());
731 ImplVDrawRect(rRenderContext, n, nVirTop, n, nVirBottom);
737 void Ruler::ImplDrawIndent(vcl::RenderContext& rRenderContext, const tools::Polygon& rPoly, bool bIsHit)
739 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
741 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
742 rRenderContext.SetFillColor(bIsHit ? rStyleSettings.GetDarkShadowColor() : rStyleSettings.GetWorkspaceColor());
743 tools::Polygon aPolygon(rPoly);
744 aPolygon.Optimize(PolyOptimizeFlags::CLOSE);
745 rRenderContext.DrawPolygon(aPolygon);
748 void Ruler::ImplDrawIndents(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
750 tools::Long n;
751 tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
752 tools::Long nIndentWidth2 = nIndentHeight-3;
754 tools::Polygon aPoly(5);
756 for (std::vector<RulerIndent>::size_type j = 0; j < mpData->pIndents.size(); j++)
758 if (mpData->pIndents[j].bInvisible)
759 continue;
761 RulerIndentStyle nIndentStyle = mpData->pIndents[j].nStyle;
763 n = mpData->pIndents[j].nPos+mpData->nNullVirOff;
765 if ((n >= nMin) && (n <= nMax))
767 if (nIndentStyle == RulerIndentStyle::Bottom)
769 aPoly.SetPoint(Point(n + 0, nVirBottom - nIndentHeight), 0);
770 aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom - 3), 1);
771 aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom), 2);
772 aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom), 3);
773 aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom - 3), 4);
775 else
777 aPoly.SetPoint(Point(n + 0, nVirTop + nIndentHeight), 0);
778 aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop + 3), 1);
779 aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop), 2);
780 aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop), 3);
781 aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop + 3), 4);
784 if (0 == (mnWinStyle & WB_HORZ))
786 Point aTmp;
787 for (sal_uInt16 i = 0; i < 5; i++)
789 aTmp = aPoly[i];
790 Point aSet(nVirBottom - aTmp.Y(), aTmp.X());
791 aPoly[i] = aSet;
794 bool bIsHit = false;
795 if (mxCurrentHitTest != nullptr && mxCurrentHitTest->eType == RulerType::Indent)
797 bIsHit = mxCurrentHitTest->nAryPos == j;
799 else if(mbDrag && meDragType == RulerType::Indent)
801 bIsHit = mnDragAryPos == j;
803 ImplDrawIndent(rRenderContext, aPoly, bIsHit);
808 static void ImplCenterTabPos(Point& rPos, sal_uInt16 nTabStyle)
810 bool bRTL = 0 != (nTabStyle & RULER_TAB_RTL);
811 nTabStyle &= RULER_TAB_STYLE;
812 rPos.AdjustY(ruler_tab.height/2 );
814 if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) ||
815 ( bRTL && nTabStyle == RULER_TAB_RIGHT) )
817 rPos.AdjustX( -(ruler_tab.width / 2) );
819 else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) ||
820 ( bRTL && nTabStyle == RULER_TAB_LEFT) )
822 rPos.AdjustX(ruler_tab.width / 2 );
826 static void lcl_RotateRect_Impl(tools::Rectangle& rRect, const tools::Long nReference, bool bRightAligned)
828 if (rRect.IsEmpty())
829 return;
831 tools::Rectangle aTmp(rRect);
832 rRect.SetTop( aTmp.Left() );
833 rRect.SetBottom( aTmp.Right() );
834 rRect.SetLeft( aTmp.Top() );
835 rRect.SetRight( aTmp.Bottom() );
837 if (bRightAligned)
839 tools::Long nRef = 2 * nReference;
840 rRect.SetLeft( nRef - rRect.Left() );
841 rRect.SetRight( nRef - rRect.Right() );
845 static void ImplDrawRulerTab(vcl::RenderContext& rRenderContext, const Point& rPos,
846 sal_uInt16 nStyle, WinBits nWinBits)
848 if (nStyle & RULER_STYLE_INVISIBLE)
849 return;
851 sal_uInt16 nTabStyle = nStyle & RULER_TAB_STYLE;
852 bool bRTL = 0 != (nStyle & RULER_TAB_RTL);
854 // Scale by the screen DPI scaling factor
855 // However when doing this some of the rectangles
856 // drawn become asymmetric due to the +1 offsets
857 sal_uInt16 DPIOffset = rRenderContext.GetDPIScaleFactor() - 1;
859 // A tabstop is drawn using three rectangles
860 tools::Rectangle aRect1; // A horizontal short line
861 tools::Rectangle aRect2; // A vertical short line
862 tools::Rectangle aRect3; // A small square
864 aRect3.SetEmpty();
866 if (nTabStyle == RULER_TAB_DEFAULT)
868 aRect1.SetLeft( rPos.X() - ruler_tab.dwidth2 + 1 );
869 aRect1.SetTop( rPos.Y() - ruler_tab.dheight2 + 1 );
870 aRect1.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth + DPIOffset );
871 aRect1.SetBottom( rPos.Y() );
873 aRect2.SetLeft( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 );
874 aRect2.SetTop( rPos.Y() - ruler_tab.dheight + 1 );
875 aRect2.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 + ruler_tab.dwidth4 - 1 );
876 aRect2.SetBottom( rPos.Y() );
879 else if ((!bRTL && nTabStyle == RULER_TAB_LEFT) || (bRTL && nTabStyle == RULER_TAB_RIGHT))
881 aRect1.SetLeft( rPos.X() );
882 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
883 aRect1.SetRight( rPos.X() + ruler_tab.width - 1 );
884 aRect1.SetBottom( rPos.Y() );
886 aRect2.SetLeft( rPos.X() );
887 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
888 aRect2.SetRight( rPos.X() + ruler_tab.width2 - 1 );
889 aRect2.SetBottom( rPos.Y() );
891 else if ((!bRTL && nTabStyle == RULER_TAB_RIGHT) || (bRTL && nTabStyle == RULER_TAB_LEFT))
893 aRect1.SetLeft( rPos.X() - ruler_tab.width + 1 );
894 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
895 aRect1.SetRight( rPos.X() );
896 aRect1.SetBottom( rPos.Y() );
898 aRect2.SetLeft( rPos.X() - ruler_tab.width2 + 1 );
899 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
900 aRect2.SetRight( rPos.X() );
901 aRect2.SetBottom( rPos.Y() );
903 else
905 aRect1.SetLeft( rPos.X() - ruler_tab.cwidth2 + 1 );
906 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
907 aRect1.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset );
908 aRect1.SetBottom( rPos.Y() );
910 aRect2.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 );
911 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
912 aRect2.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 + ruler_tab.cwidth4 - 1 );
913 aRect2.SetBottom( rPos.Y() );
915 if (nTabStyle == RULER_TAB_DECIMAL)
917 aRect3.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth - 1 );
918 aRect3.SetTop( rPos.Y() - ruler_tab.height + 1 + 1 - DPIOffset );
919 aRect3.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset );
920 aRect3.SetBottom( rPos.Y() - ruler_tab.height + 1 + 2 );
923 if (0 == (nWinBits & WB_HORZ))
925 bool bRightAligned = 0 != (nWinBits & WB_RIGHT_ALIGNED);
926 lcl_RotateRect_Impl(aRect1, rPos.Y(), bRightAligned);
927 lcl_RotateRect_Impl(aRect2, rPos.Y(), bRightAligned);
928 lcl_RotateRect_Impl(aRect3, rPos.Y(), bRightAligned);
930 rRenderContext.DrawRect(aRect1);
931 rRenderContext.DrawRect(aRect2);
933 if (!aRect3.IsEmpty())
934 rRenderContext.DrawRect(aRect3);
937 void Ruler::ImplDrawTab(vcl::RenderContext& rRenderContext, const Point& rPos, sal_uInt16 nStyle)
939 if (nStyle & RULER_STYLE_INVISIBLE)
940 return;
942 rRenderContext.SetLineColor();
944 if (nStyle & RULER_STYLE_DONTKNOW)
945 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceColor());
946 else
947 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor());
949 if (mpData->bTextRTL)
950 nStyle |= RULER_TAB_RTL;
952 ImplDrawRulerTab(rRenderContext, rPos, nStyle, GetStyle());
955 void Ruler::ImplDrawTabs(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
957 for (const RulerTab & rTab : mpData->pTabs)
959 if (rTab.nStyle & RULER_STYLE_INVISIBLE)
960 continue;
962 tools::Long aPosition;
963 aPosition = rTab.nPos;
964 aPosition += +mpData->nNullVirOff;
965 tools::Long nTopBottom = (GetStyle() & WB_RIGHT_ALIGNED) ? nVirTop : nVirBottom;
966 if (nMin <= aPosition && aPosition <= nMax)
967 ImplDrawTab(rRenderContext, Point( aPosition, nTopBottom ), rTab.nStyle);
971 static int adjustSize(int nOrig)
973 if (nOrig <= 0)
974 return 0;
976 // make sure we return an odd number, that looks better in the ruler
977 return ( (3*nOrig) / 8) * 2 + 1;
980 void Ruler::ApplySettings(vcl::RenderContext& rRenderContext)
982 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
984 vcl::Font aFont = rStyleSettings.GetToolFont();
985 // make the font a bit smaller than default
986 Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
987 aFont.SetFontSize(aSize);
989 ApplyControlFont(rRenderContext, aFont);
991 ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
992 SetTextFillColor();
994 Color aColor;
995 svtools::ColorConfig aColorConfig;
996 aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
997 ApplyControlBackground(rRenderContext, aColor);
998 // A hack to get it to change the non-ruler application background to change immediately
999 if (aColor != maVirDev->GetBackground().GetColor())
1001 maVirDev->SetBackground(aColor);
1002 Resize();
1006 void Ruler::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1008 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1010 if (bFont)
1012 vcl::Font aFont = rStyleSettings.GetToolFont();
1013 // make the font a bit smaller than default
1014 Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
1015 aFont.SetFontSize(aSize);
1017 ApplyControlFont(*GetOutDev(), aFont);
1020 if (bForeground || bFont)
1022 ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
1023 SetTextFillColor();
1026 if (bBackground)
1028 Color aColor;
1029 svtools::ColorConfig aColorConfig;
1030 aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
1031 ApplyControlBackground(*GetOutDev(), aColor);
1034 maVirDev->SetSettings( GetSettings() );
1035 maVirDev->SetBackground( GetBackground() );
1036 vcl::Font aFont = GetFont();
1038 if (mnWinStyle & WB_VERT)
1039 aFont.SetOrientation(900_deg10);
1041 maVirDev->SetFont(aFont);
1042 maVirDev->SetTextColor(GetTextColor());
1043 maVirDev->SetTextFillColor(GetTextFillColor());
1046 void Ruler::ImplCalc()
1048 // calculate offset
1049 mpData->nRulVirOff = mnWinOff + mpData->nPageOff;
1050 if ( mpData->nRulVirOff > mnVirOff )
1051 mpData->nRulVirOff -= mnVirOff;
1052 else
1053 mpData->nRulVirOff = 0;
1054 tools::Long nRulWinOff = mpData->nRulVirOff+mnVirOff;
1056 // calculate non-visual part of the page
1057 tools::Long nNotVisPageWidth;
1058 if ( mpData->nPageOff < 0 )
1060 nNotVisPageWidth = -(mpData->nPageOff);
1061 if ( nRulWinOff < mnWinOff )
1062 nNotVisPageWidth -= mnWinOff-nRulWinOff;
1064 else
1065 nNotVisPageWidth = 0;
1067 // calculate width
1068 if ( mnWinStyle & WB_HORZ )
1070 if ( mbAutoWinWidth )
1071 mnWinWidth = mnWidth - mnVirOff;
1072 if ( mpData->bAutoPageWidth )
1073 mpData->nPageWidth = mnWinWidth;
1074 mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1075 if ( nRulWinOff+mpData->nRulWidth > mnWidth )
1076 mpData->nRulWidth = mnWidth-nRulWinOff;
1078 else
1080 if ( mbAutoWinWidth )
1081 mnWinWidth = mnHeight - mnVirOff;
1082 if ( mpData->bAutoPageWidth )
1083 mpData->nPageWidth = mnWinWidth;
1084 mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1085 if ( nRulWinOff+mpData->nRulWidth > mnHeight )
1086 mpData->nRulWidth = mnHeight-nRulWinOff;
1089 mbCalc = false;
1092 void Ruler::ImplFormat(vcl::RenderContext const & rRenderContext)
1094 // if already formatted, don't do it again
1095 if (!mbFormat)
1096 return;
1098 // don't do anything if the window still has no size
1099 if (!mnVirWidth)
1100 return;
1102 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1103 tools::Long nP1; // pixel position of Page1
1104 tools::Long nP2; // pixel position of Page2
1105 tools::Long nM1; // pixel position of Margin1
1106 tools::Long nM2; // pixel position of Margin2
1107 tools::Long nVirTop; // top/left corner
1108 tools::Long nVirBottom; // bottom/right corner
1109 tools::Long nVirLeft; // left/top corner
1110 tools::Long nVirRight; // right/bottom corner
1111 tools::Long nNullVirOff; // for faster calculation
1113 // calculate values
1114 if (mbCalc)
1115 ImplCalc();
1117 mpData->nNullVirOff = mnWinOff + mpData->nPageOff + mpData->nNullOff - mnVirOff;
1119 nNullVirOff = mpData->nNullVirOff;
1120 nVirLeft = mpData->nRulVirOff;
1121 nVirRight = nVirLeft + mpData->nRulWidth - 1;
1122 nVirTop = 0;
1123 nVirBottom = mnVirHeight - 1;
1125 if (!IsReallyVisible())
1126 return;
1128 Size aVirDevSize;
1130 // initialize VirtualDevice
1131 if (mnWinStyle & WB_HORZ)
1133 aVirDevSize.setWidth( mnVirWidth );
1134 aVirDevSize.setHeight( mnVirHeight );
1136 else
1138 aVirDevSize.setHeight( mnVirWidth );
1139 aVirDevSize.setWidth( mnVirHeight );
1141 if (aVirDevSize != maVirDev->GetOutputSizePixel())
1142 maVirDev->SetOutputSizePixel(aVirDevSize);
1143 else
1144 maVirDev->Erase();
1146 // calculate margins
1147 if (!(mpData->nMargin1Style & RulerMarginStyle::Invisible))
1149 nM1 = mpData->nMargin1 + nNullVirOff;
1150 if (mpData->bAutoPageWidth)
1152 nP1 = nVirLeft;
1153 if (nM1 < nVirLeft)
1154 nP1--;
1156 else
1157 nP1 = nNullVirOff - mpData->nNullOff;
1159 else
1161 nM1 = nVirLeft-1;
1162 nP1 = nM1;
1164 if (!(mpData->nMargin2Style & RulerMarginStyle::Invisible))
1166 nM2 = mpData->nMargin2 + nNullVirOff;
1167 if (mpData->bAutoPageWidth)
1169 nP2 = nVirRight;
1170 if (nM2 > nVirRight)
1171 nP2++;
1173 else
1174 nP2 = nNullVirOff - mpData->nNullOff + mpData->nPageWidth;
1175 if (nM2 > nP2)
1176 nM2 = nP2;
1178 else
1180 nM2 = nVirRight+1;
1181 nP2 = nM2;
1184 // top/bottom border
1185 maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1186 ImplVDrawLine(*maVirDev, nVirLeft, nVirTop + 1, nM1, nVirTop + 1); //top left line
1187 ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nP2 - 1, nVirTop + 1); //top right line
1189 nVirTop++;
1190 nVirBottom--;
1192 // draw margin1, margin2 and in-between
1193 maVirDev->SetLineColor();
1194 maVirDev->SetFillColor(rStyleSettings.GetDialogColor());
1195 if (nM1 > nVirLeft)
1196 ImplVDrawRect(*maVirDev, nP1, nVirTop + 1, nM1, nVirBottom); //left gray rectangle
1197 if (nM2 < nP2)
1198 ImplVDrawRect(*maVirDev, nM2, nVirTop + 1, nP2, nVirBottom); //right gray rectangle
1199 if (nM2 - nM1 > 0)
1201 maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1202 ImplVDrawRect(*maVirDev, nM1 + 1, nVirTop, nM2 - 1, nVirBottom); //center rectangle
1204 maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1205 if (nM1 > nVirLeft)
1207 ImplVDrawLine(*maVirDev, nM1, nVirTop + 1, nM1, nVirBottom); //right line of the left rectangle
1208 ImplVDrawLine(*maVirDev, nP1, nVirBottom, nM1, nVirBottom); //bottom line of the left rectangle
1209 if (nP1 >= nVirLeft)
1211 ImplVDrawLine(*maVirDev, nP1, nVirTop + 1, nP1, nVirBottom); //left line of the left rectangle
1212 ImplVDrawLine(*maVirDev, nP1, nVirBottom, nP1 + 1, nVirBottom); //?
1215 if (nM2 < nP2)
1217 ImplVDrawLine(*maVirDev, nM2, nVirBottom, nP2 - 1, nVirBottom); //bottom line of the right rectangle
1218 ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nM2, nVirBottom); //left line of the right rectangle
1219 if (nP2 <= nVirRight + 1)
1220 ImplVDrawLine(*maVirDev, nP2 - 1, nVirTop + 1, nP2 - 1, nVirBottom); //right line of the right rectangle
1223 tools::Long nMin = nVirLeft;
1224 tools::Long nMax = nP2;
1225 tools::Long nStart = 0;
1227 if (mpData->bTextRTL)
1228 nStart = mpData->nRightFrameMargin + nNullVirOff;
1229 else
1230 nStart = mpData->nLeftFrameMargin + nNullVirOff;
1232 if (nP1 > nVirLeft)
1233 nMin++;
1235 if (nP2 < nVirRight)
1236 nMax--;
1238 // Draw captions
1239 ImplDrawTicks(*maVirDev, nMin, nMax, nStart, nVirTop, nVirBottom);
1241 // Draw borders
1242 if (!mpData->pBorders.empty())
1243 ImplDrawBorders(*maVirDev, nVirLeft, nP2, nVirTop, nVirBottom);
1245 // Draw indents
1246 if (!mpData->pIndents.empty())
1247 ImplDrawIndents(*maVirDev, nVirLeft, nP2, nVirTop - 1, nVirBottom + 1);
1249 // Tabs
1250 if (!mpData->pTabs.empty())
1251 ImplDrawTabs(*maVirDev, nVirLeft, nP2, nVirTop-1, nVirBottom + 1);
1253 mbFormat = false;
1256 void Ruler::ImplInitExtraField( bool bUpdate )
1258 Size aWinSize = GetOutputSizePixel();
1260 // extra field evaluate
1261 if ( mnWinStyle & WB_EXTRAFIELD )
1263 maExtraRect.SetLeft( RULER_OFF );
1264 maExtraRect.SetTop( RULER_OFF );
1265 maExtraRect.SetRight( RULER_OFF + mnVirHeight - 1 );
1266 maExtraRect.SetBottom( RULER_OFF + mnVirHeight - 1 );
1267 if(mpData->bTextRTL)
1269 if(mnWinStyle & WB_HORZ)
1270 maExtraRect.Move(aWinSize.Width() - maExtraRect.GetWidth() - maExtraRect.Left(), 0);
1271 else
1272 maExtraRect.Move(0, aWinSize.Height() - maExtraRect.GetHeight() - maExtraRect.Top());
1273 mnVirOff = 0;
1275 else
1276 mnVirOff = maExtraRect.Right()+1;
1279 else
1281 maExtraRect.SetEmpty();
1282 mnVirOff = 0;
1285 // mnVirWidth depends on mnVirOff
1286 if ( (mnVirWidth > RULER_MIN_SIZE) ||
1287 ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) )
1289 if ( mnWinStyle & WB_HORZ )
1290 mnVirWidth = aWinSize.Width()-mnVirOff;
1291 else
1292 mnVirWidth = aWinSize.Height()-mnVirOff;
1294 if ( mnVirWidth < RULER_MIN_SIZE )
1295 mnVirWidth = 0;
1298 if ( bUpdate )
1300 mbCalc = true;
1301 mbFormat = true;
1302 Invalidate();
1306 void Ruler::ImplDraw(vcl::RenderContext& rRenderContext)
1308 if (mbFormat)
1310 ImplFormat(rRenderContext);
1313 if (!IsReallyVisible())
1314 return;
1316 // output the ruler to the virtual device
1317 Point aOffPos;
1318 Size aVirDevSize = maVirDev->GetOutputSizePixel();
1320 if (mnWinStyle & WB_HORZ)
1322 aOffPos.setX( mnVirOff );
1323 if (mpData->bTextRTL)
1324 aVirDevSize.AdjustWidth( -(maExtraRect.GetWidth()) );
1326 aOffPos.setY( RULER_OFF );
1328 else
1330 aOffPos.setX( RULER_OFF );
1331 aOffPos.setY( mnVirOff );
1333 rRenderContext.DrawOutDev(aOffPos, aVirDevSize, Point(), aVirDevSize, *maVirDev);
1335 // redraw positionlines
1336 ImplInvertLines(rRenderContext);
1339 void Ruler::ImplDrawExtra(vcl::RenderContext& rRenderContext)
1341 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1342 tools::Rectangle aRect = maExtraRect;
1343 bool bEraseRect = false;
1345 aRect.AdjustLeft(2 );
1346 aRect.AdjustTop(2 );
1347 aRect.AdjustRight( -2 );
1348 aRect.AdjustBottom( -2 );
1350 if (mnExtraStyle & RULER_STYLE_HIGHLIGHT)
1352 rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
1353 bEraseRect = true;
1356 if (bEraseRect)
1358 rRenderContext.SetLineColor();
1359 rRenderContext.DrawRect(aRect);
1362 // output content
1363 if (meExtraType == RulerExtra::NullOffset)
1365 rRenderContext.SetLineColor(rStyleSettings.GetButtonTextColor());
1366 rRenderContext.DrawLine(Point(aRect.Left() + 1, aRect.Top() + 4),
1367 Point(aRect.Right() - 1, aRect.Top() + 4));
1368 rRenderContext.DrawLine(Point(aRect.Left() + 4, aRect.Top() + 1),
1369 Point(aRect.Left() + 4, aRect.Bottom() - 1));
1371 else if (meExtraType == RulerExtra::Tab)
1373 sal_uInt16 nTabStyle = mnExtraStyle & RULER_TAB_STYLE;
1374 if (mpData->bTextRTL)
1375 nTabStyle |= RULER_TAB_RTL;
1376 Point aCenter = aRect.Center();
1377 Point aDraw(aCenter);
1378 ImplCenterTabPos(aDraw, nTabStyle);
1379 WinBits nWinBits = GetStyle();
1380 if (0 == (nWinBits & WB_HORZ))
1382 if ((nWinBits & WB_RIGHT_ALIGNED) != 0)
1383 aDraw.setY( 2 * aCenter.Y() - aDraw.Y() );
1385 if (mpData->bTextRTL)
1387 tools::Long nTemp = aDraw.X();
1388 aDraw.setX( aDraw.Y() );
1389 aDraw.setY( nTemp );
1392 ImplDrawTab(rRenderContext, aDraw, nTabStyle);
1396 void Ruler::ImplUpdate( bool bMustCalc )
1398 // clear lines in this place so they aren't considered at recalculation
1399 if (!mbFormat)
1400 Invalidate(InvalidateFlags::NoErase);
1402 // set flags
1403 if (bMustCalc)
1404 mbCalc = true;
1405 mbFormat = true;
1407 // abort if we are dragging as drag-handler will update the ruler after drag is finished
1408 if (mbDrag)
1409 return;
1411 // otherwise trigger update
1412 if (IsReallyVisible() && IsUpdateMode())
1414 Invalidate(InvalidateFlags::NoErase);
1418 bool Ruler::ImplDoHitTest( const Point& rPos, RulerSelection* pHitTest,
1419 bool bRequireStyle, RulerIndentStyle nRequiredStyle,
1420 tools::Long nTolerance ) const
1422 sal_Int32 i;
1423 sal_uInt16 nStyle;
1424 tools::Long nHitBottom;
1425 tools::Long nX;
1426 tools::Long nY;
1427 tools::Long n1;
1429 if ( !mbActive )
1430 return false;
1432 // determine positions
1433 bool bIsHori = 0 != (mnWinStyle & WB_HORZ);
1434 if ( bIsHori )
1436 nX = rPos.X();
1437 nY = rPos.Y();
1439 else
1441 nX = rPos.Y();
1442 nY = rPos.X();
1444 nHitBottom = mnVirHeight + (RULER_OFF * 2);
1446 // #i32608#
1447 pHitTest->nAryPos = 0;
1448 pHitTest->mnDragSize = RulerDragSize::Move;
1449 pHitTest->bSize = false;
1450 pHitTest->bSizeBar = false;
1452 // so that leftover tabs and indents are taken into account
1453 tools::Long nXExtraOff;
1454 if ( !mpData->pTabs.empty() || !mpData->pIndents.empty() )
1455 nXExtraOff = (mnVirHeight / 2) - 4;
1456 else
1457 nXExtraOff = 0;
1459 // test if outside
1460 nX -= mnVirOff;
1461 if ( (nX < mpData->nRulVirOff - nXExtraOff) ||
1462 (nX > mpData->nRulVirOff + mpData->nRulWidth + nXExtraOff) ||
1463 (nY < 0) ||
1464 (nY > nHitBottom) )
1466 pHitTest->nPos = 0;
1467 pHitTest->eType = RulerType::Outside;
1468 return false;
1471 nX -= mpData->nNullVirOff;
1472 pHitTest->nPos = nX;
1473 pHitTest->eType = RulerType::DontKnow;
1475 // first test the tabs
1476 tools::Rectangle aRect;
1477 if ( !mpData->pTabs.empty() )
1479 aRect.SetBottom( nHitBottom );
1480 aRect.SetTop( aRect.Bottom() - ruler_tab.height - RULER_OFF );
1482 for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1484 nStyle = mpData->pTabs[i].nStyle;
1485 if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1487 nStyle &= RULER_TAB_STYLE;
1489 // default tabs are only shown (no action)
1490 if ( nStyle != RULER_TAB_DEFAULT )
1492 n1 = mpData->pTabs[i].nPos;
1494 if ( nStyle == RULER_TAB_LEFT )
1496 aRect.SetLeft( n1 );
1497 aRect.SetRight( n1 + ruler_tab.width - 1 );
1499 else if ( nStyle == RULER_TAB_RIGHT )
1501 aRect.SetRight( n1 );
1502 aRect.SetLeft( n1 - ruler_tab.width - 1 );
1504 else
1506 aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1507 aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1510 if ( aRect.Contains( Point( nX, nY ) ) )
1512 pHitTest->eType = RulerType::Tab;
1513 pHitTest->nAryPos = i;
1514 return true;
1521 // Indents
1522 if ( !mpData->pIndents.empty() )
1524 tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
1525 tools::Long nIndentWidth2 = nIndentHeight - 3;
1527 for ( i = mpData->pIndents.size(); i; i-- )
1529 RulerIndentStyle nIndentStyle = mpData->pIndents[i-1].nStyle;
1530 if ( (! bRequireStyle || nIndentStyle == nRequiredStyle) &&
1531 !mpData->pIndents[i-1].bInvisible )
1533 n1 = mpData->pIndents[i-1].nPos;
1535 if ( (nIndentStyle == RulerIndentStyle::Bottom) != !bIsHori )
1537 aRect.SetLeft( n1-nIndentWidth2 );
1538 aRect.SetRight( n1+nIndentWidth2 );
1539 aRect.SetTop( nHitBottom-nIndentHeight-RULER_OFF+1 );
1540 aRect.SetBottom( nHitBottom );
1542 else
1544 aRect.SetLeft( n1-nIndentWidth2 );
1545 aRect.SetRight( n1+nIndentWidth2 );
1546 aRect.SetTop( 0 );
1547 aRect.SetBottom( nIndentHeight+RULER_OFF-1 );
1550 if ( aRect.Contains( Point( nX, nY ) ) )
1552 pHitTest->eType = RulerType::Indent;
1553 pHitTest->nAryPos = i-1;
1554 return true;
1560 // test the borders
1561 int nBorderTolerance = nTolerance;
1562 if(pHitTest->bExpandTest)
1564 nBorderTolerance++;
1567 for ( i = mpData->pBorders.size(); i; i-- )
1569 n1 = mpData->pBorders[i-1].nPos;
1570 tools::Long n2 = n1 + mpData->pBorders[i-1].nWidth;
1572 // borders have at least 3 pixel padding
1573 if ( !mpData->pBorders[i-1].nWidth )
1575 n1 -= nBorderTolerance;
1576 n2 += nBorderTolerance;
1579 if ( (nX >= n1) && (nX <= n2) )
1581 RulerBorderStyle nBorderStyle = mpData->pBorders[i-1].nStyle;
1582 if ( !(nBorderStyle & RulerBorderStyle::Invisible) )
1584 pHitTest->eType = RulerType::Border;
1585 pHitTest->nAryPos = i-1;
1587 if ( !(nBorderStyle & RulerBorderStyle::Sizeable) )
1589 if ( nBorderStyle & RulerBorderStyle::Moveable )
1591 pHitTest->bSizeBar = true;
1592 pHitTest->mnDragSize = RulerDragSize::Move;
1595 else
1597 tools::Long nMOff = RULER_MOUSE_BORDERWIDTH;
1598 while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) )
1600 if ( nMOff < 2 )
1602 nMOff = 0;
1603 break;
1605 else
1606 nMOff--;
1609 if ( nX <= n1+nMOff )
1611 pHitTest->bSize = true;
1612 pHitTest->mnDragSize = RulerDragSize::N1;
1614 else if ( nX >= n2-nMOff )
1616 pHitTest->bSize = true;
1617 pHitTest->mnDragSize = RulerDragSize::N2;
1619 else
1621 if ( nBorderStyle & RulerBorderStyle::Moveable )
1623 pHitTest->bSizeBar = true;
1624 pHitTest->mnDragSize = RulerDragSize::Move;
1629 return true;
1634 // Margins
1635 int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH;
1637 if ( (mpData->nMargin1Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1639 n1 = mpData->nMargin1;
1640 if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1642 pHitTest->eType = RulerType::Margin1;
1643 pHitTest->bSize = true;
1644 return true;
1647 if ( (mpData->nMargin2Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1649 n1 = mpData->nMargin2;
1650 if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1652 pHitTest->eType = RulerType::Margin2;
1653 pHitTest->bSize = true;
1654 return true;
1658 // test tabs again
1659 if ( !mpData->pTabs.empty() )
1661 aRect.SetTop( RULER_OFF );
1662 aRect.SetBottom( nHitBottom );
1664 for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1666 nStyle = mpData->pTabs[i].nStyle;
1667 if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1669 nStyle &= RULER_TAB_STYLE;
1671 // default tabs are only shown (no action)
1672 if ( nStyle != RULER_TAB_DEFAULT )
1674 n1 = mpData->pTabs[i].nPos;
1676 if ( nStyle == RULER_TAB_LEFT )
1678 aRect.SetLeft( n1 );
1679 aRect.SetRight( n1 + ruler_tab.width - 1 );
1681 else if ( nStyle == RULER_TAB_RIGHT )
1683 aRect.SetRight( n1 );
1684 aRect.SetLeft( n1 - ruler_tab.width - 1 );
1686 else
1688 aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1689 aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1692 aRect.AdjustLeft( -1 );
1693 aRect.AdjustRight( 1 );
1695 if ( aRect.Contains( Point( nX, nY ) ) )
1697 pHitTest->eType = RulerType::Tab;
1698 pHitTest->nAryPos = i;
1699 return true;
1706 return false;
1709 bool Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType,
1710 RulerSelection* pHitTest, tools::Long nTolerance ) const
1712 Point aPos = rPos;
1713 bool bRequiredStyle = false;
1714 RulerIndentStyle nRequiredStyle = RulerIndentStyle::Top;
1716 if (eDragType == RulerType::Indent)
1718 bRequiredStyle = true;
1719 nRequiredStyle = RulerIndentStyle::Bottom;
1722 if ( mnWinStyle & WB_HORZ )
1723 aPos.AdjustX(mnWinOff );
1724 else
1725 aPos.AdjustY(mnWinOff );
1727 if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::DontKnow) )
1729 if ( mnWinStyle & WB_HORZ )
1730 aPos.setY( RULER_OFF + 1 );
1731 else
1732 aPos.setX( RULER_OFF + 1 );
1734 if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle, nTolerance ) )
1736 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1737 return true;
1741 if ( (eDragType == RulerType::Indent) ||
1742 (eDragType == RulerType::Tab) ||
1743 (eDragType == RulerType::DontKnow) )
1745 if ( mnWinStyle & WB_HORZ )
1746 aPos.setY( mnHeight - RULER_OFF - 1 );
1747 else
1748 aPos.setX( mnWidth - RULER_OFF - 1 );
1750 if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle, nTolerance ) )
1752 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1753 return true;
1757 if ( (eDragType == RulerType::Margin1) || (eDragType == RulerType::Margin2) ||
1758 (eDragType == RulerType::Border) || (eDragType == RulerType::DontKnow) )
1760 if ( mnWinStyle & WB_HORZ )
1761 aPos.setY( RULER_OFF + (mnVirHeight / 2) );
1762 else
1763 aPos.setX( RULER_OFF + (mnVirHeight / 2) );
1765 if ( ImplDoHitTest( aPos, pHitTest, false, RulerIndentStyle::Top, nTolerance ) )
1767 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1768 return true;
1772 pHitTest->eType = RulerType::DontKnow;
1774 return false;
1777 bool Ruler::ImplStartDrag( RulerSelection const * pHitTest, sal_uInt16 nModifier )
1779 // don't trigger drag if a border that was clicked can not be changed
1780 if ( (pHitTest->eType == RulerType::Border) &&
1781 !pHitTest->bSize && !pHitTest->bSizeBar )
1782 return false;
1784 // Set drag data
1785 meDragType = pHitTest->eType;
1786 mnDragPos = pHitTest->nPos;
1787 mnDragAryPos = pHitTest->nAryPos;
1788 mnDragSize = pHitTest->mnDragSize;
1789 mnDragModifier = nModifier;
1790 *mpDragData = *mpSaveData;
1791 mpData = mpDragData.get();
1793 // call handler
1794 if (StartDrag())
1796 // if the handler allows dragging, initialize dragging
1797 mbDrag = true;
1798 mnStartDragPos = mnDragPos;
1799 StartTracking();
1800 Invalidate(InvalidateFlags::NoErase);
1801 return true;
1803 else
1805 // otherwise reset the data
1806 meDragType = RulerType::DontKnow;
1807 mnDragPos = 0;
1808 mnDragAryPos = 0;
1809 mnDragSize = RulerDragSize::Move;
1810 mnDragModifier = 0;
1811 mpData = mpSaveData.get();
1814 return false;
1817 void Ruler::ImplDrag( const Point& rPos )
1819 tools::Long nX;
1820 tools::Long nY;
1821 tools::Long nOutHeight;
1823 if ( mnWinStyle & WB_HORZ )
1825 nX = rPos.X();
1826 nY = rPos.Y();
1827 nOutHeight = mnHeight;
1829 else
1831 nX = rPos.Y();
1832 nY = rPos.X();
1833 nOutHeight = mnWidth;
1836 // calculate and fit X
1837 nX -= mnVirOff;
1838 if ( nX < mpData->nRulVirOff )
1840 nX = mpData->nRulVirOff;
1842 else if ( nX > mpData->nRulVirOff+mpData->nRulWidth )
1844 nX = mpData->nRulVirOff+mpData->nRulWidth;
1846 nX -= mpData->nNullVirOff;
1848 // if upper or left from ruler, then consider old values
1849 mbDragDelete = false;
1850 if ( nY < 0 )
1852 if ( !mbDragCanceled )
1854 // reset the data
1855 mbDragCanceled = true;
1856 ImplRulerData aTempData = *mpDragData;
1857 *mpDragData = *mpSaveData;
1858 mbCalc = true;
1859 mbFormat = true;
1861 // call handler
1862 mnDragPos = mnStartDragPos;
1863 Drag();
1865 // and redraw
1866 Invalidate(InvalidateFlags::NoErase);
1868 // reset the data as before cancel
1869 *mpDragData = std::move(aTempData);
1872 else
1874 mbDragCanceled = false;
1876 // +2, so the tabs are not cleared too quickly
1877 if ( nY > nOutHeight + 2 )
1878 mbDragDelete = true;
1880 mnDragPos = nX;
1882 // call handler
1883 Drag();
1885 // redraw
1886 if (mbFormat)
1887 Invalidate(InvalidateFlags::NoErase);
1891 void Ruler::ImplEndDrag()
1893 // get values
1894 if ( mbDragCanceled )
1895 *mpDragData = *mpSaveData;
1896 else
1897 *mpSaveData = *mpDragData;
1899 mpData = mpSaveData.get();
1900 mbDrag = false;
1902 // call handler
1903 EndDrag();
1905 // reset drag values
1906 meDragType = RulerType::DontKnow;
1907 mnDragPos = 0;
1908 mnDragAryPos = 0;
1909 mnDragSize = RulerDragSize::Move;
1910 mbDragCanceled = false;
1911 mbDragDelete = false;
1912 mnDragModifier = 0;
1913 mnStartDragPos = 0;
1915 // redraw
1916 Invalidate(InvalidateFlags::NoErase);
1919 void Ruler::MouseButtonDown( const MouseEvent& rMEvt )
1921 if ( !rMEvt.IsLeft() || IsTracking() )
1922 return;
1924 Point aMousePos = rMEvt.GetPosPixel();
1925 sal_uInt16 nMouseClicks = rMEvt.GetClicks();
1926 sal_uInt16 nMouseModifier = rMEvt.GetModifier();
1928 // update ruler
1929 if ( mbFormat )
1931 Invalidate(InvalidateFlags::NoErase);
1934 if ( maExtraRect.Contains( aMousePos ) )
1936 ExtraDown();
1938 else
1940 RulerSelection aHitTest;
1941 bool bHitTestResult = ImplDoHitTest(aMousePos, &aHitTest);
1943 if ( nMouseClicks == 1 )
1945 if ( bHitTestResult )
1947 ImplStartDrag( &aHitTest, nMouseModifier );
1949 else
1951 // calculate position inside of ruler area
1952 if ( aHitTest.eType == RulerType::DontKnow )
1954 mnDragPos = aHitTest.nPos;
1955 Click();
1956 mnDragPos = 0;
1958 // call HitTest again as a click, for example, could set a new tab
1959 if ( ImplDoHitTest(aMousePos, &aHitTest) )
1960 ImplStartDrag(&aHitTest, nMouseModifier);
1964 else
1966 if (bHitTestResult)
1968 mnDragPos = aHitTest.nPos;
1969 mnDragAryPos = aHitTest.nAryPos;
1971 meDragType = aHitTest.eType;
1973 DoubleClick();
1975 meDragType = RulerType::DontKnow;
1976 mnDragPos = 0;
1977 mnDragAryPos = 0;
1982 void Ruler::MouseMove( const MouseEvent& rMEvt )
1984 PointerStyle ePtrStyle = PointerStyle::Arrow;
1986 mxPreviousHitTest.swap(mxCurrentHitTest);
1988 mxCurrentHitTest.reset(new RulerSelection);
1990 maHoverSelection.eType = RulerType::DontKnow;
1992 if (ImplDoHitTest( rMEvt.GetPosPixel(), mxCurrentHitTest.get() ))
1994 maHoverSelection = *mxCurrentHitTest;
1996 if (mxCurrentHitTest->bSize)
1998 if (mnWinStyle & WB_HORZ)
2000 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
2001 ePtrStyle = PointerStyle::TabSelectW;
2002 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2003 ePtrStyle = PointerStyle::TabSelectE;
2004 else
2005 ePtrStyle = PointerStyle::ESize;
2007 else
2009 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
2010 ePtrStyle = PointerStyle::WindowNSize;
2011 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2012 ePtrStyle = PointerStyle::WindowSSize;
2013 else
2014 ePtrStyle = PointerStyle::SSize;
2017 else if (mxCurrentHitTest->bSizeBar)
2019 if (mnWinStyle & WB_HORZ)
2020 ePtrStyle = PointerStyle::HSizeBar;
2021 else
2022 ePtrStyle = PointerStyle::VSizeBar;
2026 if (mxPreviousHitTest != nullptr && mxPreviousHitTest->eType != mxCurrentHitTest->eType)
2028 mbFormat = true;
2031 SetPointer( ePtrStyle );
2033 if (mbFormat)
2035 Invalidate(InvalidateFlags::NoErase);
2039 void Ruler::Tracking( const TrackingEvent& rTEvt )
2041 if ( rTEvt.IsTrackingEnded() )
2043 // reset the old state at cancel
2044 if ( rTEvt.IsTrackingCanceled() )
2046 mbDragCanceled = true;
2047 mbFormat = true;
2050 ImplEndDrag();
2052 else
2053 ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() );
2056 void Ruler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2058 ImplDraw(rRenderContext);
2060 // consider extra field
2061 if (mnWinStyle & WB_EXTRAFIELD)
2062 ImplDrawExtra(rRenderContext);
2065 void Ruler::Resize()
2067 Size aWinSize = GetOutputSizePixel();
2069 tools::Long nNewHeight;
2070 if ( mnWinStyle & WB_HORZ )
2072 if ( aWinSize.Height() != mnHeight )
2073 nNewHeight = aWinSize.Height();
2074 else
2075 nNewHeight = 0;
2077 else
2079 if ( aWinSize.Width() != mnWidth )
2080 nNewHeight = aWinSize.Width();
2081 else
2082 nNewHeight = 0;
2085 mbFormat = true;
2087 // clear lines
2088 bool bVisible = IsReallyVisible();
2089 if ( bVisible && !mpData->pLines.empty() )
2091 mnUpdateFlags |= RULER_UPDATE_LINES;
2092 Invalidate(InvalidateFlags::NoErase);
2095 // recalculate some values if the height/width changes
2096 // extra field should always be updated
2097 ImplInitExtraField( mpData->bTextRTL );
2098 if ( nNewHeight )
2100 mbCalc = true;
2101 mnVirHeight = nNewHeight - mnBorderWidth - ( RULER_OFF * 2 );
2103 else
2105 if ( mpData->bAutoPageWidth )
2106 ImplUpdate( true );
2107 else if ( mbAutoWinWidth )
2108 mbCalc = true;
2111 // clear part of the border
2112 if ( bVisible )
2114 if ( nNewHeight )
2115 Invalidate(InvalidateFlags::NoErase);
2116 else if ( mpData->bAutoPageWidth )
2118 // only at AutoPageWidth do we need to redraw
2119 tools::Rectangle aRect;
2121 if ( mnWinStyle & WB_HORZ )
2123 if ( mnWidth < aWinSize.Width() )
2124 aRect.SetLeft( mnWidth - RULER_RESIZE_OFF );
2125 else
2126 aRect.SetLeft( aWinSize.Width() - RULER_RESIZE_OFF );
2127 aRect.SetRight( aRect.Left() + RULER_RESIZE_OFF );
2128 aRect.SetTop( RULER_OFF );
2129 aRect.SetBottom( RULER_OFF + mnVirHeight );
2131 else
2133 if ( mnHeight < aWinSize.Height() )
2134 aRect.SetTop( mnHeight-RULER_RESIZE_OFF );
2135 else
2136 aRect.SetTop( aWinSize.Height()-RULER_RESIZE_OFF );
2137 aRect.SetBottom( aRect.Top() + RULER_RESIZE_OFF );
2138 aRect.SetLeft( RULER_OFF );
2139 aRect.SetRight( RULER_OFF + mnVirHeight );
2142 Invalidate(aRect, InvalidateFlags::NoErase);
2146 mnWidth = aWinSize.Width();
2147 mnHeight = aWinSize.Height();
2150 void Ruler::StateChanged( StateChangedType nType )
2152 Window::StateChanged( nType );
2154 if ( nType == StateChangedType::InitShow )
2155 Invalidate();
2156 else if ( nType == StateChangedType::UpdateMode )
2158 if ( IsReallyVisible() && IsUpdateMode() )
2159 Invalidate();
2161 else if ( (nType == StateChangedType::Zoom) ||
2162 (nType == StateChangedType::ControlFont) )
2164 ImplInitSettings( true, false, false );
2165 Invalidate();
2167 else if ( nType == StateChangedType::ControlForeground )
2169 ImplInitSettings( false, true, false );
2170 Invalidate();
2172 else if ( nType == StateChangedType::ControlBackground )
2174 ImplInitSettings( false, false, true );
2175 Invalidate();
2179 void Ruler::DataChanged( const DataChangedEvent& rDCEvt )
2181 Window::DataChanged( rDCEvt );
2183 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2184 (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
2185 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2186 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2187 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2189 mbFormat = true;
2190 ImplInitSettings( true, true, true );
2191 Invalidate();
2195 bool Ruler::StartDrag()
2197 return false;
2200 void Ruler::Drag()
2204 void Ruler::EndDrag()
2208 void Ruler::Click()
2212 void Ruler::DoubleClick()
2214 maDoubleClickHdl.Call( this );
2217 void Ruler::ExtraDown()
2221 void Ruler::Activate()
2223 mbActive = true;
2225 // update positionlines - draw is delayed
2226 mnUpdateFlags |= RULER_UPDATE_LINES;
2227 Invalidate(InvalidateFlags::NoErase);
2230 void Ruler::Deactivate()
2232 // clear positionlines
2233 Invalidate(InvalidateFlags::NoErase);
2235 mbActive = false;
2238 bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType, tools::Long nTolerance )
2240 if ( !mbDrag )
2242 Point aMousePos = rMEvt.GetPosPixel();
2243 sal_uInt16 nMouseClicks = rMEvt.GetClicks();
2244 sal_uInt16 nMouseModifier = rMEvt.GetModifier();
2245 RulerSelection aHitTest;
2247 if(eDragType != RulerType::DontKnow)
2248 aHitTest.bExpandTest = true;
2250 // update ruler
2251 if ( mbFormat )
2253 if (!IsReallyVisible())
2255 // set mpData for ImplDocHitTest()
2256 ImplFormat(*GetOutDev());
2259 Invalidate(InvalidateFlags::NoErase);
2262 if ( nMouseClicks == 1 )
2264 if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest, nTolerance ) )
2266 PointerStyle aPtr = PointerStyle::Arrow;
2268 if ( aHitTest.bSize )
2270 if ( mnWinStyle & WB_HORZ )
2271 aPtr = PointerStyle::ESize;
2272 else
2273 aPtr = PointerStyle::SSize;
2275 else if ( aHitTest.bSizeBar )
2277 if ( mnWinStyle & WB_HORZ )
2278 aPtr = PointerStyle::HSizeBar;
2279 else
2280 aPtr = PointerStyle::VSizeBar;
2282 SetPointer( aPtr );
2283 return ImplStartDrag( &aHitTest, nMouseModifier );
2286 else if ( nMouseClicks == 2 )
2288 if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest, nTolerance ) )
2290 mnDragPos = aHitTest.nPos;
2291 mnDragAryPos = aHitTest.nAryPos;
2294 DoubleClick();
2296 mnDragPos = 0;
2297 mnDragAryPos = 0;
2299 return true;
2303 return false;
2306 void Ruler::CancelDrag()
2308 if ( mbDrag )
2310 ImplDrag( Point( -1, -1 ) );
2311 ImplEndDrag();
2315 RulerType Ruler::GetRulerType( const Point& rPos, sal_uInt16* pAryPos )
2317 RulerSelection aHitTest;
2319 // update ruler
2320 if ( IsReallyVisible() && mbFormat )
2322 Invalidate(InvalidateFlags::NoErase);
2325 (void)ImplDoHitTest(rPos, &aHitTest);
2327 // return values
2328 if ( pAryPos )
2329 *pAryPos = aHitTest.nAryPos;
2330 return aHitTest.eType;
2333 void Ruler::SetWinPos( tools::Long nNewOff, tools::Long nNewWidth )
2335 // should widths be automatically calculated
2336 if ( !nNewWidth )
2337 mbAutoWinWidth = true;
2338 else
2339 mbAutoWinWidth = false;
2341 mnWinOff = nNewOff;
2342 mnWinWidth = nNewWidth;
2343 ImplUpdate( true );
2346 void Ruler::SetPagePos( tools::Long nNewOff, tools::Long nNewWidth )
2348 // should we do anything?
2349 if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) )
2350 return;
2352 // should widths be automatically calculated
2353 if ( !nNewWidth )
2354 mpData->bAutoPageWidth = true;
2355 else
2356 mpData->bAutoPageWidth = false;
2358 mpData->nPageOff = nNewOff;
2359 mpData->nPageWidth = nNewWidth;
2360 ImplUpdate( true );
2363 void Ruler::SetBorderPos( tools::Long nOff )
2365 if ( mnWinStyle & WB_BORDER )
2367 if ( mnBorderOff != nOff )
2369 mnBorderOff = nOff;
2371 if ( IsReallyVisible() && IsUpdateMode() )
2372 Invalidate(InvalidateFlags::NoErase);
2377 void Ruler::SetUnit( FieldUnit eNewUnit )
2379 if ( meUnit == eNewUnit )
2380 return;
2382 meUnit = eNewUnit;
2383 switch ( meUnit )
2385 case FieldUnit::MM:
2386 mnUnitIndex = RULER_UNIT_MM;
2387 break;
2388 case FieldUnit::CM:
2389 mnUnitIndex = RULER_UNIT_CM;
2390 break;
2391 case FieldUnit::M:
2392 mnUnitIndex = RULER_UNIT_M;
2393 break;
2394 case FieldUnit::KM:
2395 mnUnitIndex = RULER_UNIT_KM;
2396 break;
2397 case FieldUnit::INCH:
2398 mnUnitIndex = RULER_UNIT_INCH;
2399 break;
2400 case FieldUnit::FOOT:
2401 mnUnitIndex = RULER_UNIT_FOOT;
2402 break;
2403 case FieldUnit::MILE:
2404 mnUnitIndex = RULER_UNIT_MILE;
2405 break;
2406 case FieldUnit::POINT:
2407 mnUnitIndex = RULER_UNIT_POINT;
2408 break;
2409 case FieldUnit::PICA:
2410 mnUnitIndex = RULER_UNIT_PICA;
2411 break;
2412 case FieldUnit::CHAR:
2413 mnUnitIndex = RULER_UNIT_CHAR;
2414 break;
2415 case FieldUnit::LINE:
2416 mnUnitIndex = RULER_UNIT_LINE;
2417 break;
2418 default:
2419 SAL_WARN( "svtools.control", "Ruler::SetUnit() - Wrong Unit" );
2420 break;
2423 maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit );
2424 ImplUpdate();
2427 void Ruler::SetZoom( const Fraction& rNewZoom )
2429 DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" );
2431 if ( maZoom != rNewZoom )
2433 maZoom = rNewZoom;
2434 maMapMode.SetScaleX( maZoom );
2435 maMapMode.SetScaleY( maZoom );
2436 ImplUpdate();
2440 void Ruler::SetExtraType( RulerExtra eNewExtraType, sal_uInt16 nStyle )
2442 if ( mnWinStyle & WB_EXTRAFIELD )
2444 meExtraType = eNewExtraType;
2445 mnExtraStyle = nStyle;
2446 if (IsReallyVisible() && IsUpdateMode())
2447 Invalidate();
2451 void Ruler::SetNullOffset( tools::Long nPos )
2453 if ( mpData->nNullOff != nPos )
2455 mpData->nNullVirOff += nPos - mpData->nNullOff;
2456 mpData->nNullOff = nPos;
2457 ImplUpdate();
2461 void Ruler::SetLeftFrameMargin( tools::Long nPos )
2463 if ( mpData->nLeftFrameMargin != nPos )
2465 mpData->nLeftFrameMargin = nPos;
2466 ImplUpdate();
2470 void Ruler::SetRightFrameMargin( tools::Long nPos )
2472 if ( mpData->nRightFrameMargin != nPos )
2474 mpData->nRightFrameMargin = nPos;
2475 ImplUpdate();
2479 void Ruler::SetMargin1( tools::Long nPos, RulerMarginStyle nMarginStyle )
2481 if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) )
2483 mpData->nMargin1 = nPos;
2484 mpData->nMargin1Style = nMarginStyle;
2485 ImplUpdate();
2489 void Ruler::SetMargin2( tools::Long nPos, RulerMarginStyle nMarginStyle )
2491 DBG_ASSERT( (nPos >= mpData->nMargin1) ||
2492 (mpData->nMargin1Style & RulerMarginStyle::Invisible) ||
2493 (mpData->nMargin2Style & RulerMarginStyle::Invisible),
2494 "Ruler::SetMargin2() - Margin2 < Margin1" );
2496 if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) )
2498 mpData->nMargin2 = nPos;
2499 mpData->nMargin2Style = nMarginStyle;
2500 ImplUpdate();
2504 void Ruler::SetLines( sal_uInt32 aLineArraySize, const RulerLine* pLineArray )
2506 // To determine if what has changed
2507 if ( mpData->pLines.size() == aLineArraySize )
2509 sal_uInt32 i = aLineArraySize;
2510 std::vector<RulerLine>::const_iterator aItr1 = mpData->pLines.begin();
2511 const RulerLine* pAry2 = pLineArray;
2512 while ( i )
2514 if ( aItr1->nPos != pAry2->nPos )
2515 break;
2516 ++aItr1;
2517 ++pAry2;
2518 i--;
2520 if ( !i )
2521 return;
2524 // New values and new share issue
2525 bool bMustUpdate;
2526 bMustUpdate = IsReallyVisible() && IsUpdateMode();
2528 // Delete old lines
2529 if ( bMustUpdate )
2530 Invalidate(InvalidateFlags::NoErase);
2532 // New data set
2533 if ( !aLineArraySize || !pLineArray )
2535 if ( mpData->pLines.empty() )
2536 return;
2537 mpData->pLines.clear();
2539 else
2541 if ( mpData->pLines.size() != aLineArraySize )
2543 mpData->pLines.resize(aLineArraySize);
2546 std::copy( pLineArray,
2547 pLineArray + aLineArraySize,
2548 mpData->pLines.begin() );
2550 if ( bMustUpdate )
2551 Invalidate(InvalidateFlags::NoErase);
2555 void Ruler::SetBorders( sal_uInt32 aBorderArraySize, const RulerBorder* pBorderArray )
2557 if ( !aBorderArraySize || !pBorderArray )
2559 if ( mpData->pBorders.empty() )
2560 return;
2561 mpData->pBorders.clear();
2563 else
2565 if ( mpData->pBorders.size() != aBorderArraySize )
2567 mpData->pBorders.resize(aBorderArraySize);
2569 else
2571 sal_uInt32 i = aBorderArraySize;
2572 const RulerBorder* pAry1 = mpData->pBorders.data();
2573 const RulerBorder* pAry2 = pBorderArray;
2574 while ( i )
2576 if ( (pAry1->nPos != pAry2->nPos) ||
2577 (pAry1->nWidth != pAry2->nWidth) ||
2578 (pAry1->nStyle != pAry2->nStyle) )
2579 break;
2580 pAry1++;
2581 pAry2++;
2582 i--;
2584 if ( !i )
2585 return;
2587 std::copy( pBorderArray,
2588 pBorderArray + aBorderArraySize,
2589 mpData->pBorders.begin() );
2592 ImplUpdate();
2595 void Ruler::SetIndents( sal_uInt32 aIndentArraySize, const RulerIndent* pIndentArray )
2598 if ( !aIndentArraySize || !pIndentArray )
2600 if ( mpData->pIndents.empty() )
2601 return;
2602 mpData->pIndents.clear();
2604 else
2606 if ( mpData->pIndents.size() != aIndentArraySize )
2608 mpData->pIndents.resize(aIndentArraySize);
2610 else
2612 sal_uInt32 i = aIndentArraySize;
2613 const RulerIndent* pAry1 = mpData->pIndents.data();
2614 const RulerIndent* pAry2 = pIndentArray;
2615 while ( i )
2617 if ( (pAry1->nPos != pAry2->nPos) ||
2618 (pAry1->nStyle != pAry2->nStyle) )
2619 break;
2620 pAry1++;
2621 pAry2++;
2622 i--;
2624 if ( !i )
2625 return;
2628 std::copy( pIndentArray,
2629 pIndentArray + aIndentArraySize,
2630 mpData->pIndents.begin() );
2633 ImplUpdate();
2636 void Ruler::SetTabs( sal_uInt32 aTabArraySize, const RulerTab* pTabArray )
2638 if ( aTabArraySize == 0 || pTabArray == nullptr )
2640 if ( mpData->pTabs.empty() )
2641 return;
2642 mpData->pTabs.clear();
2644 else
2646 if ( mpData->pTabs.size() != aTabArraySize )
2648 mpData->pTabs.resize(aTabArraySize);
2650 else
2652 sal_uInt32 i = aTabArraySize;
2653 std::vector<RulerTab>::iterator aTabIterator = mpData->pTabs.begin();
2654 const RulerTab* pInputArray = pTabArray;
2655 while ( i )
2657 RulerTab& aCurrent = *aTabIterator;
2658 if ( aCurrent.nPos != pInputArray->nPos ||
2659 aCurrent.nStyle != pInputArray->nStyle )
2661 break;
2663 ++aTabIterator;
2664 pInputArray++;
2665 i--;
2667 if ( !i )
2668 return;
2670 std::copy(pTabArray, pTabArray + aTabArraySize, mpData->pTabs.begin());
2673 ImplUpdate();
2676 const std::vector<RulerTab>& Ruler::GetTabs() const
2678 return mpData->pTabs;
2681 void Ruler::SetStyle( WinBits nStyle )
2683 if ( mnWinStyle != nStyle )
2685 mnWinStyle = nStyle;
2686 ImplInitExtraField( true );
2690 void Ruler::DrawTab(vcl::RenderContext& rRenderContext, const Color &rFillColor, const Point& rPos, sal_uInt16 nStyle)
2692 Point aPos(rPos);
2693 sal_uInt16 nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL);
2695 rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
2696 rRenderContext.SetLineColor();
2697 rRenderContext.SetFillColor(rFillColor);
2698 ImplCenterTabPos(aPos, nTabStyle);
2699 ImplDrawRulerTab(rRenderContext, aPos, nTabStyle, nStyle);
2700 rRenderContext.Pop();
2703 void Ruler::SetTextRTL(bool bRTL)
2705 if(mpData->bTextRTL != bRTL)
2707 mpData->bTextRTL = bRTL;
2708 if ( IsReallyVisible() && IsUpdateMode() )
2709 ImplInitExtraField( true );
2714 tools::Long Ruler::GetPageOffset() const
2716 return mpData->nPageOff;
2719 tools::Long Ruler::GetNullOffset() const
2721 return mpData->nNullOff;
2724 tools::Long Ruler::GetMargin1() const
2726 return mpData->nMargin1;
2729 tools::Long Ruler::GetMargin2() const
2731 return mpData->nMargin2;
2734 const RulerUnitData& Ruler::GetCurrentRulerUnit() const
2736 return aImplRulerUnitTab[mnUnitIndex];
2739 void Ruler::DrawTicks()
2741 mbFormat = true;
2742 Invalidate(InvalidateFlags::NoErase);
2745 uno::Reference< XAccessible > Ruler::CreateAccessible()
2747 vcl::Window* pParent = GetAccessibleParentWindow();
2748 OSL_ENSURE( pParent, "-SvxRuler::CreateAccessible(): No Parent!" );
2749 uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
2750 if( xAccParent.is() )
2752 // MT: Fixed compiler issue because the address from a temporary object was used.
2753 // BUT: Should it really be a Pointer, instead of const&???
2754 OUString aStr;
2755 if ( mnWinStyle & WB_HORZ )
2757 aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME);
2759 else
2761 aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME);
2763 mxAccContext = new SvtRulerAccessible( xAccParent, *this, aStr );
2764 SetAccessible(mxAccContext);
2765 return mxAccContext;
2767 else
2768 return uno::Reference< XAccessible >();
2771 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */