nss: upgrade to release 3.73
[LibreOffice.git] / svtools / source / control / ruler.cxx
blob09c442bee0208e12079a4501f45d4afdb5572908
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 std;
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::accessibility;
44 #define RULER_OFF 3
45 #define RULER_RESIZE_OFF 4
46 #define RULER_MIN_SIZE 3
48 #define RULER_VAR_SIZE 8
50 #define RULER_UPDATE_LINES 0x01
52 #define RULER_CLIP 150
54 #define RULER_UNIT_MM 0
55 #define RULER_UNIT_CM 1
56 #define RULER_UNIT_M 2
57 #define RULER_UNIT_KM 3
58 #define RULER_UNIT_INCH 4
59 #define RULER_UNIT_FOOT 5
60 #define RULER_UNIT_MILE 6
61 #define RULER_UNIT_POINT 7
62 #define RULER_UNIT_PICA 8
63 #define RULER_UNIT_CHAR 9
64 #define RULER_UNIT_LINE 10
65 #define RULER_UNIT_COUNT 11
67 namespace
69 /**
70 * Pre-calculates glyph items for rText on rRenderContext. Subsequent calls
71 * avoid the calculation and just return a pointer to rTextGlyphs.
73 SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext, const OUString& rText,
74 SalLayoutGlyphs& rTextGlyphs)
76 if (rTextGlyphs.IsValid())
77 // Use pre-calculated result.
78 return &rTextGlyphs;
80 // Calculate glyph items.
82 std::unique_ptr<SalLayout> pLayout = rRenderContext.ImplLayout(
83 rText, 0, rText.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly);
84 if (!pLayout)
85 return nullptr;
87 const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs();
88 if (!pGlyphs)
89 return nullptr;
91 // Remember the calculation result.
92 rTextGlyphs = *pGlyphs;
94 return &rTextGlyphs;
98 class ImplRulerData
100 friend class Ruler;
102 private:
103 vector<RulerLine> pLines;
104 vector<RulerBorder> pBorders;
105 vector<RulerIndent> pIndents;
106 vector<RulerTab> pTabs;
108 tools::Long nNullVirOff;
109 tools::Long nRulVirOff;
110 tools::Long nRulWidth;
111 tools::Long nPageOff;
112 tools::Long nPageWidth;
113 tools::Long nNullOff;
114 tools::Long nMargin1;
115 tools::Long nMargin2;
116 // In this context, "frame margin" means paragraph margins (indents)
117 tools::Long nLeftFrameMargin;
118 tools::Long nRightFrameMargin;
119 RulerMarginStyle nMargin1Style;
120 RulerMarginStyle nMargin2Style;
121 bool bAutoPageWidth;
122 bool bTextRTL;
124 public:
125 ImplRulerData();
128 ImplRulerData::ImplRulerData() :
129 nNullVirOff (0),
130 nRulVirOff (0),
131 nRulWidth (0),
132 nPageOff (0),
133 nPageWidth (0),
134 nNullOff (0),
135 nMargin1 (0),
136 nMargin2 (0),
137 nLeftFrameMargin (0),
138 nRightFrameMargin (0),
139 nMargin1Style (RulerMarginStyle::NONE),
140 nMargin2Style (RulerMarginStyle::NONE),
141 bAutoPageWidth (true), // Page width == EditWin width
142 bTextRTL (false)
146 const RulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] =
148 { MapUnit::Map100thMM, 100, 25.0, 25.0, 50.0, 100.0, " mm" }, // MM
149 { MapUnit::Map100thMM, 1000, 100.0, 500.0, 1000.0, 1000.0, " cm" }, // CM
150 { MapUnit::MapMM, 1000, 10.0, 250.0, 500.0, 1000.0, " m" }, // M
151 { MapUnit::MapCM, 100000, 12500.0, 25000.0, 50000.0, 100000.0, " km" }, // KM
152 { MapUnit::Map1000thInch, 1000, 62.5, 125.0, 500.0, 1000.0, "\"" }, // INCH
153 { MapUnit::Map100thInch, 1200, 120.0, 120.0, 600.0, 1200.0, "'" }, // FOOT
154 { MapUnit::Map10thInch, 633600, 63360.0, 63360.0, 316800.0, 633600.0, " miles" }, // MILE
155 { MapUnit::MapPoint, 1, 12.0, 12.0, 12.0, 36.0, " pt" }, // POINT
156 { MapUnit::Map100thMM, 423, 423.0, 423.0, 423.0, 846.0, " pc" }, // PICA
157 { MapUnit::Map100thMM, 371, 371.0, 371.0, 371.0, 743.0, " ch" }, // CHAR
158 { MapUnit::Map100thMM, 551, 551.0, 551.0, 551.0, 1102.0, " li" } // LINE
161 static RulerTabData ruler_tab =
163 0, // DPIScaleFactor to be set
164 7, // ruler_tab_width
165 6, // ruler_tab_height
166 2, // ruler_tab_height2
167 2, // ruler_tab_width2
168 8, // ruler_tab_cwidth
169 4, // ruler_tab_cwidth2
170 4, // ruler_tab_cwidth3
171 2, // ruler_tab_cwidth4
172 4, // ruler_tab_dheight
173 1, // ruler_tab_dheight2
174 5, // ruler_tab_dwidth
175 3, // ruler_tab_dwidth2
176 3, // ruler_tab_dwidth3
177 1, // ruler_tab_dwidth4
178 5 // ruler_tab_textoff
181 void Ruler::ImplInit( WinBits nWinBits )
183 // Set default WinBits
184 if ( !(nWinBits & WB_VERT) )
186 nWinBits |= WB_HORZ;
188 // RTL: no UI mirroring for horizontal rulers, because
189 // the document is also not mirrored
190 EnableRTL( false );
193 // Initialize variables
194 mnWinStyle = nWinBits; // Window-Style
195 mnBorderOff = 0; // Border-Offset
196 mnWinOff = 0; // EditWinOffset
197 mnWinWidth = 0; // EditWinWidth
198 mnWidth = 0; // Window width
199 mnHeight = 0; // Window height
200 mnVirOff = 0; // Offset of VirtualDevice from top-left corner
201 mnVirWidth = 0; // width or height from VirtualDevice
202 mnVirHeight = 0; // height of width from VirtualDevice
203 mnDragPos = 0; // Drag-Position (Null point)
204 mnDragAryPos = 0; // Drag-Array-Index
205 mnDragSize = RulerDragSize::Move; // Did size change at dragging
206 mnDragModifier = 0; // Modifier key at dragging
207 mnExtraStyle = 0; // Style of Extra field
208 mnCharWidth = 371;
209 mnLineHeight = 551;
210 mbCalc = true; // Should recalculate page width
211 mbFormat = true; // Should redraw
212 mbDrag = false; // Currently at dragging
213 mbDragDelete = false; // Has mouse left the dragging area
214 mbDragCanceled = false; // Dragging cancelled?
215 mbAutoWinWidth = true; // EditWinWidth == RulerWidth
216 mbActive = true; // Is ruler active
217 mnUpdateFlags = 0; // What needs to be updated
218 mpData = mpSaveData.get(); // Pointer to normal data
219 meExtraType = RulerExtra::DontKnow; // What is in extra field
220 meDragType = RulerType::DontKnow; // Which element is dragged
222 // Initialize Units
223 mnUnitIndex = RULER_UNIT_CM;
224 meUnit = FieldUnit::CM;
225 maZoom = Fraction( 1, 1 );
227 // Recalculate border widths
228 if ( nWinBits & WB_BORDER )
229 mnBorderWidth = 1;
230 else
231 mnBorderWidth = 0;
233 // Settings
234 ImplInitSettings( true, true, true );
236 // Setup the default size
237 tools::Rectangle aRect;
238 GetTextBoundRect( aRect, "0123456789" );
239 tools::Long nDefHeight = aRect.GetHeight() + RULER_OFF * 2 + ruler_tab.textoff * 2 + mnBorderWidth;
241 Size aDefSize;
242 if ( nWinBits & WB_HORZ )
243 aDefSize.setHeight( nDefHeight );
244 else
245 aDefSize.setWidth( nDefHeight );
246 SetOutputSizePixel( aDefSize );
247 SetType(WindowType::RULER);
250 Ruler::Ruler( vcl::Window* pParent, WinBits nWinStyle ) :
251 Window( pParent, nWinStyle & WB_3DLOOK ),
252 maVirDev( VclPtr<VirtualDevice>::Create(*this) ),
253 maMapMode( MapUnit::Map100thMM ),
254 mpSaveData(new ImplRulerData),
255 mpData(nullptr),
256 mpDragData(new ImplRulerData)
258 // Check to see if the ruler constructor has
259 // already been called before otherwise
260 // we end up with over-scaled elements
261 if (ruler_tab.DPIScaleFactor == 0)
263 ruler_tab.DPIScaleFactor = GetDPIScaleFactor();
264 ruler_tab.width *= ruler_tab.DPIScaleFactor;
265 ruler_tab.height *= ruler_tab.DPIScaleFactor;
266 ruler_tab.height2 *= ruler_tab.DPIScaleFactor;
267 ruler_tab.width2 *= ruler_tab.DPIScaleFactor;
268 ruler_tab.cwidth *= ruler_tab.DPIScaleFactor;
269 ruler_tab.cwidth2 *= ruler_tab.DPIScaleFactor;
270 ruler_tab.cwidth3 *= ruler_tab.DPIScaleFactor;
271 ruler_tab.cwidth4 *= ruler_tab.DPIScaleFactor;
272 ruler_tab.dheight *= ruler_tab.DPIScaleFactor;
273 ruler_tab.dheight2 *= ruler_tab.DPIScaleFactor;
274 ruler_tab.dwidth *= ruler_tab.DPIScaleFactor;
275 ruler_tab.dwidth2 *= ruler_tab.DPIScaleFactor;
276 ruler_tab.dwidth3 *= ruler_tab.DPIScaleFactor;
277 ruler_tab.dwidth4 *= ruler_tab.DPIScaleFactor;
278 ruler_tab.textoff *= ruler_tab.DPIScaleFactor;
282 ImplInit( nWinStyle );
285 Ruler::~Ruler()
287 disposeOnce();
290 void Ruler::dispose()
292 mpSaveData.reset();
293 mpDragData.reset();
294 mxAccContext.clear();
295 Window::dispose();
298 void Ruler::ImplVDrawLine(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
300 if ( nX1 < -RULER_CLIP )
302 nX1 = -RULER_CLIP;
303 if ( nX2 < -RULER_CLIP )
304 return;
306 tools::Long nClip = mnVirWidth + RULER_CLIP;
307 if ( nX2 > nClip )
309 nX2 = nClip;
310 if ( nX1 > nClip )
311 return;
314 if ( mnWinStyle & WB_HORZ )
315 rRenderContext.DrawLine( Point( nX1, nY1 ), Point( nX2, nY2 ) );
316 else
317 rRenderContext.DrawLine( Point( nY1, nX1 ), Point( nY2, nX2 ) );
320 void Ruler::ImplVDrawRect(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
322 if ( nX1 < -RULER_CLIP )
324 nX1 = -RULER_CLIP;
325 if ( nX2 < -RULER_CLIP )
326 return;
328 tools::Long nClip = mnVirWidth + RULER_CLIP;
329 if ( nX2 > nClip )
331 nX2 = nClip;
332 if ( nX1 > nClip )
333 return;
336 if ( mnWinStyle & WB_HORZ )
337 rRenderContext.DrawRect(tools::Rectangle(nX1, nY1, nX2, nY2));
338 else
339 rRenderContext.DrawRect(tools::Rectangle(nY1, nX1, nY2, nX2));
342 void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, tools::Long nY, const OUString& rText, tools::Long nMin, tools::Long nMax)
344 tools::Rectangle aRect;
345 SalLayoutGlyphs* pTextLayout
346 = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]);
347 rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, nullptr, pTextLayout);
349 tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left();
350 tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top();
352 if ( (nX > -RULER_CLIP) && (nX < mnVirWidth + RULER_CLIP) && ( nX < nMax - nShiftX ) && ( nX > nMin + nShiftX ) )
354 if ( mnWinStyle & WB_HORZ )
355 rRenderContext.DrawText(Point(nX - nShiftX, nY - nShiftY), rText, 0, -1, nullptr,
356 nullptr, pTextLayout);
357 else
358 rRenderContext.DrawText(Point(nY - nShiftX, nX - nShiftY), rText, 0, -1, nullptr,
359 nullptr, pTextLayout);
363 void Ruler::ImplInvertLines(vcl::RenderContext& rRenderContext)
365 // Position lines
366 if (mpData->pLines.empty() || !mbActive || mbDrag || mbFormat || (mnUpdateFlags & RULER_UPDATE_LINES) )
367 return;
369 tools::Long nNullWinOff = mpData->nNullVirOff + mnVirOff;
370 tools::Long nRulX1 = mpData->nRulVirOff + mnVirOff;
371 tools::Long nRulX2 = nRulX1 + mpData->nRulWidth;
372 tools::Long nY = (RULER_OFF * 2) + mnVirHeight - 1;
374 // Calculate rectangle
375 tools::Rectangle aRect;
376 if (mnWinStyle & WB_HORZ)
377 aRect.SetBottom( nY );
378 else
379 aRect.SetRight( nY );
381 // Draw lines
382 for (const RulerLine & rLine : mpData->pLines)
384 const tools::Long n = rLine.nPos + nNullWinOff;
385 if ((n >= nRulX1) && (n < nRulX2))
387 if (mnWinStyle & WB_HORZ )
389 aRect.SetLeft( n );
390 aRect.SetRight( n );
392 else
394 aRect.SetTop( n );
395 aRect.SetBottom( n );
397 tools::Rectangle aTempRect = aRect;
399 if (mnWinStyle & WB_HORZ)
400 aTempRect.SetBottom( RULER_OFF - 1 );
401 else
402 aTempRect.SetRight( RULER_OFF - 1 );
404 rRenderContext.Erase(aTempRect);
406 if (mnWinStyle & WB_HORZ)
408 aTempRect.SetBottom( aRect.Bottom() );
409 aTempRect.SetTop( aTempRect.Bottom() - RULER_OFF + 1 );
411 else
413 aTempRect.SetRight( aRect.Right() );
414 aTempRect.SetLeft( aTempRect.Right() - RULER_OFF + 1 );
416 rRenderContext.Erase(aTempRect);
417 Invert(aRect);
420 mnUpdateFlags = 0;
423 void Ruler::ImplDrawTicks(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nStart, tools::Long nTop, tools::Long nBottom)
425 double nCenter = nTop + ((nBottom - nTop) / 2);
427 tools::Long nTickLength3 = (nBottom - nTop) * 0.5;
428 tools::Long nTickLength2 = nTickLength3 * 0.66;
429 tools::Long nTickLength1 = nTickLength2 * 0.66;
431 tools::Long nScale = ruler_tab.DPIScaleFactor;
432 tools::Long DPIOffset = nScale - 1;
434 double nTick4 = aImplRulerUnitTab[mnUnitIndex].nTick4;
435 double nTick2 = 0;
436 double nTickCount = aImplRulerUnitTab[mnUnitIndex].nTick1 / nScale;
437 double nTickUnit = 0;
438 tools::Long nTickWidth;
439 bool bNoTicks = false;
441 Size aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
443 if (mnUnitIndex == RULER_UNIT_CHAR)
445 if (mnCharWidth == 0)
446 mnCharWidth = 371;
447 nTick4 = mnCharWidth * 2;
448 nTick2 = mnCharWidth;
449 nTickCount = mnCharWidth;
450 nTickUnit = mnCharWidth;
452 else if (mnUnitIndex == RULER_UNIT_LINE)
454 if (mnLineHeight == 0)
455 mnLineHeight = 551;
456 nTick4 = mnLineHeight * 2;
457 nTick2 = mnLineHeight;
458 nTickUnit = mnLineHeight;
459 nTickCount = mnLineHeight;
462 if (mnWinStyle & WB_HORZ)
464 nTickWidth = aPixSize.Width();
466 else
468 vcl::Font aFont = rRenderContext.GetFont();
469 if (mnWinStyle & WB_RIGHT_ALIGNED)
470 aFont.SetOrientation(Degree10(2700));
471 else
472 aFont.SetOrientation(Degree10(900));
473 rRenderContext.SetFont(aFont);
474 nTickWidth = aPixSize.Height();
477 tools::Long nMaxWidth = rRenderContext.PixelToLogic(Size(mpData->nPageWidth, 0), maMapMode).Width();
478 if (nMaxWidth < 0)
479 nMaxWidth = -nMaxWidth;
481 if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
482 nMaxWidth /= nTickUnit;
483 else
484 nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit;
486 OUString aNumString = OUString::number(nMaxWidth);
487 tools::Long nTxtWidth = rRenderContext.GetTextWidth( aNumString );
488 const tools::Long nTextOff = 4;
490 // Determine the number divider for ruler drawn numbers - means which numbers
491 // should be shown on the ruler and which should be skipped because the ruler
492 // is not big enough to draw them
493 if (nTickWidth < nTxtWidth + nTextOff)
495 // Calculate the scale of the ruler
496 tools::Long nMulti = 1;
497 tools::Long nOrgTick4 = nTick4;
499 while (nTickWidth < nTxtWidth + nTextOff)
501 tools::Long nOldMulti = nMulti;
502 if (nTickWidth == 0)
503 nMulti *= 10;
504 else if (nMulti < 10)
505 nMulti++;
506 else if (nMulti < 100)
507 nMulti += 10;
508 else if (nMulti < 1000)
509 nMulti += 100;
510 else
511 nMulti += 1000;
513 // Overflow - in this case don't draw ticks and exit
514 if (nMulti < nOldMulti)
516 bNoTicks = true;
517 break;
520 nTick4 = nOrgTick4 * nMulti;
521 aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
522 if (mnWinStyle & WB_HORZ)
523 nTickWidth = aPixSize.Width();
524 else
525 nTickWidth = aPixSize.Height();
527 nTickCount = nTick4;
529 else
531 rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetShadowColor());
534 if (bNoTicks)
535 return;
537 tools::Long n = 0;
538 double nTick = 0.0;
539 double nTick3 = 0;
541 if ((mnUnitIndex != RULER_UNIT_CHAR) && (mnUnitIndex != RULER_UNIT_LINE))
543 nTick2 = aImplRulerUnitTab[mnUnitIndex].nTick2;
544 nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3;
547 Size nTickGapSize;
549 nTickGapSize = rRenderContext.LogicToPixel(Size(nTickCount, nTickCount), maMapMode);
550 tools::Long nTickGap1 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
551 nTickGapSize = rRenderContext.LogicToPixel(Size(nTick2, nTick2), maMapMode);
552 tools::Long nTickGap2 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
553 nTickGapSize = rRenderContext.LogicToPixel(Size(nTick3, nTick3), maMapMode);
554 tools::Long nTickGap3 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
556 while (((nStart - n) >= nMin) || ((nStart + n) <= nMax))
558 // Null point
559 if (nTick == 0.0)
561 if (nStart > nMin)
563 // 0 is only painted when Margin1 is not equal to zero
564 if ((mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin1 != 0))
566 aNumString = "0";
567 ImplVDrawText(rRenderContext, nStart, nCenter, aNumString);
571 else
573 aPixSize = rRenderContext.LogicToPixel(Size(nTick, nTick), maMapMode);
575 if (mnWinStyle & WB_HORZ)
576 n = aPixSize.Width();
577 else
578 n = aPixSize.Height();
580 // Tick4 - Output (Text)
581 double aStep = nTick / nTick4;
582 double aRest = std::abs(aStep - std::floor(aStep));
583 double nAcceptanceDelta = 0.0001;
585 if (aRest < nAcceptanceDelta)
587 if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
588 aNumString = OUString::number(nTick / nTickUnit);
589 else
590 aNumString = OUString::number(nTick / aImplRulerUnitTab[mnUnitIndex].nTickUnit);
592 tools::Long nHorizontalLocation = nStart + n;
593 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
595 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
597 ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom - 1 * nScale, nHorizontalLocation + DPIOffset, nBottom);
598 ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop, nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
601 nHorizontalLocation = nStart - n;
602 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
604 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
606 ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom,
607 nHorizontalLocation + DPIOffset, nBottom - 1 * nScale);
608 ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop,
609 nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
612 // Tick/Tick2 - Output (Strokes)
613 else
615 tools::Long nTickLength = nTickLength1;
617 aStep = (nTick / nTick2);
618 aRest = std::abs(aStep - std::floor(aStep));
619 if (aRest < nAcceptanceDelta)
620 nTickLength = nTickLength2;
622 aStep = (nTick / nTick3);
623 aRest = std::abs(aStep - std::floor(aStep));
624 if (aRest < nAcceptanceDelta )
625 nTickLength = nTickLength3;
627 if ((nTickLength == nTickLength1 && nTickGap1 > 6) ||
628 (nTickLength == nTickLength2 && nTickGap2 > 6) ||
629 (nTickLength == nTickLength3 && nTickGap3 > 6))
631 tools::Long nT1 = nCenter - (nTickLength / 2.0);
632 tools::Long nT2 = nT1 + nTickLength - 1;
633 tools::Long nT;
635 nT = nStart + n;
637 if (nT < nMax)
638 ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2);
639 nT = nStart - n;
640 if (nT > nMin)
641 ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2);
645 nTick += nTickCount;
649 void Ruler::ImplDrawBorders(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
651 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
652 tools::Long n;
653 tools::Long n1;
654 tools::Long n2;
655 tools::Long nTemp1;
656 tools::Long nTemp2;
658 for (std::vector<RulerBorder>::size_type i = 0; i < mpData->pBorders.size(); i++)
660 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Invisible)
661 continue;
663 n1 = mpData->pBorders[i].nPos + mpData->nNullVirOff;
664 n2 = n1 + mpData->pBorders[i].nWidth;
666 if (((n1 >= nMin) && (n1 <= nMax)) || ((n2 >= nMin) && (n2 <= nMax)))
668 if ((n2 - n1) > 3)
670 rRenderContext.SetLineColor();
671 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
672 ImplVDrawRect(rRenderContext, n1, nVirTop, n2, nVirBottom);
674 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
675 ImplVDrawLine(rRenderContext, n1 + 1, nVirTop, n1 + 1, nVirBottom);
676 ImplVDrawLine(rRenderContext, n1, nVirTop, n2, nVirTop);
678 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
679 ImplVDrawLine(rRenderContext, n1, nVirTop, n1, nVirBottom);
680 ImplVDrawLine(rRenderContext, n1, nVirBottom, n2, nVirBottom);
681 ImplVDrawLine(rRenderContext, n2 - 1, nVirTop, n2 - 1, nVirBottom);
683 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
684 ImplVDrawLine(rRenderContext, n2, nVirTop, n2, nVirBottom);
686 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Variable)
688 if (n2 - n1 > RULER_VAR_SIZE + 4)
690 nTemp1 = n1 + (((n2 - n1 + 1) - RULER_VAR_SIZE) / 2);
691 nTemp2 = nVirTop + (((nVirBottom - nVirTop + 1) - RULER_VAR_SIZE) / 2);
692 tools::Long nTemp3 = nTemp1 + RULER_VAR_SIZE - 1;
693 tools::Long nTemp4 = nTemp2 + RULER_VAR_SIZE - 1;
694 tools::Long nTempY = nTemp2;
696 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
697 while (nTempY <= nTemp4)
699 ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
700 nTempY += 2;
703 nTempY = nTemp2 + 1;
704 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
705 while (nTempY <= nTemp4)
707 ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
708 nTempY += 2;
713 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Sizeable)
715 if (n2 - n1 > RULER_VAR_SIZE + 10)
717 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
718 ImplVDrawLine(rRenderContext, n1 + 4, nVirTop + 3, n1 + 4, nVirBottom - 3);
719 ImplVDrawLine(rRenderContext, n2 - 5, nVirTop + 3, n2 - 5, nVirBottom - 3);
720 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
721 ImplVDrawLine(rRenderContext, n1 + 5, nVirTop + 3, n1 + 5, nVirBottom - 3);
722 ImplVDrawLine(rRenderContext, n2 - 4, nVirTop + 3, n2 - 4, nVirBottom - 3);
726 else
728 n = n1 + ((n2 - n1) / 2);
729 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
731 ImplVDrawLine(rRenderContext, n - 1, nVirTop, n - 1, nVirBottom);
732 ImplVDrawLine(rRenderContext, n + 1, nVirTop, n + 1, nVirBottom);
733 rRenderContext.SetLineColor();
734 rRenderContext.SetFillColor(rStyleSettings.GetWindowColor());
735 ImplVDrawRect(rRenderContext, n, nVirTop, n, nVirBottom);
741 void Ruler::ImplDrawIndent(vcl::RenderContext& rRenderContext, const tools::Polygon& rPoly, bool bIsHit)
743 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
745 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
746 rRenderContext.SetFillColor(bIsHit ? rStyleSettings.GetDarkShadowColor() : rStyleSettings.GetWorkspaceColor());
747 tools::Polygon aPolygon(rPoly);
748 aPolygon.Optimize(PolyOptimizeFlags::CLOSE);
749 rRenderContext.DrawPolygon(aPolygon);
752 void Ruler::ImplDrawIndents(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
754 tools::Long n;
755 tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
756 tools::Long nIndentWidth2 = nIndentHeight-3;
758 tools::Polygon aPoly(5);
760 for (std::vector<RulerIndent>::size_type j = 0; j < mpData->pIndents.size(); j++)
762 if (mpData->pIndents[j].bInvisible)
763 continue;
765 RulerIndentStyle nIndentStyle = mpData->pIndents[j].nStyle;
767 n = mpData->pIndents[j].nPos+mpData->nNullVirOff;
769 if ((n >= nMin) && (n <= nMax))
771 if (nIndentStyle == RulerIndentStyle::Bottom)
773 aPoly.SetPoint(Point(n + 0, nVirBottom - nIndentHeight), 0);
774 aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom - 3), 1);
775 aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom), 2);
776 aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom), 3);
777 aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom - 3), 4);
779 else
781 aPoly.SetPoint(Point(n + 0, nVirTop + nIndentHeight), 0);
782 aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop + 3), 1);
783 aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop), 2);
784 aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop), 3);
785 aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop + 3), 4);
788 if (0 == (mnWinStyle & WB_HORZ))
790 Point aTmp;
791 for (sal_uInt16 i = 0; i < 5; i++)
793 aTmp = aPoly[i];
794 Point aSet(nVirBottom - aTmp.Y(), aTmp.X());
795 aPoly[i] = aSet;
798 bool bIsHit = false;
799 if (mxCurrentHitTest != nullptr && mxCurrentHitTest->eType == RulerType::Indent)
801 bIsHit = mxCurrentHitTest->nAryPos == j;
803 else if(mbDrag && meDragType == RulerType::Indent)
805 bIsHit = mnDragAryPos == j;
807 ImplDrawIndent(rRenderContext, aPoly, bIsHit);
812 static void ImplCenterTabPos(Point& rPos, sal_uInt16 nTabStyle)
814 bool bRTL = 0 != (nTabStyle & RULER_TAB_RTL);
815 nTabStyle &= RULER_TAB_STYLE;
816 rPos.AdjustY(ruler_tab.height/2 );
818 if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) ||
819 ( bRTL && nTabStyle == RULER_TAB_RIGHT) )
821 rPos.AdjustX( -(ruler_tab.width / 2) );
823 else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) ||
824 ( bRTL && nTabStyle == RULER_TAB_LEFT) )
826 rPos.AdjustX(ruler_tab.width / 2 );
830 static void lcl_RotateRect_Impl(tools::Rectangle& rRect, const tools::Long nReference, bool bRightAligned)
832 if (rRect.IsEmpty())
833 return;
835 tools::Rectangle aTmp(rRect);
836 rRect.SetTop( aTmp.Left() );
837 rRect.SetBottom( aTmp.Right() );
838 rRect.SetLeft( aTmp.Top() );
839 rRect.SetRight( aTmp.Bottom() );
841 if (bRightAligned)
843 tools::Long nRef = 2 * nReference;
844 rRect.SetLeft( nRef - rRect.Left() );
845 rRect.SetRight( nRef - rRect.Right() );
849 static void ImplDrawRulerTab(vcl::RenderContext& rRenderContext, const Point& rPos,
850 sal_uInt16 nStyle, WinBits nWinBits)
852 if (nStyle & RULER_STYLE_INVISIBLE)
853 return;
855 sal_uInt16 nTabStyle = nStyle & RULER_TAB_STYLE;
856 bool bRTL = 0 != (nStyle & RULER_TAB_RTL);
858 // Scale by the screen DPI scaling factor
859 // However when doing this some of the rectangles
860 // drawn become asymmetric due to the +1 offsets
861 sal_uInt16 DPIOffset = rRenderContext.GetDPIScaleFactor() - 1;
863 tools::Rectangle aRect1;
864 tools::Rectangle aRect2;
865 tools::Rectangle aRect3;
867 aRect3.SetEmpty();
869 if (nTabStyle == RULER_TAB_DEFAULT)
871 aRect1.SetLeft( rPos.X() - ruler_tab.dwidth2 + 1 );
872 aRect1.SetTop( rPos.Y() - ruler_tab.dheight2 + 1 );
873 aRect1.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth + DPIOffset );
874 aRect1.SetBottom( rPos.Y() );
876 aRect2.SetLeft( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 );
877 aRect2.SetTop( rPos.Y() - ruler_tab.dheight + 1 );
878 aRect2.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 + ruler_tab.dwidth4 - 1 );
879 aRect2.SetBottom( rPos.Y() );
882 else if ((!bRTL && nTabStyle == RULER_TAB_LEFT) || (bRTL && nTabStyle == RULER_TAB_RIGHT))
884 aRect1.SetLeft( rPos.X() );
885 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
886 aRect1.SetRight( rPos.X() + ruler_tab.width - 1 );
887 aRect1.SetBottom( rPos.Y() );
889 aRect2.SetLeft( rPos.X() );
890 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
891 aRect2.SetRight( rPos.X() + ruler_tab.width2 - 1 );
892 aRect2.SetBottom( rPos.Y() );
894 else if ((!bRTL && nTabStyle == RULER_TAB_RIGHT) || (bRTL && nTabStyle == RULER_TAB_LEFT))
896 aRect1.SetLeft( rPos.X() - ruler_tab.width + 1 );
897 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
898 aRect1.SetRight( rPos.X() );
899 aRect1.SetBottom( rPos.Y() );
901 aRect2.SetLeft( rPos.X() - ruler_tab.width2 + 1 );
902 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
903 aRect2.SetRight( rPos.X() );
904 aRect2.SetBottom( rPos.Y() );
906 else
908 aRect1.SetLeft( rPos.X() - ruler_tab.cwidth2 + 1 );
909 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
910 aRect1.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset );
911 aRect1.SetBottom( rPos.Y() );
913 aRect2.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 );
914 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
915 aRect2.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 + ruler_tab.cwidth4 - 1 );
916 aRect2.SetBottom( rPos.Y() );
918 if (nTabStyle == RULER_TAB_DECIMAL)
920 aRect3.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth - 1 );
921 aRect3.SetTop( rPos.Y() - ruler_tab.height + 1 + 1 - DPIOffset );
922 aRect3.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset );
923 aRect3.SetBottom( rPos.Y() - ruler_tab.height + 1 + 2 );
926 if (0 == (nWinBits & WB_HORZ))
928 bool bRightAligned = 0 != (nWinBits & WB_RIGHT_ALIGNED);
929 lcl_RotateRect_Impl(aRect1, rPos.Y(), bRightAligned);
930 lcl_RotateRect_Impl(aRect2, rPos.Y(), bRightAligned);
931 lcl_RotateRect_Impl(aRect3, rPos.Y(), bRightAligned);
933 rRenderContext.DrawRect(aRect1);
934 rRenderContext.DrawRect(aRect2);
936 if (!aRect3.IsEmpty())
937 rRenderContext.DrawRect(aRect3);
940 void Ruler::ImplDrawTab(vcl::RenderContext& rRenderContext, const Point& rPos, sal_uInt16 nStyle)
942 if (nStyle & RULER_STYLE_INVISIBLE)
943 return;
945 rRenderContext.SetLineColor();
947 if (nStyle & RULER_STYLE_DONTKNOW)
948 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceColor());
949 else
950 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor());
952 if (mpData->bTextRTL)
953 nStyle |= RULER_TAB_RTL;
955 ImplDrawRulerTab(rRenderContext, rPos, nStyle, GetStyle());
958 void Ruler::ImplDrawTabs(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
960 for (const RulerTab & rTab : mpData->pTabs)
962 if (rTab.nStyle & RULER_STYLE_INVISIBLE)
963 continue;
965 tools::Long aPosition;
966 aPosition = rTab.nPos;
967 aPosition += +mpData->nNullVirOff;
968 tools::Long nTopBottom = (GetStyle() & WB_RIGHT_ALIGNED) ? nVirTop : nVirBottom;
969 if (nMin <= aPosition && aPosition <= nMax)
970 ImplDrawTab(rRenderContext, Point( aPosition, nTopBottom ), rTab.nStyle);
974 static int adjustSize(int nOrig)
976 if (nOrig <= 0)
977 return 0;
979 // make sure we return an odd number, that looks better in the ruler
980 return ( (3*nOrig) / 8) * 2 + 1;
983 void Ruler::ApplySettings(vcl::RenderContext& rRenderContext)
985 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
987 vcl::Font aFont = rStyleSettings.GetToolFont();
988 // make the font a bit smaller than default
989 Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
990 aFont.SetFontSize(aSize);
992 ApplyControlFont(rRenderContext, aFont);
994 ApplyControlForeground(*this, rStyleSettings.GetDarkShadowColor());
995 SetTextFillColor();
997 Color aColor;
998 svtools::ColorConfig aColorConfig;
999 aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
1000 ApplyControlBackground(rRenderContext, aColor);
1003 void Ruler::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1005 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1007 if (bFont)
1009 vcl::Font aFont = rStyleSettings.GetToolFont();
1010 // make the font a bit smaller than default
1011 Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
1012 aFont.SetFontSize(aSize);
1014 ApplyControlFont(*this, aFont);
1017 if (bForeground || bFont)
1019 ApplyControlForeground(*this, rStyleSettings.GetDarkShadowColor());
1020 SetTextFillColor();
1023 if (bBackground)
1025 Color aColor;
1026 svtools::ColorConfig aColorConfig;
1027 aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
1028 ApplyControlBackground(*this, aColor);
1031 maVirDev->SetSettings( GetSettings() );
1032 maVirDev->SetBackground( GetBackground() );
1033 vcl::Font aFont = GetFont();
1035 if (mnWinStyle & WB_VERT)
1036 aFont.SetOrientation(Degree10(900));
1038 maVirDev->SetFont(aFont);
1039 maVirDev->SetTextColor(GetTextColor());
1040 maVirDev->SetTextFillColor(GetTextFillColor());
1043 void Ruler::ImplCalc()
1045 // calculate offset
1046 mpData->nRulVirOff = mnWinOff + mpData->nPageOff;
1047 if ( mpData->nRulVirOff > mnVirOff )
1048 mpData->nRulVirOff -= mnVirOff;
1049 else
1050 mpData->nRulVirOff = 0;
1051 tools::Long nRulWinOff = mpData->nRulVirOff+mnVirOff;
1053 // calculate non-visual part of the page
1054 tools::Long nNotVisPageWidth;
1055 if ( mpData->nPageOff < 0 )
1057 nNotVisPageWidth = -(mpData->nPageOff);
1058 if ( nRulWinOff < mnWinOff )
1059 nNotVisPageWidth -= mnWinOff-nRulWinOff;
1061 else
1062 nNotVisPageWidth = 0;
1064 // calculate width
1065 if ( mnWinStyle & WB_HORZ )
1067 if ( mbAutoWinWidth )
1068 mnWinWidth = mnWidth - mnVirOff;
1069 if ( mpData->bAutoPageWidth )
1070 mpData->nPageWidth = mnWinWidth;
1071 mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1072 if ( nRulWinOff+mpData->nRulWidth > mnWidth )
1073 mpData->nRulWidth = mnWidth-nRulWinOff;
1075 else
1077 if ( mbAutoWinWidth )
1078 mnWinWidth = mnHeight - mnVirOff;
1079 if ( mpData->bAutoPageWidth )
1080 mpData->nPageWidth = mnWinWidth;
1081 mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1082 if ( nRulWinOff+mpData->nRulWidth > mnHeight )
1083 mpData->nRulWidth = mnHeight-nRulWinOff;
1086 mbCalc = false;
1089 void Ruler::ImplFormat(vcl::RenderContext const & rRenderContext)
1091 // if already formatted, don't do it again
1092 if (!mbFormat)
1093 return;
1095 // don't do anything if the window still has no size
1096 if (!mnVirWidth)
1097 return;
1099 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1100 tools::Long nP1; // pixel position of Page1
1101 tools::Long nP2; // pixel position of Page2
1102 tools::Long nM1; // pixel position of Margin1
1103 tools::Long nM2; // pixel position of Margin2
1104 tools::Long nVirTop; // top/left corner
1105 tools::Long nVirBottom; // bottom/right corner
1106 tools::Long nVirLeft; // left/top corner
1107 tools::Long nVirRight; // right/bottom corner
1108 tools::Long nNullVirOff; // for faster calculation
1110 // calculate values
1111 if (mbCalc)
1112 ImplCalc();
1114 mpData->nNullVirOff = mnWinOff + mpData->nPageOff + mpData->nNullOff - mnVirOff;
1116 nNullVirOff = mpData->nNullVirOff;
1117 nVirLeft = mpData->nRulVirOff;
1118 nVirRight = nVirLeft + mpData->nRulWidth - 1;
1119 nVirTop = 0;
1120 nVirBottom = mnVirHeight - 1;
1122 if (!IsReallyVisible())
1123 return;
1125 Size aVirDevSize;
1127 // initialize VirtualDevice
1128 if (mnWinStyle & WB_HORZ)
1130 aVirDevSize.setWidth( mnVirWidth );
1131 aVirDevSize.setHeight( mnVirHeight );
1133 else
1135 aVirDevSize.setHeight( mnVirWidth );
1136 aVirDevSize.setWidth( mnVirHeight );
1138 if (aVirDevSize != maVirDev->GetOutputSizePixel())
1139 maVirDev->SetOutputSizePixel(aVirDevSize);
1140 else
1141 maVirDev->Erase();
1143 // calculate margins
1144 if (!(mpData->nMargin1Style & RulerMarginStyle::Invisible))
1146 nM1 = mpData->nMargin1 + nNullVirOff;
1147 if (mpData->bAutoPageWidth)
1149 nP1 = nVirLeft;
1150 if (nM1 < nVirLeft)
1151 nP1--;
1153 else
1154 nP1 = nNullVirOff - mpData->nNullOff;
1156 else
1158 nM1 = nVirLeft-1;
1159 nP1 = nM1;
1161 if (!(mpData->nMargin2Style & RulerMarginStyle::Invisible))
1163 nM2 = mpData->nMargin2 + nNullVirOff;
1164 if (mpData->bAutoPageWidth)
1166 nP2 = nVirRight;
1167 if (nM2 > nVirRight)
1168 nP2++;
1170 else
1171 nP2 = nNullVirOff - mpData->nNullOff + mpData->nPageWidth;
1172 if (nM2 > nP2)
1173 nM2 = nP2;
1175 else
1177 nM2 = nVirRight+1;
1178 nP2 = nM2;
1181 // top/bottom border
1182 maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1183 ImplVDrawLine(*maVirDev, nVirLeft, nVirTop + 1, nM1, nVirTop + 1); //top left line
1184 ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nP2 - 1, nVirTop + 1); //top right line
1186 nVirTop++;
1187 nVirBottom--;
1189 // draw margin1, margin2 and in-between
1190 maVirDev->SetLineColor();
1191 maVirDev->SetFillColor(rStyleSettings.GetDialogColor());
1192 if (nM1 > nVirLeft)
1193 ImplVDrawRect(*maVirDev, nP1, nVirTop + 1, nM1, nVirBottom); //left gray rectangle
1194 if (nM2 < nP2)
1195 ImplVDrawRect(*maVirDev, nM2, nVirTop + 1, nP2, nVirBottom); //right gray rectangle
1196 if (nM2 - nM1 > 0)
1198 maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1199 ImplVDrawRect(*maVirDev, nM1 + 1, nVirTop, nM2 - 1, nVirBottom); //center rectangle
1201 maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1202 if (nM1 > nVirLeft)
1204 ImplVDrawLine(*maVirDev, nM1, nVirTop + 1, nM1, nVirBottom); //right line of the left rectangle
1205 ImplVDrawLine(*maVirDev, nP1, nVirBottom, nM1, nVirBottom); //bottom line of the left rectangle
1206 if (nP1 >= nVirLeft)
1208 ImplVDrawLine(*maVirDev, nP1, nVirTop + 1, nP1, nVirBottom); //left line of the left rectangle
1209 ImplVDrawLine(*maVirDev, nP1, nVirBottom, nP1 + 1, nVirBottom); //?
1212 if (nM2 < nP2)
1214 ImplVDrawLine(*maVirDev, nM2, nVirBottom, nP2 - 1, nVirBottom); //bottom line of the right rectangle
1215 ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nM2, nVirBottom); //left line of the right rectangle
1216 if (nP2 <= nVirRight + 1)
1217 ImplVDrawLine(*maVirDev, nP2 - 1, nVirTop + 1, nP2 - 1, nVirBottom); //right line of the right rectangle
1220 tools::Long nMin = nVirLeft;
1221 tools::Long nMax = nP2;
1222 tools::Long nStart = 0;
1224 if (mpData->bTextRTL)
1225 nStart = mpData->nRightFrameMargin + nNullVirOff;
1226 else
1227 nStart = mpData->nLeftFrameMargin + nNullVirOff;
1229 if (nP1 > nVirLeft)
1230 nMin++;
1232 if (nP2 < nVirRight)
1233 nMax--;
1235 // Draw captions
1236 ImplDrawTicks(*maVirDev, nMin, nMax, nStart, nVirTop, nVirBottom);
1238 // Draw borders
1239 if (!mpData->pBorders.empty())
1240 ImplDrawBorders(*maVirDev, nVirLeft, nP2, nVirTop, nVirBottom);
1242 // Draw indents
1243 if (!mpData->pIndents.empty())
1244 ImplDrawIndents(*maVirDev, nVirLeft, nP2, nVirTop - 1, nVirBottom + 1);
1246 // Tabs
1247 if (!mpData->pTabs.empty())
1248 ImplDrawTabs(*maVirDev, nVirLeft, nP2, nVirTop-1, nVirBottom + 1);
1250 mbFormat = false;
1253 void Ruler::ImplInitExtraField( bool bUpdate )
1255 Size aWinSize = GetOutputSizePixel();
1257 // extra field evaluate
1258 if ( mnWinStyle & WB_EXTRAFIELD )
1260 maExtraRect.SetLeft( RULER_OFF );
1261 maExtraRect.SetTop( RULER_OFF );
1262 maExtraRect.SetRight( RULER_OFF + mnVirHeight - 1 );
1263 maExtraRect.SetBottom( RULER_OFF + mnVirHeight - 1 );
1264 if(mpData->bTextRTL)
1266 if(mnWinStyle & WB_HORZ)
1267 maExtraRect.Move(aWinSize.Width() - maExtraRect.GetWidth() - maExtraRect.Left(), 0);
1268 else
1269 maExtraRect.Move(0, aWinSize.Height() - maExtraRect.GetHeight() - maExtraRect.Top());
1270 mnVirOff = 0;
1272 else
1273 mnVirOff = maExtraRect.Right()+1;
1276 else
1278 maExtraRect.SetEmpty();
1279 mnVirOff = 0;
1282 // mnVirWidth depends on mnVirOff
1283 if ( (mnVirWidth > RULER_MIN_SIZE) ||
1284 ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) )
1286 if ( mnWinStyle & WB_HORZ )
1287 mnVirWidth = aWinSize.Width()-mnVirOff;
1288 else
1289 mnVirWidth = aWinSize.Height()-mnVirOff;
1291 if ( mnVirWidth < RULER_MIN_SIZE )
1292 mnVirWidth = 0;
1295 if ( bUpdate )
1297 mbCalc = true;
1298 mbFormat = true;
1299 Invalidate();
1303 void Ruler::ImplDraw(vcl::RenderContext& rRenderContext)
1305 if (mbFormat)
1307 ImplFormat(rRenderContext);
1310 if (!IsReallyVisible())
1311 return;
1313 // output the ruler to the virtual device
1314 Point aOffPos;
1315 Size aVirDevSize = maVirDev->GetOutputSizePixel();
1317 if (mnWinStyle & WB_HORZ)
1319 aOffPos.setX( mnVirOff );
1320 if (mpData->bTextRTL)
1321 aVirDevSize.AdjustWidth( -(maExtraRect.GetWidth()) );
1323 aOffPos.setY( RULER_OFF );
1325 else
1327 aOffPos.setX( RULER_OFF );
1328 aOffPos.setY( mnVirOff );
1330 rRenderContext.DrawOutDev(aOffPos, aVirDevSize, Point(), aVirDevSize, *maVirDev);
1332 // redraw positionlines
1333 ImplInvertLines(rRenderContext);
1336 void Ruler::ImplDrawExtra(vcl::RenderContext& rRenderContext)
1338 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1339 tools::Rectangle aRect = maExtraRect;
1340 bool bEraseRect = false;
1342 aRect.AdjustLeft(2 );
1343 aRect.AdjustTop(2 );
1344 aRect.AdjustRight( -2 );
1345 aRect.AdjustBottom( -2 );
1347 if (mnExtraStyle & RULER_STYLE_HIGHLIGHT)
1349 rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
1350 bEraseRect = true;
1353 if (bEraseRect)
1355 rRenderContext.SetLineColor();
1356 rRenderContext.DrawRect(aRect);
1359 // output content
1360 if (meExtraType == RulerExtra::NullOffset)
1362 rRenderContext.SetLineColor(rStyleSettings.GetButtonTextColor());
1363 rRenderContext.DrawLine(Point(aRect.Left() + 1, aRect.Top() + 4),
1364 Point(aRect.Right() - 1, aRect.Top() + 4));
1365 rRenderContext.DrawLine(Point(aRect.Left() + 4, aRect.Top() + 1),
1366 Point(aRect.Left() + 4, aRect.Bottom() - 1));
1368 else if (meExtraType == RulerExtra::Tab)
1370 sal_uInt16 nTabStyle = mnExtraStyle & RULER_TAB_STYLE;
1371 if (mpData->bTextRTL)
1372 nTabStyle |= RULER_TAB_RTL;
1373 Point aCenter = aRect.Center();
1374 Point aDraw(aCenter);
1375 ImplCenterTabPos(aDraw, nTabStyle);
1376 WinBits nWinBits = GetStyle();
1377 if (0 == (nWinBits & WB_HORZ))
1379 if ((nWinBits & WB_RIGHT_ALIGNED) != 0)
1380 aDraw.setY( 2 * aCenter.Y() - aDraw.Y() );
1382 if (mpData->bTextRTL)
1384 tools::Long nTemp = aDraw.X();
1385 aDraw.setX( aDraw.Y() );
1386 aDraw.setY( nTemp );
1389 ImplDrawTab(rRenderContext, aDraw, nTabStyle);
1393 void Ruler::ImplUpdate( bool bMustCalc )
1395 // clear lines in this place so they aren't considered at recalculation
1396 if (!mbFormat)
1397 Invalidate(InvalidateFlags::NoErase);
1399 // set flags
1400 if (bMustCalc)
1401 mbCalc = true;
1402 mbFormat = true;
1404 // abort if we are dragging as drag-handler will update the ruler after drag is finished
1405 if (mbDrag)
1406 return;
1408 // otherwise trigger update
1409 if (IsReallyVisible() && IsUpdateMode())
1411 Invalidate(InvalidateFlags::NoErase);
1415 bool Ruler::ImplHitTest( const Point& rPos, RulerSelection* pHitTest,
1416 bool bRequireStyle, RulerIndentStyle nRequiredStyle ) const
1418 sal_Int32 i;
1419 sal_uInt16 nStyle;
1420 tools::Long nHitBottom;
1421 tools::Long nX;
1422 tools::Long nY;
1423 tools::Long n1;
1425 if ( !mbActive )
1426 return false;
1428 // determine positions
1429 bool bIsHori = 0 != (mnWinStyle & WB_HORZ);
1430 if ( bIsHori )
1432 nX = rPos.X();
1433 nY = rPos.Y();
1435 else
1437 nX = rPos.Y();
1438 nY = rPos.X();
1440 nHitBottom = mnVirHeight + (RULER_OFF * 2);
1442 // #i32608#
1443 pHitTest->nAryPos = 0;
1444 pHitTest->mnDragSize = RulerDragSize::Move;
1445 pHitTest->bSize = false;
1446 pHitTest->bSizeBar = false;
1448 // so that leftover tabs and indents are taken into account
1449 tools::Long nXExtraOff;
1450 if ( !mpData->pTabs.empty() || !mpData->pIndents.empty() )
1451 nXExtraOff = (mnVirHeight / 2) - 4;
1452 else
1453 nXExtraOff = 0;
1455 // test if outside
1456 nX -= mnVirOff;
1457 if ( (nX < mpData->nRulVirOff - nXExtraOff) ||
1458 (nX > mpData->nRulVirOff + mpData->nRulWidth + nXExtraOff) ||
1459 (nY < 0) ||
1460 (nY > nHitBottom) )
1462 pHitTest->nPos = 0;
1463 pHitTest->eType = RulerType::Outside;
1464 return false;
1467 nX -= mpData->nNullVirOff;
1468 pHitTest->nPos = nX;
1469 pHitTest->eType = RulerType::DontKnow;
1471 // first test the tabs
1472 tools::Rectangle aRect;
1473 if ( !mpData->pTabs.empty() )
1475 aRect.SetBottom( nHitBottom );
1476 aRect.SetTop( aRect.Bottom() - ruler_tab.height - RULER_OFF );
1478 for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1480 nStyle = mpData->pTabs[i].nStyle;
1481 if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1483 nStyle &= RULER_TAB_STYLE;
1485 // default tabs are only shown (no action)
1486 if ( nStyle != RULER_TAB_DEFAULT )
1488 n1 = mpData->pTabs[i].nPos;
1490 if ( nStyle == RULER_TAB_LEFT )
1492 aRect.SetLeft( n1 );
1493 aRect.SetRight( n1 + ruler_tab.width - 1 );
1495 else if ( nStyle == RULER_TAB_RIGHT )
1497 aRect.SetRight( n1 );
1498 aRect.SetLeft( n1 - ruler_tab.width - 1 );
1500 else
1502 aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1503 aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1506 if ( aRect.IsInside( Point( nX, nY ) ) )
1508 pHitTest->eType = RulerType::Tab;
1509 pHitTest->nAryPos = i;
1510 return true;
1517 // Indents
1518 if ( !mpData->pIndents.empty() )
1520 tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
1521 tools::Long nIndentWidth2 = nIndentHeight - 3;
1523 for ( i = mpData->pIndents.size(); i; i-- )
1525 RulerIndentStyle nIndentStyle = mpData->pIndents[i-1].nStyle;
1526 if ( (! bRequireStyle || nIndentStyle == nRequiredStyle) &&
1527 !mpData->pIndents[i-1].bInvisible )
1529 n1 = mpData->pIndents[i-1].nPos;
1531 if ( (nIndentStyle == RulerIndentStyle::Bottom) != !bIsHori )
1533 aRect.SetLeft( n1-nIndentWidth2 );
1534 aRect.SetRight( n1+nIndentWidth2 );
1535 aRect.SetTop( nHitBottom-nIndentHeight-RULER_OFF+1 );
1536 aRect.SetBottom( nHitBottom );
1538 else
1540 aRect.SetLeft( n1-nIndentWidth2 );
1541 aRect.SetRight( n1+nIndentWidth2 );
1542 aRect.SetTop( 0 );
1543 aRect.SetBottom( nIndentHeight+RULER_OFF-1 );
1546 if ( aRect.IsInside( Point( nX, nY ) ) )
1548 pHitTest->eType = RulerType::Indent;
1549 pHitTest->nAryPos = i-1;
1550 return true;
1556 // test the borders
1557 int nBorderTolerance = 1;
1558 if(pHitTest->bExpandTest)
1560 nBorderTolerance++;
1563 for ( i = mpData->pBorders.size(); i; i-- )
1565 n1 = mpData->pBorders[i-1].nPos;
1566 tools::Long n2 = n1 + mpData->pBorders[i-1].nWidth;
1568 // borders have at least 3 pixel padding
1569 if ( !mpData->pBorders[i-1].nWidth )
1571 n1 -= nBorderTolerance;
1572 n2 += nBorderTolerance;
1576 if ( (nX >= n1) && (nX <= n2) )
1578 RulerBorderStyle nBorderStyle = mpData->pBorders[i-1].nStyle;
1579 if ( !(nBorderStyle & RulerBorderStyle::Invisible) )
1581 pHitTest->eType = RulerType::Border;
1582 pHitTest->nAryPos = i-1;
1584 if ( !(nBorderStyle & RulerBorderStyle::Sizeable) )
1586 if ( nBorderStyle & RulerBorderStyle::Moveable )
1588 pHitTest->bSizeBar = true;
1589 pHitTest->mnDragSize = RulerDragSize::Move;
1592 else
1594 tools::Long nMOff = RULER_MOUSE_BORDERWIDTH;
1595 while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) )
1597 if ( nMOff < 2 )
1599 nMOff = 0;
1600 break;
1602 else
1603 nMOff--;
1606 if ( nX <= n1+nMOff )
1608 pHitTest->bSize = true;
1609 pHitTest->mnDragSize = RulerDragSize::N1;
1611 else if ( nX >= n2-nMOff )
1613 pHitTest->bSize = true;
1614 pHitTest->mnDragSize = RulerDragSize::N2;
1616 else
1618 if ( nBorderStyle & RulerBorderStyle::Moveable )
1620 pHitTest->bSizeBar = true;
1621 pHitTest->mnDragSize = RulerDragSize::Move;
1626 return true;
1631 // Margins
1632 int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH;
1634 if ( (mpData->nMargin1Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1636 n1 = mpData->nMargin1;
1637 if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1639 pHitTest->eType = RulerType::Margin1;
1640 pHitTest->bSize = true;
1641 return true;
1644 if ( (mpData->nMargin2Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1646 n1 = mpData->nMargin2;
1647 if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1649 pHitTest->eType = RulerType::Margin2;
1650 pHitTest->bSize = true;
1651 return true;
1655 // test tabs again
1656 if ( !mpData->pTabs.empty() )
1658 aRect.SetTop( RULER_OFF );
1659 aRect.SetBottom( nHitBottom );
1661 for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1663 nStyle = mpData->pTabs[i].nStyle;
1664 if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1666 nStyle &= RULER_TAB_STYLE;
1668 // default tabs are only shown (no action)
1669 if ( nStyle != RULER_TAB_DEFAULT )
1671 n1 = mpData->pTabs[i].nPos;
1673 if ( nStyle == RULER_TAB_LEFT )
1675 aRect.SetLeft( n1 );
1676 aRect.SetRight( n1 + ruler_tab.width - 1 );
1678 else if ( nStyle == RULER_TAB_RIGHT )
1680 aRect.SetRight( n1 );
1681 aRect.SetLeft( n1 - ruler_tab.width - 1 );
1683 else
1685 aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1686 aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1689 aRect.AdjustLeft( -1 );
1690 aRect.AdjustRight( 1 );
1692 if ( aRect.IsInside( Point( nX, nY ) ) )
1694 pHitTest->eType = RulerType::Tab;
1695 pHitTest->nAryPos = i;
1696 return true;
1703 return false;
1706 bool Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType,
1707 RulerSelection* pHitTest ) const
1709 Point aPos = rPos;
1710 bool bRequiredStyle = false;
1711 RulerIndentStyle nRequiredStyle = RulerIndentStyle::Top;
1713 if (eDragType == RulerType::Indent)
1715 bRequiredStyle = true;
1716 nRequiredStyle = RulerIndentStyle::Bottom;
1719 if ( mnWinStyle & WB_HORZ )
1720 aPos.AdjustX(mnWinOff );
1721 else
1722 aPos.AdjustY(mnWinOff );
1724 if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::DontKnow) )
1726 if ( mnWinStyle & WB_HORZ )
1727 aPos.setY( RULER_OFF + 1 );
1728 else
1729 aPos.setX( RULER_OFF + 1 );
1731 if ( ImplHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) )
1733 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1734 return true;
1738 if ( (eDragType == RulerType::Indent) ||
1739 (eDragType == RulerType::Tab) ||
1740 (eDragType == RulerType::DontKnow) )
1742 if ( mnWinStyle & WB_HORZ )
1743 aPos.setY( mnHeight - RULER_OFF - 1 );
1744 else
1745 aPos.setX( mnWidth - RULER_OFF - 1 );
1747 if ( ImplHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) )
1749 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1750 return true;
1754 if ( (eDragType == RulerType::Margin1) || (eDragType == RulerType::Margin2) ||
1755 (eDragType == RulerType::Border) || (eDragType == RulerType::DontKnow) )
1757 if ( mnWinStyle & WB_HORZ )
1758 aPos.setY( RULER_OFF + (mnVirHeight / 2) );
1759 else
1760 aPos.setX( RULER_OFF + (mnVirHeight / 2) );
1762 if ( ImplHitTest( aPos, pHitTest ) )
1764 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1765 return true;
1769 pHitTest->eType = RulerType::DontKnow;
1771 return false;
1774 bool Ruler::ImplStartDrag( RulerSelection const * pHitTest, sal_uInt16 nModifier )
1776 // don't trigger drag if a border that was clicked can not be changed
1777 if ( (pHitTest->eType == RulerType::Border) &&
1778 !pHitTest->bSize && !pHitTest->bSizeBar )
1779 return false;
1781 // Set drag data
1782 meDragType = pHitTest->eType;
1783 mnDragPos = pHitTest->nPos;
1784 mnDragAryPos = pHitTest->nAryPos;
1785 mnDragSize = pHitTest->mnDragSize;
1786 mnDragModifier = nModifier;
1787 *mpDragData = *mpSaveData;
1788 mpData = mpDragData.get();
1790 // call handler
1791 if (StartDrag())
1793 // if the handler allows dragging, initialize dragging
1794 mbDrag = true;
1795 mnStartDragPos = mnDragPos;
1796 StartTracking();
1797 Invalidate(InvalidateFlags::NoErase);
1798 return true;
1800 else
1802 // otherwise reset the data
1803 meDragType = RulerType::DontKnow;
1804 mnDragPos = 0;
1805 mnDragAryPos = 0;
1806 mnDragSize = RulerDragSize::Move;
1807 mnDragModifier = 0;
1808 mpData = mpSaveData.get();
1811 return false;
1814 void Ruler::ImplDrag( const Point& rPos )
1816 tools::Long nX;
1817 tools::Long nY;
1818 tools::Long nOutHeight;
1820 if ( mnWinStyle & WB_HORZ )
1822 nX = rPos.X();
1823 nY = rPos.Y();
1824 nOutHeight = mnHeight;
1826 else
1828 nX = rPos.Y();
1829 nY = rPos.X();
1830 nOutHeight = mnWidth;
1833 // calculate and fit X
1834 nX -= mnVirOff;
1835 if ( nX < mpData->nRulVirOff )
1837 nX = mpData->nRulVirOff;
1839 else if ( nX > mpData->nRulVirOff+mpData->nRulWidth )
1841 nX = mpData->nRulVirOff+mpData->nRulWidth;
1843 nX -= mpData->nNullVirOff;
1845 // if upper or left from ruler, then consider old values
1846 mbDragDelete = false;
1847 if ( nY < 0 )
1849 if ( !mbDragCanceled )
1851 // reset the data
1852 mbDragCanceled = true;
1853 ImplRulerData aTempData = *mpDragData;
1854 *mpDragData = *mpSaveData;
1855 mbCalc = true;
1856 mbFormat = true;
1858 // call handler
1859 mnDragPos = mnStartDragPos;
1860 Drag();
1862 // and redraw
1863 Invalidate(InvalidateFlags::NoErase);
1865 // reset the data as before cancel
1866 *mpDragData = aTempData;
1869 else
1871 mbDragCanceled = false;
1873 // +2, so the tabs are not cleared too quickly
1874 if ( nY > nOutHeight + 2 )
1875 mbDragDelete = true;
1877 mnDragPos = nX;
1879 // call handler
1880 Drag();
1882 // redraw
1883 if (mbFormat)
1884 Invalidate(InvalidateFlags::NoErase);
1888 void Ruler::ImplEndDrag()
1890 // get values
1891 if ( mbDragCanceled )
1892 *mpDragData = *mpSaveData;
1893 else
1894 *mpSaveData = *mpDragData;
1896 mpData = mpSaveData.get();
1897 mbDrag = false;
1899 // call handler
1900 EndDrag();
1902 // reset drag values
1903 meDragType = RulerType::DontKnow;
1904 mnDragPos = 0;
1905 mnDragAryPos = 0;
1906 mnDragSize = RulerDragSize::Move;
1907 mbDragCanceled = false;
1908 mbDragDelete = false;
1909 mnDragModifier = 0;
1910 mnStartDragPos = 0;
1912 // redraw
1913 Invalidate(InvalidateFlags::NoErase);
1916 void Ruler::MouseButtonDown( const MouseEvent& rMEvt )
1918 if ( !rMEvt.IsLeft() || IsTracking() )
1919 return;
1921 Point aMousePos = rMEvt.GetPosPixel();
1922 sal_uInt16 nMouseClicks = rMEvt.GetClicks();
1923 sal_uInt16 nMouseModifier = rMEvt.GetModifier();
1925 // update ruler
1926 if ( mbFormat )
1928 Invalidate(InvalidateFlags::NoErase);
1931 if ( maExtraRect.IsInside( aMousePos ) )
1933 ExtraDown();
1935 else
1937 std::unique_ptr<RulerSelection> pHitTest(new RulerSelection);
1938 bool bHitTestResult = ImplHitTest(aMousePos, pHitTest.get());
1940 if ( nMouseClicks == 1 )
1942 if ( bHitTestResult )
1944 ImplStartDrag( pHitTest.get(), nMouseModifier );
1946 else
1948 // calculate position inside of ruler area
1949 if ( pHitTest->eType == RulerType::DontKnow )
1951 mnDragPos = pHitTest->nPos;
1952 Click();
1953 mnDragPos = 0;
1955 // call HitTest again as a click, for example, could set a new tab
1956 if ( ImplHitTest(aMousePos, pHitTest.get()) )
1957 ImplStartDrag(pHitTest.get(), nMouseModifier);
1961 else
1963 if (bHitTestResult)
1965 mnDragPos = pHitTest->nPos;
1966 mnDragAryPos = pHitTest->nAryPos;
1968 meDragType = pHitTest->eType;
1970 DoubleClick();
1972 meDragType = RulerType::DontKnow;
1973 mnDragPos = 0;
1974 mnDragAryPos = 0;
1979 void Ruler::MouseMove( const MouseEvent& rMEvt )
1981 PointerStyle ePtrStyle = PointerStyle::Arrow;
1983 mxPreviousHitTest.swap(mxCurrentHitTest);
1985 mxCurrentHitTest.reset(new RulerSelection);
1987 maHoverSelection.eType = RulerType::DontKnow;
1989 if (ImplHitTest( rMEvt.GetPosPixel(), mxCurrentHitTest.get() ))
1991 maHoverSelection = *mxCurrentHitTest;
1993 if (mxCurrentHitTest->bSize)
1995 if (mnWinStyle & WB_HORZ)
1997 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
1998 ePtrStyle = PointerStyle::TabSelectW;
1999 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2000 ePtrStyle = PointerStyle::TabSelectE;
2001 else
2002 ePtrStyle = PointerStyle::ESize;
2004 else
2006 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
2007 ePtrStyle = PointerStyle::WindowNSize;
2008 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2009 ePtrStyle = PointerStyle::WindowSSize;
2010 else
2011 ePtrStyle = PointerStyle::SSize;
2014 else if (mxCurrentHitTest->bSizeBar)
2016 if (mnWinStyle & WB_HORZ)
2017 ePtrStyle = PointerStyle::HSizeBar;
2018 else
2019 ePtrStyle = PointerStyle::VSizeBar;
2023 if (mxPreviousHitTest != nullptr && mxPreviousHitTest->eType != mxCurrentHitTest->eType)
2025 mbFormat = true;
2028 SetPointer( ePtrStyle );
2030 if (mbFormat)
2032 Invalidate(InvalidateFlags::NoErase);
2036 void Ruler::Tracking( const TrackingEvent& rTEvt )
2038 if ( rTEvt.IsTrackingEnded() )
2040 // reset the old state at cancel
2041 if ( rTEvt.IsTrackingCanceled() )
2043 mbDragCanceled = true;
2044 mbFormat = true;
2047 ImplEndDrag();
2049 else
2050 ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() );
2053 void Ruler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2055 ImplDraw(rRenderContext);
2057 // consider extra field
2058 if (mnWinStyle & WB_EXTRAFIELD)
2059 ImplDrawExtra(rRenderContext);
2062 void Ruler::Resize()
2064 Size aWinSize = GetOutputSizePixel();
2066 tools::Long nNewHeight;
2067 if ( mnWinStyle & WB_HORZ )
2069 if ( aWinSize.Height() != mnHeight )
2070 nNewHeight = aWinSize.Height();
2071 else
2072 nNewHeight = 0;
2074 else
2076 if ( aWinSize.Width() != mnWidth )
2077 nNewHeight = aWinSize.Width();
2078 else
2079 nNewHeight = 0;
2082 mbFormat = true;
2084 // clear lines
2085 bool bVisible = IsReallyVisible();
2086 if ( bVisible && !mpData->pLines.empty() )
2088 mnUpdateFlags |= RULER_UPDATE_LINES;
2089 Invalidate(InvalidateFlags::NoErase);
2092 // recalculate some values if the height/width changes
2093 // extra field should always be updated
2094 ImplInitExtraField( mpData->bTextRTL );
2095 if ( nNewHeight )
2097 mbCalc = true;
2098 mnVirHeight = nNewHeight - mnBorderWidth - ( RULER_OFF * 2 );
2100 else
2102 if ( mpData->bAutoPageWidth )
2103 ImplUpdate( true );
2104 else if ( mbAutoWinWidth )
2105 mbCalc = true;
2108 // clear part of the border
2109 if ( bVisible )
2111 if ( nNewHeight )
2112 Invalidate(InvalidateFlags::NoErase);
2113 else if ( mpData->bAutoPageWidth )
2115 // only at AutoPageWidth do we need to redraw
2116 tools::Rectangle aRect;
2118 if ( mnWinStyle & WB_HORZ )
2120 if ( mnWidth < aWinSize.Width() )
2121 aRect.SetLeft( mnWidth - RULER_RESIZE_OFF );
2122 else
2123 aRect.SetLeft( aWinSize.Width() - RULER_RESIZE_OFF );
2124 aRect.SetRight( aRect.Left() + RULER_RESIZE_OFF );
2125 aRect.SetTop( RULER_OFF );
2126 aRect.SetBottom( RULER_OFF + mnVirHeight );
2128 else
2130 if ( mnHeight < aWinSize.Height() )
2131 aRect.SetTop( mnHeight-RULER_RESIZE_OFF );
2132 else
2133 aRect.SetTop( aWinSize.Height()-RULER_RESIZE_OFF );
2134 aRect.SetBottom( aRect.Top() + RULER_RESIZE_OFF );
2135 aRect.SetLeft( RULER_OFF );
2136 aRect.SetRight( RULER_OFF + mnVirHeight );
2139 Invalidate(aRect, InvalidateFlags::NoErase);
2143 mnWidth = aWinSize.Width();
2144 mnHeight = aWinSize.Height();
2147 void Ruler::StateChanged( StateChangedType nType )
2149 Window::StateChanged( nType );
2151 if ( nType == StateChangedType::InitShow )
2152 Invalidate();
2153 else if ( nType == StateChangedType::UpdateMode )
2155 if ( IsReallyVisible() && IsUpdateMode() )
2156 Invalidate();
2158 else if ( (nType == StateChangedType::Zoom) ||
2159 (nType == StateChangedType::ControlFont) )
2161 ImplInitSettings( true, false, false );
2162 Invalidate();
2164 else if ( nType == StateChangedType::ControlForeground )
2166 ImplInitSettings( false, true, false );
2167 Invalidate();
2169 else if ( nType == StateChangedType::ControlBackground )
2171 ImplInitSettings( false, false, true );
2172 Invalidate();
2176 void Ruler::DataChanged( const DataChangedEvent& rDCEvt )
2178 Window::DataChanged( rDCEvt );
2180 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2181 (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
2182 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2183 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2184 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2186 mbFormat = true;
2187 ImplInitSettings( true, true, true );
2188 Invalidate();
2192 bool Ruler::StartDrag()
2194 return false;
2197 void Ruler::Drag()
2201 void Ruler::EndDrag()
2205 void Ruler::Click()
2209 void Ruler::DoubleClick()
2211 maDoubleClickHdl.Call( this );
2214 void Ruler::ExtraDown()
2218 void Ruler::Activate()
2220 mbActive = true;
2222 // update positionlines - draw is delayed
2223 mnUpdateFlags |= RULER_UPDATE_LINES;
2224 Invalidate(InvalidateFlags::NoErase);
2227 void Ruler::Deactivate()
2229 // clear positionlines
2230 Invalidate(InvalidateFlags::NoErase);
2232 mbActive = false;
2235 bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType )
2237 if ( !mbDrag )
2239 Point aMousePos = rMEvt.GetPosPixel();
2240 sal_uInt16 nMouseClicks = rMEvt.GetClicks();
2241 sal_uInt16 nMouseModifier = rMEvt.GetModifier();
2242 RulerSelection aHitTest;
2244 if(eDragType != RulerType::DontKnow)
2245 aHitTest.bExpandTest = true;
2247 // update ruler
2248 if ( mbFormat )
2250 if (!IsReallyVisible())
2252 // set mpData for ImplDocHitTest()
2253 ImplFormat(*this);
2256 Invalidate(InvalidateFlags::NoErase);
2259 if ( nMouseClicks == 1 )
2261 if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) )
2263 PointerStyle aPtr = PointerStyle::Arrow;
2265 if ( aHitTest.bSize )
2267 if ( mnWinStyle & WB_HORZ )
2268 aPtr = PointerStyle::ESize;
2269 else
2270 aPtr = PointerStyle::SSize;
2272 else if ( aHitTest.bSizeBar )
2274 if ( mnWinStyle & WB_HORZ )
2275 aPtr = PointerStyle::HSizeBar;
2276 else
2277 aPtr = PointerStyle::VSizeBar;
2279 SetPointer( aPtr );
2280 return ImplStartDrag( &aHitTest, nMouseModifier );
2283 else if ( nMouseClicks == 2 )
2285 if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) )
2287 mnDragPos = aHitTest.nPos;
2288 mnDragAryPos = aHitTest.nAryPos;
2291 DoubleClick();
2293 mnDragPos = 0;
2294 mnDragAryPos = 0;
2296 return true;
2300 return false;
2303 void Ruler::CancelDrag()
2305 if ( mbDrag )
2307 ImplDrag( Point( -1, -1 ) );
2308 ImplEndDrag();
2312 RulerType Ruler::GetType( const Point& rPos, sal_uInt16* pAryPos )
2314 RulerSelection aHitTest;
2316 // update ruler
2317 if ( IsReallyVisible() && mbFormat )
2319 Invalidate(InvalidateFlags::NoErase);
2322 (void)ImplHitTest(rPos, &aHitTest);
2324 // return values
2325 if ( pAryPos )
2326 *pAryPos = aHitTest.nAryPos;
2327 return aHitTest.eType;
2330 void Ruler::SetWinPos( tools::Long nNewOff, tools::Long nNewWidth )
2332 // should widths be automatically calculated
2333 if ( !nNewWidth )
2334 mbAutoWinWidth = true;
2335 else
2336 mbAutoWinWidth = false;
2338 mnWinOff = nNewOff;
2339 mnWinWidth = nNewWidth;
2340 ImplUpdate( true );
2343 void Ruler::SetPagePos( tools::Long nNewOff, tools::Long nNewWidth )
2345 // should we do anything?
2346 if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) )
2347 return;
2349 // should widths be automatically calculated
2350 if ( !nNewWidth )
2351 mpData->bAutoPageWidth = true;
2352 else
2353 mpData->bAutoPageWidth = false;
2355 mpData->nPageOff = nNewOff;
2356 mpData->nPageWidth = nNewWidth;
2357 ImplUpdate( true );
2360 void Ruler::SetBorderPos( tools::Long nOff )
2362 if ( mnWinStyle & WB_BORDER )
2364 if ( mnBorderOff != nOff )
2366 mnBorderOff = nOff;
2368 if ( IsReallyVisible() && IsUpdateMode() )
2369 Invalidate(InvalidateFlags::NoErase);
2374 void Ruler::SetUnit( FieldUnit eNewUnit )
2376 if ( meUnit == eNewUnit )
2377 return;
2379 meUnit = eNewUnit;
2380 switch ( meUnit )
2382 case FieldUnit::MM:
2383 mnUnitIndex = RULER_UNIT_MM;
2384 break;
2385 case FieldUnit::CM:
2386 mnUnitIndex = RULER_UNIT_CM;
2387 break;
2388 case FieldUnit::M:
2389 mnUnitIndex = RULER_UNIT_M;
2390 break;
2391 case FieldUnit::KM:
2392 mnUnitIndex = RULER_UNIT_KM;
2393 break;
2394 case FieldUnit::INCH:
2395 mnUnitIndex = RULER_UNIT_INCH;
2396 break;
2397 case FieldUnit::FOOT:
2398 mnUnitIndex = RULER_UNIT_FOOT;
2399 break;
2400 case FieldUnit::MILE:
2401 mnUnitIndex = RULER_UNIT_MILE;
2402 break;
2403 case FieldUnit::POINT:
2404 mnUnitIndex = RULER_UNIT_POINT;
2405 break;
2406 case FieldUnit::PICA:
2407 mnUnitIndex = RULER_UNIT_PICA;
2408 break;
2409 case FieldUnit::CHAR:
2410 mnUnitIndex = RULER_UNIT_CHAR;
2411 break;
2412 case FieldUnit::LINE:
2413 mnUnitIndex = RULER_UNIT_LINE;
2414 break;
2415 default:
2416 SAL_WARN( "svtools.control", "Ruler::SetUnit() - Wrong Unit" );
2417 break;
2420 maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit );
2421 ImplUpdate();
2424 void Ruler::SetZoom( const Fraction& rNewZoom )
2426 DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" );
2428 if ( maZoom != rNewZoom )
2430 maZoom = rNewZoom;
2431 maMapMode.SetScaleX( maZoom );
2432 maMapMode.SetScaleY( maZoom );
2433 ImplUpdate();
2437 void Ruler::SetExtraType( RulerExtra eNewExtraType, sal_uInt16 nStyle )
2439 if ( mnWinStyle & WB_EXTRAFIELD )
2441 meExtraType = eNewExtraType;
2442 mnExtraStyle = nStyle;
2443 if (IsReallyVisible() && IsUpdateMode())
2444 Invalidate();
2448 void Ruler::SetNullOffset( tools::Long nPos )
2450 if ( mpData->nNullOff != nPos )
2452 mpData->nNullVirOff += nPos - mpData->nNullOff;
2453 mpData->nNullOff = nPos;
2454 ImplUpdate();
2458 void Ruler::SetLeftFrameMargin( tools::Long nPos )
2460 if ( mpData->nLeftFrameMargin != nPos )
2462 mpData->nLeftFrameMargin = nPos;
2463 ImplUpdate();
2467 void Ruler::SetRightFrameMargin( tools::Long nPos )
2469 if ( mpData->nRightFrameMargin != nPos )
2471 mpData->nRightFrameMargin = nPos;
2472 ImplUpdate();
2476 void Ruler::SetMargin1( tools::Long nPos, RulerMarginStyle nMarginStyle )
2478 if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) )
2480 mpData->nMargin1 = nPos;
2481 mpData->nMargin1Style = nMarginStyle;
2482 ImplUpdate();
2486 void Ruler::SetMargin2( tools::Long nPos, RulerMarginStyle nMarginStyle )
2488 DBG_ASSERT( (nPos >= mpData->nMargin1) ||
2489 (mpData->nMargin1Style & RulerMarginStyle::Invisible) ||
2490 (mpData->nMargin2Style & RulerMarginStyle::Invisible),
2491 "Ruler::SetMargin2() - Margin2 < Margin1" );
2493 if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) )
2495 mpData->nMargin2 = nPos;
2496 mpData->nMargin2Style = nMarginStyle;
2497 ImplUpdate();
2501 void Ruler::SetLines( sal_uInt32 aLineArraySize, const RulerLine* pLineArray )
2503 // To determine if what has changed
2504 if ( mpData->pLines.size() == aLineArraySize )
2506 sal_uInt32 i = aLineArraySize;
2507 vector<RulerLine>::const_iterator aItr1 = mpData->pLines.begin();
2508 const RulerLine* pAry2 = pLineArray;
2509 while ( i )
2511 if ( aItr1->nPos != pAry2->nPos )
2512 break;
2513 ++aItr1;
2514 ++pAry2;
2515 i--;
2517 if ( !i )
2518 return;
2521 // New values and new share issue
2522 bool bMustUpdate;
2523 bMustUpdate = IsReallyVisible() && IsUpdateMode();
2525 // Delete old lines
2526 if ( bMustUpdate )
2527 Invalidate(InvalidateFlags::NoErase);
2529 // New data set
2530 if ( !aLineArraySize || !pLineArray )
2532 if ( mpData->pLines.empty() )
2533 return;
2534 mpData->pLines.clear();
2536 else
2538 if ( mpData->pLines.size() != aLineArraySize )
2540 mpData->pLines.resize(aLineArraySize);
2543 std::copy( pLineArray,
2544 pLineArray + aLineArraySize,
2545 mpData->pLines.begin() );
2547 if ( bMustUpdate )
2548 Invalidate(InvalidateFlags::NoErase);
2552 void Ruler::SetBorders( sal_uInt32 aBorderArraySize, const RulerBorder* pBorderArray )
2554 if ( !aBorderArraySize || !pBorderArray )
2556 if ( mpData->pBorders.empty() )
2557 return;
2558 mpData->pBorders.clear();
2560 else
2562 if ( mpData->pBorders.size() != aBorderArraySize )
2564 mpData->pBorders.resize(aBorderArraySize);
2566 else
2568 sal_uInt32 i = aBorderArraySize;
2569 const RulerBorder* pAry1 = mpData->pBorders.data();
2570 const RulerBorder* pAry2 = pBorderArray;
2571 while ( i )
2573 if ( (pAry1->nPos != pAry2->nPos) ||
2574 (pAry1->nWidth != pAry2->nWidth) ||
2575 (pAry1->nStyle != pAry2->nStyle) )
2576 break;
2577 pAry1++;
2578 pAry2++;
2579 i--;
2581 if ( !i )
2582 return;
2584 std::copy( pBorderArray,
2585 pBorderArray + aBorderArraySize,
2586 mpData->pBorders.begin() );
2589 ImplUpdate();
2592 void Ruler::SetIndents( sal_uInt32 aIndentArraySize, const RulerIndent* pIndentArray )
2595 if ( !aIndentArraySize || !pIndentArray )
2597 if ( mpData->pIndents.empty() )
2598 return;
2599 mpData->pIndents.clear();
2601 else
2603 if ( mpData->pIndents.size() != aIndentArraySize )
2605 mpData->pIndents.resize(aIndentArraySize);
2607 else
2609 sal_uInt32 i = aIndentArraySize;
2610 const RulerIndent* pAry1 = mpData->pIndents.data();
2611 const RulerIndent* pAry2 = pIndentArray;
2612 while ( i )
2614 if ( (pAry1->nPos != pAry2->nPos) ||
2615 (pAry1->nStyle != pAry2->nStyle) )
2616 break;
2617 pAry1++;
2618 pAry2++;
2619 i--;
2621 if ( !i )
2622 return;
2625 std::copy( pIndentArray,
2626 pIndentArray + aIndentArraySize,
2627 mpData->pIndents.begin() );
2630 ImplUpdate();
2633 void Ruler::SetTabs( sal_uInt32 aTabArraySize, const RulerTab* pTabArray )
2635 if ( aTabArraySize == 0 || pTabArray == nullptr )
2637 if ( mpData->pTabs.empty() )
2638 return;
2639 mpData->pTabs.clear();
2641 else
2643 if ( mpData->pTabs.size() != aTabArraySize )
2645 mpData->pTabs.resize(aTabArraySize);
2647 else
2649 sal_uInt32 i = aTabArraySize;
2650 vector<RulerTab>::iterator aTabIterator = mpData->pTabs.begin();
2651 const RulerTab* pInputArray = pTabArray;
2652 while ( i )
2654 RulerTab& aCurrent = *aTabIterator;
2655 if ( aCurrent.nPos != pInputArray->nPos ||
2656 aCurrent.nStyle != pInputArray->nStyle )
2658 break;
2660 ++aTabIterator;
2661 pInputArray++;
2662 i--;
2664 if ( !i )
2665 return;
2667 std::copy(pTabArray, pTabArray + aTabArraySize, mpData->pTabs.begin());
2670 ImplUpdate();
2673 const std::vector<RulerTab>& Ruler::GetTabs() const
2675 return mpData->pTabs;
2678 void Ruler::SetStyle( WinBits nStyle )
2680 if ( mnWinStyle != nStyle )
2682 mnWinStyle = nStyle;
2683 ImplInitExtraField( true );
2687 void Ruler::DrawTab(vcl::RenderContext& rRenderContext, const Color &rFillColor, const Point& rPos, sal_uInt16 nStyle)
2689 Point aPos(rPos);
2690 sal_uInt16 nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL);
2692 rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
2693 rRenderContext.SetLineColor();
2694 rRenderContext.SetFillColor(rFillColor);
2695 ImplCenterTabPos(aPos, nTabStyle);
2696 ImplDrawRulerTab(rRenderContext, aPos, nTabStyle, nStyle);
2697 rRenderContext.Pop();
2700 void Ruler::SetTextRTL(bool bRTL)
2702 if(mpData->bTextRTL != bRTL)
2704 mpData->bTextRTL = bRTL;
2705 if ( IsReallyVisible() && IsUpdateMode() )
2706 ImplInitExtraField( true );
2711 tools::Long Ruler::GetPageOffset() const
2713 return mpData->nPageOff;
2716 tools::Long Ruler::GetNullOffset() const
2718 return mpData->nNullOff;
2721 tools::Long Ruler::GetMargin1() const
2723 return mpData->nMargin1;
2726 tools::Long Ruler::GetMargin2() const
2728 return mpData->nMargin2;
2732 bool Ruler::GetTextRTL() const
2734 return mpData->bTextRTL;
2737 const RulerUnitData& Ruler::GetCurrentRulerUnit() const
2739 return aImplRulerUnitTab[mnUnitIndex];
2742 void Ruler::DrawTicks()
2744 mbFormat = true;
2745 Invalidate(InvalidateFlags::NoErase);
2748 uno::Reference< XAccessible > Ruler::CreateAccessible()
2750 vcl::Window* pParent = GetAccessibleParentWindow();
2751 OSL_ENSURE( pParent, "-SvxRuler::CreateAccessible(): No Parent!" );
2752 uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
2753 if( xAccParent.is() )
2755 // MT: Fixed compiler issue because the address from a temporary object was used.
2756 // BUT: Should it really be a Pointer, instead of const&???
2757 OUString aStr;
2758 if ( mnWinStyle & WB_HORZ )
2760 aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME);
2762 else
2764 aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME);
2766 mxAccContext = new SvtRulerAccessible( xAccParent, *this, aStr );
2767 SetAccessible(mxAccContext.get());
2768 return mxAccContext.get();
2770 else
2771 return uno::Reference< XAccessible >();
2774 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */