xref: /core/svtools/source/control/ruler.cxx (revision b285cf49)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
28 
29 #include <svtools/ruler.hxx>
30 #include <svtools/svtresid.hxx>
31 #include <svtools/strings.hrc>
32 #include <svtools/colorcfg.hxx>
33 #include "accessibleruler.hxx"
34 
35 #include <memory>
36 #include <vector>
37 
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::accessibility;
41 
42 #define RULER_OFF           3
43 #define RULER_RESIZE_OFF    4
44 #define RULER_MIN_SIZE      3
45 
46 #define RULER_VAR_SIZE      8
47 
48 #define RULER_UPDATE_LINES  0x01
49 
50 #define RULER_CLIP          150
51 
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
64 
65 namespace
66 {
67 /**
68  * Pre-calculates glyph items for rText on rRenderContext. Subsequent calls
69  * avoid the calculation and just return a pointer to rTextGlyphs.
70  */
lcl_GetRulerTextGlyphs(const vcl::RenderContext & rRenderContext,const OUString & rText,SalLayoutGlyphs & rTextGlyphs)71 SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext, const OUString& rText,
72                                         SalLayoutGlyphs& rTextGlyphs)
73 {
74     if (rTextGlyphs.IsValid())
75         // Use pre-calculated result.
76         return &rTextGlyphs;
77 
78     // Calculate glyph items.
79 
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;
84 
85     // Remember the calculation result.
86     rTextGlyphs = pLayout->GetGlyphs();
87 
88     return &rTextGlyphs;
89 }
90 }
91 
92 class ImplRulerData
93 {
94     friend class Ruler;
95 
96 private:
97     std::vector<RulerLine>    pLines;
98     std::vector<RulerBorder>  pBorders;
99     std::vector<RulerIndent>  pIndents;
100     std::vector<RulerTab>     pTabs;
101 
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;
117 
118 public:
119     ImplRulerData();
120 };
121 
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)
137 {
138 }
139 
140 const RulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] =
141 {
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
153 };
154 
155 static RulerTabData ruler_tab =
156 {
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
173 };
174 
ImplInit(WinBits nWinBits)175 void Ruler::ImplInit( WinBits nWinBits )
176 {
177     // Set default WinBits
178     if ( !(nWinBits & WB_VERT) )
179     {
180         nWinBits |= WB_HORZ;
181 
182         // RTL: no UI mirroring for horizontal rulers, because
183         // the document is also not mirrored
184         EnableRTL( false );
185     }
186 
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
215 
216     // Initialize Units
217     mnUnitIndex     = RULER_UNIT_CM;
218     meUnit          = FieldUnit::CM;
219     maZoom          = Fraction( 1, 1 );
220 
221     // Recalculate border widths
222     if ( nWinBits & WB_BORDER )
223         mnBorderWidth = 1;
224     else
225         mnBorderWidth = 0;
226 
227     // Settings
228     ImplInitSettings( true, true, true );
229 
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;
234 
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);
242 }
243 
Ruler(vcl::Window * pParent,WinBits nWinStyle)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)
251 {
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)
256     {
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;
273     }
274 
275 
276     ImplInit( nWinStyle );
277 }
278 
~Ruler()279 Ruler::~Ruler()
280 {
281     disposeOnce();
282 }
283 
dispose()284 void Ruler::dispose()
285 {
286     mpSaveData.reset();
287     mpDragData.reset();
288     mxAccContext.clear();
289     Window::dispose();
290 }
291 
ImplVDrawLine(vcl::RenderContext & rRenderContext,tools::Long nX1,tools::Long nY1,tools::Long nX2,tools::Long nY2)292 void Ruler::ImplVDrawLine(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
293 {
294     if ( nX1 < -RULER_CLIP )
295     {
296         nX1 = -RULER_CLIP;
297         if ( nX2 < -RULER_CLIP )
298             return;
299     }
300     tools::Long nClip = mnVirWidth + RULER_CLIP;
301     if ( nX2 > nClip )
302     {
303         nX2 = nClip;
304         if ( nX1 > nClip )
305             return;
306     }
307 
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 ) );
312 }
313 
ImplVDrawRect(vcl::RenderContext & rRenderContext,tools::Long nX1,tools::Long nY1,tools::Long nX2,tools::Long nY2)314 void Ruler::ImplVDrawRect(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
315 {
316     if ( nX1 < -RULER_CLIP )
317     {
318         nX1 = -RULER_CLIP;
319         if ( nX2 < -RULER_CLIP )
320             return;
321     }
322     tools::Long nClip = mnVirWidth + RULER_CLIP;
323     if ( nX2 > nClip )
324     {
325         nX2 = nClip;
326         if ( nX1 > nClip )
327             return;
328     }
329 
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));
334 }
335 
ImplVDrawText(vcl::RenderContext & rRenderContext,tools::Long nX,tools::Long nY,const OUString & rText,tools::Long nMin,tools::Long nMax)336 void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, tools::Long nY, const OUString& rText, tools::Long nMin, tools::Long nMax)
337 {
338     tools::Rectangle aRect;
339     SalLayoutGlyphs* pTextLayout
340         = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]);
341     rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, {}, {}, pTextLayout);
342 
343     tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left();
344     tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top();
345 
346     if ( (nX > -RULER_CLIP) && (nX < mnVirWidth + RULER_CLIP) && ( nX < nMax - nShiftX ) && ( nX > nMin + nShiftX ) )
347     {
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);
354     }
355 }
356 
ImplInvertLines(vcl::RenderContext & rRenderContext)357 void Ruler::ImplInvertLines(vcl::RenderContext& rRenderContext)
358 {
359     // Position lines
360     if (mpData->pLines.empty() || !mbActive || mbDrag || mbFormat || (mnUpdateFlags & RULER_UPDATE_LINES) )
361         return;
362 
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;
367 
368     // Calculate rectangle
369     tools::Rectangle aRect;
370     if (mnWinStyle & WB_HORZ)
371         aRect.SetBottom( nY );
372     else
373         aRect.SetRight( nY );
374 
375     // Draw lines
376     for (const RulerLine & rLine : mpData->pLines)
377     {
378         const tools::Long n = rLine.nPos + nNullWinOff;
379         if ((n >= nRulX1) && (n < nRulX2))
380         {
381             if (mnWinStyle & WB_HORZ )
382             {
383                 aRect.SetLeft( n );
384                 aRect.SetRight( n );
385             }
386             else
387             {
388                 aRect.SetTop( n );
389                 aRect.SetBottom( n );
390             }
391             tools::Rectangle aTempRect = aRect;
392 
393             if (mnWinStyle & WB_HORZ)
394                 aTempRect.SetBottom( RULER_OFF - 1 );
395             else
396                 aTempRect.SetRight( RULER_OFF - 1 );
397 
398             rRenderContext.Erase(aTempRect);
399 
400             if (mnWinStyle & WB_HORZ)
401             {
402                 aTempRect.SetBottom( aRect.Bottom() );
403                 aTempRect.SetTop( aTempRect.Bottom() - RULER_OFF + 1 );
404             }
405             else
406             {
407                 aTempRect.SetRight( aRect.Right() );
408                 aTempRect.SetLeft( aTempRect.Right() - RULER_OFF + 1 );
409             }
410             rRenderContext.Erase(aTempRect);
411             GetOutDev()->Invert(aRect);
412         }
413     }
414     mnUpdateFlags = 0;
415 }
416 
ImplDrawTicks(vcl::RenderContext & rRenderContext,tools::Long nMin,tools::Long nMax,tools::Long nStart,tools::Long nTop,tools::Long nBottom)417 void Ruler::ImplDrawTicks(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nStart, tools::Long nTop, tools::Long nBottom)
418 {
419     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
420     double nCenter = nTop + ((nBottom - nTop) / 2);
421 
422     tools::Long nTickLength3 = (nBottom - nTop) * 0.5;
423     tools::Long nTickLength2 = nTickLength3 * 0.66;
424     tools::Long nTickLength1 = nTickLength2 * 0.66;
425 
426     tools::Long nScale = ruler_tab.DPIScaleFactor;
427     tools::Long DPIOffset = nScale - 1;
428 
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;
435 
436     Size aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
437 
438     if (mnUnitIndex == RULER_UNIT_CHAR)
439     {
440         if (mnCharWidth == 0)
441             mnCharWidth = 371;
442         nTick4 = mnCharWidth * 2;
443         nTick2 = mnCharWidth;
444         nTickCount = mnCharWidth;
445         nTickUnit = mnCharWidth;
446     }
447     else if (mnUnitIndex == RULER_UNIT_LINE)
448     {
449         if (mnLineHeight == 0)
450             mnLineHeight = 551;
451         nTick4 = mnLineHeight * 2;
452         nTick2 = mnLineHeight;
453         nTickUnit = mnLineHeight;
454         nTickCount = mnLineHeight;
455     }
456 
457     if (mnWinStyle & WB_HORZ)
458     {
459         nTickWidth = aPixSize.Width();
460     }
461     else
462     {
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();
470     }
471 
472     tools::Long nMaxWidth = rRenderContext.PixelToLogic(Size(mpData->nPageWidth, 0), maMapMode).Width();
473     if (nMaxWidth < 0)
474         nMaxWidth = -nMaxWidth;
475 
476     if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
477         nMaxWidth /= nTickUnit;
478     else
479         nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit;
480 
481     OUString aNumString = OUString::number(nMaxWidth);
482     tools::Long nTxtWidth = rRenderContext.GetTextWidth( aNumString );
483     const tools::Long nTextOff = 4;
484 
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)
489     {
490         // Calculate the scale of the ruler
491         tools::Long nMulti = 1;
492         tools::Long nOrgTick4 = nTick4;
493 
494         while (nTickWidth < nTxtWidth + nTextOff)
495         {
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;
507 
508             // Overflow - in this case don't draw ticks and exit
509             if (nMulti < nOldMulti)
510             {
511                 bNoTicks = true;
512                 break;
513             }
514 
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();
521         }
522         nTickCount = nTick4;
523     }
524     else
525     {
526         rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
527     }
528 
529     if (bNoTicks)
530         return;
531 
532     tools::Long n = 0;
533     double nTick = 0.0;
534     double nTick3 = 0;
535 
536     if ((mnUnitIndex != RULER_UNIT_CHAR) && (mnUnitIndex != RULER_UNIT_LINE))
537     {
538         nTick2 = aImplRulerUnitTab[mnUnitIndex].nTick2;
539         nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3;
540     }
541 
542     Size nTickGapSize;
543 
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();
550 
551     while (((nStart - n) >= nMin) || ((nStart + n) <= nMax))
552     {
553         // Null point
554         if (nTick == 0.0)
555         {
556             if (nStart > nMin)
557             {
558                 // 0 is only painted when Margin1 is not equal to zero
559                 if ((mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin1 != 0))
560                 {
561                     aNumString = "0";
562                     ImplVDrawText(rRenderContext, nStart, nCenter, aNumString);
563                 }
564             }
565         }
566         else
567         {
568             aPixSize = rRenderContext.LogicToPixel(Size(nTick, nTick), maMapMode);
569 
570             if (mnWinStyle & WB_HORZ)
571                 n = aPixSize.Width();
572             else
573                 n = aPixSize.Height();
574 
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());
580 
581             if (aRest < nAcceptanceDelta)
582             {
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);
587 
588                 tools::Long nHorizontalLocation = nStart + n;
589                 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
590 
591                 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
592                 {
593                     ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom - 1 * nScale, nHorizontalLocation + DPIOffset, nBottom);
594                     ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop, nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
595                 }
596 
597                 nHorizontalLocation = nStart - n;
598                 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
599 
600                 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
601                 {
602                     ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom,
603                                                   nHorizontalLocation + DPIOffset, nBottom - 1 * nScale);
604                     ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop,
605                                                   nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
606                 }
607             }
608             // Tick/Tick2 - Output (Strokes)
609             else
610             {
611                 tools::Long nTickLength = nTickLength1;
612 
613                 aStep = (nTick / nTick2);
614                 aRest = std::abs(aStep - std::floor(aStep));
615                 if (aRest < nAcceptanceDelta)
616                     nTickLength = nTickLength2;
617 
618                 aStep = (nTick / nTick3);
619                 aRest = std::abs(aStep - std::floor(aStep));
620                 if (aRest < nAcceptanceDelta )
621                     nTickLength = nTickLength3;
622 
623                 if ((nTickLength == nTickLength1 && nTickGap1 > 6) ||
624                     (nTickLength == nTickLength2 && nTickGap2 > 6) ||
625                     (nTickLength == nTickLength3 && nTickGap3 > 6))
626                 {
627                     tools::Long nT1 = nCenter - (nTickLength / 2.0);
628                     tools::Long nT2 = nT1 + nTickLength - 1;
629                     tools::Long nT;
630 
631                     nT = nStart + n;
632 
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);
638                 }
639             }
640         }
641         nTick += nTickCount;
642     }
643 }
644 
ImplDrawBorders(vcl::RenderContext & rRenderContext,tools::Long nMin,tools::Long nMax,tools::Long nVirTop,tools::Long nVirBottom)645 void Ruler::ImplDrawBorders(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
646 {
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;
653 
654     for (std::vector<RulerBorder>::size_type i = 0; i < mpData->pBorders.size(); i++)
655     {
656         if (mpData->pBorders[i].nStyle & RulerBorderStyle::Invisible)
657             continue;
658 
659         n1 = mpData->pBorders[i].nPos + mpData->nNullVirOff;
660         n2 = n1 + mpData->pBorders[i].nWidth;
661 
662         if (((n1 >= nMin) && (n1 <= nMax)) || ((n2 >= nMin) && (n2 <= nMax)))
663         {
664             if ((n2 - n1) > 3)
665             {
666                 rRenderContext.SetLineColor();
667                 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
668                 ImplVDrawRect(rRenderContext, n1, nVirTop, n2, nVirBottom);
669 
670                 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
671                 ImplVDrawLine(rRenderContext, n1 + 1, nVirTop, n1 + 1, nVirBottom);
672                 ImplVDrawLine(rRenderContext, n1,     nVirTop, n2,     nVirTop);
673 
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);
678 
679                 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
680                 ImplVDrawLine(rRenderContext, n2, nVirTop, n2, nVirBottom);
681 
682                 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Variable)
683                 {
684                     if (n2 - n1 > RULER_VAR_SIZE + 4)
685                     {
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;
691 
692                         rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
693                         while (nTempY <= nTemp4)
694                         {
695                             ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
696                             nTempY += 2;
697                         }
698 
699                         nTempY = nTemp2 + 1;
700                         rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
701                         while (nTempY <= nTemp4)
702                         {
703                             ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
704                             nTempY += 2;
705                         }
706                     }
707                 }
708 
709                 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Sizeable)
710                 {
711                     if (n2 - n1 > RULER_VAR_SIZE + 10)
712                     {
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);
719                     }
720                 }
721             }
722             else
723             {
724                 n = n1 + ((n2 - n1) / 2);
725                 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
726 
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);
732             }
733         }
734     }
735 }
736 
ImplDrawIndent(vcl::RenderContext & rRenderContext,const tools::Polygon & rPoly,bool bIsHit)737 void Ruler::ImplDrawIndent(vcl::RenderContext& rRenderContext, const tools::Polygon& rPoly, bool bIsHit)
738 {
739     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
740 
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);
746 }
747 
ImplDrawIndents(vcl::RenderContext & rRenderContext,tools::Long nMin,tools::Long nMax,tools::Long nVirTop,tools::Long nVirBottom)748 void Ruler::ImplDrawIndents(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
749 {
750     tools::Long n;
751     tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
752     tools::Long nIndentWidth2 = nIndentHeight-3;
753 
754     tools::Polygon aPoly(5);
755 
756     for (std::vector<RulerIndent>::size_type j = 0; j < mpData->pIndents.size(); j++)
757     {
758         if (mpData->pIndents[j].bInvisible)
759             continue;
760 
761         RulerIndentStyle nIndentStyle = mpData->pIndents[j].nStyle;
762 
763         n = mpData->pIndents[j].nPos+mpData->nNullVirOff;
764 
765         if ((n >= nMin) && (n <= nMax))
766         {
767             if (nIndentStyle == RulerIndentStyle::Bottom)
768             {
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);
774             }
775             else
776             {
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);
782             }
783 
784             if (0 == (mnWinStyle & WB_HORZ))
785             {
786                 Point aTmp;
787                 for (sal_uInt16 i = 0; i < 5; i++)
788                 {
789                     aTmp = aPoly[i];
790                     Point aSet(nVirBottom - aTmp.Y(), aTmp.X());
791                     aPoly[i] = aSet;
792                 }
793             }
794             bool bIsHit = false;
795             if (mxCurrentHitTest != nullptr && mxCurrentHitTest->eType == RulerType::Indent)
796             {
797                 bIsHit = mxCurrentHitTest->nAryPos == j;
798             }
799             else if(mbDrag && meDragType == RulerType::Indent)
800             {
801                 bIsHit = mnDragAryPos == j;
802             }
803             ImplDrawIndent(rRenderContext, aPoly, bIsHit);
804         }
805     }
806 }
807 
ImplCenterTabPos(Point & rPos,sal_uInt16 nTabStyle)808 static void ImplCenterTabPos(Point& rPos, sal_uInt16 nTabStyle)
809 {
810     bool bRTL  = 0 != (nTabStyle & RULER_TAB_RTL);
811     nTabStyle &= RULER_TAB_STYLE;
812     rPos.AdjustY(ruler_tab.height/2 );
813 
814     if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) ||
815          ( bRTL && nTabStyle == RULER_TAB_RIGHT) )
816     {
817         rPos.AdjustX( -(ruler_tab.width / 2) );
818     }
819     else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) ||
820               ( bRTL && nTabStyle == RULER_TAB_LEFT) )
821     {
822         rPos.AdjustX(ruler_tab.width / 2 );
823     }
824 }
825 
lcl_RotateRect_Impl(tools::Rectangle & rRect,const tools::Long nReference,bool bRightAligned)826 static void lcl_RotateRect_Impl(tools::Rectangle& rRect, const tools::Long nReference, bool bRightAligned)
827 {
828     if (rRect.IsEmpty())
829         return;
830 
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() );
836 
837     if (bRightAligned)
838     {
839         tools::Long nRef = 2 * nReference;
840         rRect.SetLeft( nRef - rRect.Left() );
841         rRect.SetRight( nRef - rRect.Right() );
842     }
843 }
844 
ImplDrawRulerTab(vcl::RenderContext & rRenderContext,const Point & rPos,sal_uInt16 nStyle,WinBits nWinBits)845 static void ImplDrawRulerTab(vcl::RenderContext& rRenderContext, const Point& rPos,
846                               sal_uInt16 nStyle, WinBits nWinBits)
847 {
848     if (nStyle & RULER_STYLE_INVISIBLE)
849         return;
850 
851     sal_uInt16 nTabStyle = nStyle & RULER_TAB_STYLE;
852     bool bRTL = 0 != (nStyle & RULER_TAB_RTL);
853 
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;
858 
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
863 
864     aRect3.SetEmpty();
865 
866     if (nTabStyle == RULER_TAB_DEFAULT)
867     {
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() );
872 
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() );
877 
878     }
879     else if ((!bRTL && nTabStyle == RULER_TAB_LEFT) || (bRTL && nTabStyle == RULER_TAB_RIGHT))
880     {
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() );
885 
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() );
890     }
891     else if ((!bRTL && nTabStyle == RULER_TAB_RIGHT) || (bRTL && nTabStyle == RULER_TAB_LEFT))
892     {
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() );
897 
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() );
902     }
903     else
904     {
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() );
909 
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() );
914 
915         if (nTabStyle == RULER_TAB_DECIMAL)
916         {
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 );
921         }
922     }
923     if (0 == (nWinBits & WB_HORZ))
924     {
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);
929     }
930     rRenderContext.DrawRect(aRect1);
931     rRenderContext.DrawRect(aRect2);
932 
933     if (!aRect3.IsEmpty())
934         rRenderContext.DrawRect(aRect3);
935 }
936 
ImplDrawTab(vcl::RenderContext & rRenderContext,const Point & rPos,sal_uInt16 nStyle)937 void Ruler::ImplDrawTab(vcl::RenderContext& rRenderContext, const Point& rPos, sal_uInt16 nStyle)
938 {
939     if (nStyle & RULER_STYLE_INVISIBLE)
940         return;
941 
942     rRenderContext.SetLineColor();
943 
944     if (nStyle & RULER_STYLE_DONTKNOW)
945         rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceColor());
946     else
947         rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor());
948 
949     if (mpData->bTextRTL)
950         nStyle |= RULER_TAB_RTL;
951 
952     ImplDrawRulerTab(rRenderContext, rPos, nStyle, GetStyle());
953 }
954 
ImplDrawTabs(vcl::RenderContext & rRenderContext,tools::Long nMin,tools::Long nMax,tools::Long nVirTop,tools::Long nVirBottom)955 void Ruler::ImplDrawTabs(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
956 {
957     for (const RulerTab & rTab : mpData->pTabs)
958     {
959         if (rTab.nStyle & RULER_STYLE_INVISIBLE)
960             continue;
961 
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);
968     }
969 }
970 
adjustSize(int nOrig)971 static int adjustSize(int nOrig)
972 {
973     if (nOrig <= 0)
974         return 0;
975 
976     // make sure we return an odd number, that looks better in the ruler
977     return ( (3*nOrig) / 8) * 2 + 1;
978 }
979 
ApplySettings(vcl::RenderContext & rRenderContext)980 void Ruler::ApplySettings(vcl::RenderContext& rRenderContext)
981 {
982     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
983 
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);
988 
989     ApplyControlFont(rRenderContext, aFont);
990 
991     ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
992     SetTextFillColor();
993 
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())
1000     {
1001         maVirDev->SetBackground(aColor);
1002         Resize();
1003     }
1004 }
1005 
ImplInitSettings(bool bFont,bool bForeground,bool bBackground)1006 void Ruler::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1007 {
1008     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1009 
1010     if (bFont)
1011     {
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);
1016 
1017         ApplyControlFont(*GetOutDev(), aFont);
1018     }
1019 
1020     if (bForeground || bFont)
1021     {
1022         ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
1023         SetTextFillColor();
1024     }
1025 
1026     if (bBackground)
1027     {
1028         Color aColor;
1029         svtools::ColorConfig aColorConfig;
1030         aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
1031         ApplyControlBackground(*GetOutDev(), aColor);
1032     }
1033 
1034     maVirDev->SetSettings( GetSettings() );
1035     maVirDev->SetBackground( GetBackground() );
1036     vcl::Font aFont = GetFont();
1037 
1038     if (mnWinStyle & WB_VERT)
1039         aFont.SetOrientation(900_deg10);
1040 
1041     maVirDev->SetFont(aFont);
1042     maVirDev->SetTextColor(GetTextColor());
1043     maVirDev->SetTextFillColor(GetTextFillColor());
1044 }
1045 
ImplCalc()1046 void Ruler::ImplCalc()
1047 {
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;
1055 
1056     // calculate non-visual part of the page
1057     tools::Long nNotVisPageWidth;
1058     if ( mpData->nPageOff < 0 )
1059     {
1060         nNotVisPageWidth = -(mpData->nPageOff);
1061         if ( nRulWinOff < mnWinOff )
1062             nNotVisPageWidth -= mnWinOff-nRulWinOff;
1063     }
1064     else
1065         nNotVisPageWidth = 0;
1066 
1067     // calculate width
1068     if ( mnWinStyle & WB_HORZ )
1069     {
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;
1077     }
1078     else
1079     {
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;
1087     }
1088 
1089     mbCalc = false;
1090 }
1091 
ImplFormat(vcl::RenderContext const & rRenderContext)1092 void Ruler::ImplFormat(vcl::RenderContext const & rRenderContext)
1093 {
1094     // if already formatted, don't do it again
1095     if (!mbFormat)
1096         return;
1097 
1098     // don't do anything if the window still has no size
1099     if (!mnVirWidth)
1100         return;
1101 
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
1112 
1113     // calculate values
1114     if (mbCalc)
1115         ImplCalc();
1116 
1117     mpData->nNullVirOff = mnWinOff + mpData->nPageOff + mpData->nNullOff - mnVirOff;
1118 
1119     nNullVirOff = mpData->nNullVirOff;
1120     nVirLeft    = mpData->nRulVirOff;
1121     nVirRight   = nVirLeft + mpData->nRulWidth - 1;
1122     nVirTop     = 0;
1123     nVirBottom  = mnVirHeight - 1;
1124 
1125     if (!IsReallyVisible())
1126         return;
1127 
1128     Size aVirDevSize;
1129 
1130     // initialize VirtualDevice
1131     if (mnWinStyle & WB_HORZ)
1132     {
1133         aVirDevSize.setWidth( mnVirWidth );
1134         aVirDevSize.setHeight( mnVirHeight );
1135     }
1136     else
1137     {
1138         aVirDevSize.setHeight( mnVirWidth );
1139         aVirDevSize.setWidth( mnVirHeight );
1140     }
1141     if (aVirDevSize != maVirDev->GetOutputSizePixel())
1142         maVirDev->SetOutputSizePixel(aVirDevSize);
1143     else
1144         maVirDev->Erase();
1145 
1146     // calculate margins
1147     if (!(mpData->nMargin1Style & RulerMarginStyle::Invisible))
1148     {
1149         nM1 = mpData->nMargin1 + nNullVirOff;
1150         if (mpData->bAutoPageWidth)
1151         {
1152             nP1 = nVirLeft;
1153             if (nM1 < nVirLeft)
1154                 nP1--;
1155         }
1156         else
1157             nP1 = nNullVirOff - mpData->nNullOff;
1158     }
1159     else
1160     {
1161         nM1 = nVirLeft-1;
1162         nP1 = nM1;
1163     }
1164     if (!(mpData->nMargin2Style & RulerMarginStyle::Invisible))
1165     {
1166         nM2 = mpData->nMargin2 + nNullVirOff;
1167         if (mpData->bAutoPageWidth)
1168         {
1169             nP2 = nVirRight;
1170             if (nM2 > nVirRight)
1171                 nP2++;
1172         }
1173         else
1174             nP2 = nNullVirOff - mpData->nNullOff + mpData->nPageWidth;
1175         if (nM2 > nP2)
1176             nM2 = nP2;
1177     }
1178     else
1179     {
1180         nM2 = nVirRight+1;
1181         nP2 = nM2;
1182     }
1183 
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
1188 
1189     nVirTop++;
1190     nVirBottom--;
1191 
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)
1200     {
1201         maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1202         ImplVDrawRect(*maVirDev, nM1 + 1, nVirTop, nM2 - 1, nVirBottom); //center rectangle
1203     }
1204     maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1205     if (nM1 > nVirLeft)
1206     {
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)
1210         {
1211             ImplVDrawLine(*maVirDev, nP1, nVirTop + 1, nP1,     nVirBottom); //left line of the left rectangle
1212             ImplVDrawLine(*maVirDev, nP1, nVirBottom,  nP1 + 1, nVirBottom); //?
1213         }
1214     }
1215     if (nM2 < nP2)
1216     {
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
1221     }
1222 
1223     tools::Long nMin = nVirLeft;
1224     tools::Long nMax = nP2;
1225     tools::Long nStart = 0;
1226 
1227     if (mpData->bTextRTL)
1228         nStart = mpData->nRightFrameMargin + nNullVirOff;
1229     else
1230         nStart = mpData->nLeftFrameMargin + nNullVirOff;
1231 
1232     if (nP1 > nVirLeft)
1233         nMin++;
1234 
1235     if (nP2 < nVirRight)
1236         nMax--;
1237 
1238     // Draw captions
1239     ImplDrawTicks(*maVirDev, nMin, nMax, nStart, nVirTop, nVirBottom);
1240 
1241     // Draw borders
1242     if (!mpData->pBorders.empty())
1243         ImplDrawBorders(*maVirDev, nVirLeft, nP2, nVirTop, nVirBottom);
1244 
1245     // Draw indents
1246     if (!mpData->pIndents.empty())
1247         ImplDrawIndents(*maVirDev, nVirLeft, nP2, nVirTop - 1, nVirBottom + 1);
1248 
1249     // Tabs
1250     if (!mpData->pTabs.empty())
1251         ImplDrawTabs(*maVirDev, nVirLeft, nP2, nVirTop-1, nVirBottom + 1);
1252 
1253     mbFormat = false;
1254 }
1255 
ImplInitExtraField(bool bUpdate)1256 void Ruler::ImplInitExtraField( bool bUpdate )
1257 {
1258     Size aWinSize = GetOutputSizePixel();
1259 
1260     // extra field evaluate
1261     if ( mnWinStyle & WB_EXTRAFIELD )
1262     {
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)
1268         {
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;
1274         }
1275         else
1276             mnVirOff = maExtraRect.Right()+1;
1277 
1278     }
1279     else
1280     {
1281         maExtraRect.SetEmpty();
1282         mnVirOff = 0;
1283     }
1284 
1285     // mnVirWidth depends on mnVirOff
1286     if ( (mnVirWidth > RULER_MIN_SIZE) ||
1287      ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) )
1288     {
1289         if ( mnWinStyle & WB_HORZ )
1290             mnVirWidth = aWinSize.Width()-mnVirOff;
1291         else
1292             mnVirWidth = aWinSize.Height()-mnVirOff;
1293 
1294         if ( mnVirWidth < RULER_MIN_SIZE )
1295             mnVirWidth = 0;
1296     }
1297 
1298     if ( bUpdate )
1299     {
1300         mbCalc      = true;
1301         mbFormat    = true;
1302         Invalidate();
1303     }
1304 }
1305 
ImplDraw(vcl::RenderContext & rRenderContext)1306 void Ruler::ImplDraw(vcl::RenderContext& rRenderContext)
1307 {
1308     if (mbFormat)
1309     {
1310         ImplFormat(rRenderContext);
1311     }
1312 
1313     if (!IsReallyVisible())
1314         return;
1315 
1316     // output the ruler to the virtual device
1317     Point aOffPos;
1318     Size aVirDevSize = maVirDev->GetOutputSizePixel();
1319 
1320     if (mnWinStyle & WB_HORZ)
1321     {
1322         aOffPos.setX( mnVirOff );
1323         if (mpData->bTextRTL)
1324             aVirDevSize.AdjustWidth( -(maExtraRect.GetWidth()) );
1325 
1326         aOffPos.setY( RULER_OFF );
1327     }
1328     else
1329     {
1330         aOffPos.setX( RULER_OFF );
1331         aOffPos.setY( mnVirOff );
1332     }
1333     rRenderContext.DrawOutDev(aOffPos, aVirDevSize, Point(), aVirDevSize, *maVirDev);
1334 
1335     // redraw positionlines
1336     ImplInvertLines(rRenderContext);
1337 }
1338 
ImplDrawExtra(vcl::RenderContext & rRenderContext)1339 void Ruler::ImplDrawExtra(vcl::RenderContext& rRenderContext)
1340 {
1341     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1342     tools::Rectangle aRect = maExtraRect;
1343     bool bEraseRect = false;
1344 
1345     aRect.AdjustLeft(2 );
1346     aRect.AdjustTop(2 );
1347     aRect.AdjustRight( -2 );
1348     aRect.AdjustBottom( -2 );
1349 
1350     if (mnExtraStyle & RULER_STYLE_HIGHLIGHT)
1351     {
1352         rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
1353         bEraseRect = true;
1354     }
1355 
1356     if (bEraseRect)
1357     {
1358         rRenderContext.SetLineColor();
1359         rRenderContext.DrawRect(aRect);
1360     }
1361 
1362     // output content
1363     if (meExtraType == RulerExtra::NullOffset)
1364     {
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));
1370     }
1371     else if (meExtraType == RulerExtra::Tab)
1372     {
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))
1381         {
1382             if ((nWinBits & WB_RIGHT_ALIGNED) != 0)
1383                 aDraw.setY( 2 * aCenter.Y() - aDraw.Y() );
1384 
1385             if (mpData->bTextRTL)
1386             {
1387                 tools::Long nTemp = aDraw.X();
1388                 aDraw.setX( aDraw.Y() );
1389                 aDraw.setY( nTemp );
1390             }
1391         }
1392         ImplDrawTab(rRenderContext, aDraw, nTabStyle);
1393     }
1394 }
1395 
ImplUpdate(bool bMustCalc)1396 void Ruler::ImplUpdate( bool bMustCalc )
1397 {
1398     // clear lines in this place so they aren't considered at recalculation
1399     if (!mbFormat)
1400         Invalidate(InvalidateFlags::NoErase);
1401 
1402     // set flags
1403     if (bMustCalc)
1404         mbCalc = true;
1405     mbFormat = true;
1406 
1407     // abort if we are dragging as drag-handler will update the ruler after drag is finished
1408     if (mbDrag)
1409         return;
1410 
1411     // otherwise trigger update
1412     if (IsReallyVisible() && IsUpdateMode())
1413     {
1414         Invalidate(InvalidateFlags::NoErase);
1415     }
1416 }
1417 
ImplDoHitTest(const Point & rPos,RulerSelection * pHitTest,bool bRequireStyle,RulerIndentStyle nRequiredStyle,tools::Long nTolerance) const1418 bool Ruler::ImplDoHitTest( const Point& rPos, RulerSelection* pHitTest,
1419                          bool bRequireStyle, RulerIndentStyle nRequiredStyle,
1420                          tools::Long nTolerance ) const
1421 {
1422     sal_Int32   i;
1423     sal_uInt16  nStyle;
1424     tools::Long        nHitBottom;
1425     tools::Long        nX;
1426     tools::Long        nY;
1427     tools::Long        n1;
1428 
1429     if ( !mbActive )
1430         return false;
1431 
1432     // determine positions
1433     bool bIsHori = 0 != (mnWinStyle & WB_HORZ);
1434     if ( bIsHori )
1435     {
1436         nX = rPos.X();
1437         nY = rPos.Y();
1438     }
1439     else
1440     {
1441         nX = rPos.Y();
1442         nY = rPos.X();
1443     }
1444     nHitBottom = mnVirHeight + (RULER_OFF * 2);
1445 
1446     // #i32608#
1447     pHitTest->nAryPos = 0;
1448     pHitTest->mnDragSize = RulerDragSize::Move;
1449     pHitTest->bSize = false;
1450     pHitTest->bSizeBar = false;
1451 
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;
1458 
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) )
1465     {
1466         pHitTest->nPos = 0;
1467         pHitTest->eType = RulerType::Outside;
1468         return false;
1469     }
1470 
1471     nX -= mpData->nNullVirOff;
1472     pHitTest->nPos  = nX;
1473     pHitTest->eType = RulerType::DontKnow;
1474 
1475     // first test the tabs
1476     tools::Rectangle aRect;
1477     if ( !mpData->pTabs.empty() )
1478     {
1479         aRect.SetBottom( nHitBottom );
1480         aRect.SetTop( aRect.Bottom() - ruler_tab.height - RULER_OFF );
1481 
1482         for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1483         {
1484             nStyle = mpData->pTabs[i].nStyle;
1485             if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1486             {
1487                 nStyle &= RULER_TAB_STYLE;
1488 
1489                 // default tabs are only shown (no action)
1490                 if ( nStyle != RULER_TAB_DEFAULT )
1491                 {
1492                     n1 = mpData->pTabs[i].nPos;
1493 
1494                     if ( nStyle == RULER_TAB_LEFT )
1495                     {
1496                         aRect.SetLeft( n1 );
1497                         aRect.SetRight( n1 + ruler_tab.width - 1 );
1498                     }
1499                     else if ( nStyle == RULER_TAB_RIGHT )
1500                     {
1501                         aRect.SetRight( n1 );
1502                         aRect.SetLeft( n1 - ruler_tab.width - 1 );
1503                     }
1504                     else
1505                     {
1506                         aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1507                         aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1508                     }
1509 
1510                     if ( aRect.Contains( Point( nX, nY ) ) )
1511                     {
1512                         pHitTest->eType   = RulerType::Tab;
1513                         pHitTest->nAryPos = i;
1514                         return true;
1515                     }
1516                 }
1517             }
1518         }
1519     }
1520 
1521     // Indents
1522     if ( !mpData->pIndents.empty() )
1523     {
1524         tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
1525         tools::Long nIndentWidth2 = nIndentHeight - 3;
1526 
1527         for ( i = mpData->pIndents.size(); i; i-- )
1528         {
1529             RulerIndentStyle nIndentStyle = mpData->pIndents[i-1].nStyle;
1530             if ( (! bRequireStyle || nIndentStyle == nRequiredStyle) &&
1531                  !mpData->pIndents[i-1].bInvisible )
1532             {
1533                 n1 = mpData->pIndents[i-1].nPos;
1534 
1535                 if ( (nIndentStyle == RulerIndentStyle::Bottom) != !bIsHori )
1536                 {
1537                     aRect.SetLeft( n1-nIndentWidth2 );
1538                     aRect.SetRight( n1+nIndentWidth2 );
1539                     aRect.SetTop( nHitBottom-nIndentHeight-RULER_OFF+1 );
1540                     aRect.SetBottom( nHitBottom );
1541                 }
1542                 else
1543                 {
1544                     aRect.SetLeft( n1-nIndentWidth2 );
1545                     aRect.SetRight( n1+nIndentWidth2 );
1546                     aRect.SetTop( 0 );
1547                     aRect.SetBottom( nIndentHeight+RULER_OFF-1 );
1548                 }
1549 
1550                 if ( aRect.Contains( Point( nX, nY ) ) )
1551                 {
1552                     pHitTest->eType     = RulerType::Indent;
1553                     pHitTest->nAryPos   = i-1;
1554                     return true;
1555                 }
1556             }
1557         }
1558     }
1559 
1560     // test the borders
1561     int nBorderTolerance = nTolerance;
1562     if(pHitTest->bExpandTest)
1563     {
1564         nBorderTolerance++;
1565     }
1566 
1567     for ( i = mpData->pBorders.size(); i; i-- )
1568     {
1569         n1 = mpData->pBorders[i-1].nPos;
1570         tools::Long n2 = n1 + mpData->pBorders[i-1].nWidth;
1571 
1572         // borders have at least 3 pixel padding
1573         if ( !mpData->pBorders[i-1].nWidth )
1574         {
1575              n1 -= nBorderTolerance;
1576              n2 += nBorderTolerance;
1577         }
1578 
1579         if ( (nX >= n1) && (nX <= n2) )
1580         {
1581             RulerBorderStyle nBorderStyle = mpData->pBorders[i-1].nStyle;
1582             if ( !(nBorderStyle & RulerBorderStyle::Invisible) )
1583             {
1584                 pHitTest->eType     = RulerType::Border;
1585                 pHitTest->nAryPos   = i-1;
1586 
1587                 if ( !(nBorderStyle & RulerBorderStyle::Sizeable) )
1588                 {
1589                     if ( nBorderStyle & RulerBorderStyle::Moveable )
1590                     {
1591                         pHitTest->bSizeBar = true;
1592                         pHitTest->mnDragSize = RulerDragSize::Move;
1593                     }
1594                 }
1595                 else
1596                 {
1597                     tools::Long nMOff = RULER_MOUSE_BORDERWIDTH;
1598                     while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) )
1599                     {
1600                         if ( nMOff < 2 )
1601                         {
1602                             nMOff = 0;
1603                             break;
1604                         }
1605                         else
1606                             nMOff--;
1607                     }
1608 
1609                     if ( nX <= n1+nMOff )
1610                     {
1611                         pHitTest->bSize = true;
1612                         pHitTest->mnDragSize = RulerDragSize::N1;
1613                     }
1614                     else if ( nX >= n2-nMOff )
1615                     {
1616                         pHitTest->bSize = true;
1617                         pHitTest->mnDragSize = RulerDragSize::N2;
1618                     }
1619                     else
1620                     {
1621                         if ( nBorderStyle & RulerBorderStyle::Moveable )
1622                         {
1623                             pHitTest->bSizeBar = true;
1624                             pHitTest->mnDragSize = RulerDragSize::Move;
1625                         }
1626                     }
1627                 }
1628 
1629                 return true;
1630             }
1631         }
1632     }
1633 
1634     // Margins
1635     int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH;
1636 
1637     if ( (mpData->nMargin1Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1638     {
1639         n1 = mpData->nMargin1;
1640         if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1641         {
1642             pHitTest->eType = RulerType::Margin1;
1643             pHitTest->bSize = true;
1644             return true;
1645         }
1646     }
1647     if ( (mpData->nMargin2Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1648     {
1649         n1 = mpData->nMargin2;
1650         if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1651         {
1652             pHitTest->eType = RulerType::Margin2;
1653             pHitTest->bSize = true;
1654             return true;
1655         }
1656     }
1657 
1658     // test tabs again
1659     if ( !mpData->pTabs.empty() )
1660     {
1661         aRect.SetTop( RULER_OFF );
1662         aRect.SetBottom( nHitBottom );
1663 
1664         for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1665         {
1666             nStyle = mpData->pTabs[i].nStyle;
1667             if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1668             {
1669                 nStyle &= RULER_TAB_STYLE;
1670 
1671                 // default tabs are only shown (no action)
1672                 if ( nStyle != RULER_TAB_DEFAULT )
1673                 {
1674                     n1 = mpData->pTabs[i].nPos;
1675 
1676                     if ( nStyle == RULER_TAB_LEFT )
1677                     {
1678                         aRect.SetLeft( n1 );
1679                         aRect.SetRight( n1 + ruler_tab.width - 1 );
1680                     }
1681                     else if ( nStyle == RULER_TAB_RIGHT )
1682                     {
1683                         aRect.SetRight( n1 );
1684                         aRect.SetLeft( n1 - ruler_tab.width - 1 );
1685                     }
1686                     else
1687                     {
1688                         aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1689                         aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1690                     }
1691 
1692                     aRect.AdjustLeft( -1 );
1693                     aRect.AdjustRight( 1 );
1694 
1695                     if ( aRect.Contains( Point( nX, nY ) ) )
1696                     {
1697                         pHitTest->eType   = RulerType::Tab;
1698                         pHitTest->nAryPos = i;
1699                         return true;
1700                     }
1701                 }
1702             }
1703         }
1704     }
1705 
1706     return false;
1707 }
1708 
ImplDocHitTest(const Point & rPos,RulerType eDragType,RulerSelection * pHitTest,tools::Long nTolerance) const1709 bool Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType,
1710                                 RulerSelection* pHitTest, tools::Long nTolerance ) const
1711 {
1712     Point aPos = rPos;
1713     bool bRequiredStyle = false;
1714     RulerIndentStyle nRequiredStyle = RulerIndentStyle::Top;
1715 
1716     if (eDragType == RulerType::Indent)
1717     {
1718         bRequiredStyle = true;
1719         nRequiredStyle = RulerIndentStyle::Bottom;
1720     }
1721 
1722     if ( mnWinStyle & WB_HORZ )
1723         aPos.AdjustX(mnWinOff );
1724     else
1725         aPos.AdjustY(mnWinOff );
1726 
1727     if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::DontKnow) )
1728     {
1729         if ( mnWinStyle & WB_HORZ )
1730             aPos.setY( RULER_OFF + 1 );
1731         else
1732             aPos.setX( RULER_OFF + 1 );
1733 
1734         if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle, nTolerance ) )
1735         {
1736             if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1737                 return true;
1738         }
1739     }
1740 
1741     if ( (eDragType == RulerType::Indent) ||
1742          (eDragType == RulerType::Tab) ||
1743          (eDragType == RulerType::DontKnow) )
1744     {
1745         if ( mnWinStyle & WB_HORZ )
1746             aPos.setY( mnHeight - RULER_OFF - 1 );
1747         else
1748             aPos.setX( mnWidth - RULER_OFF - 1 );
1749 
1750         if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle, nTolerance ) )
1751         {
1752             if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1753                 return true;
1754         }
1755     }
1756 
1757     if ( (eDragType == RulerType::Margin1) || (eDragType == RulerType::Margin2) ||
1758          (eDragType == RulerType::Border) || (eDragType == RulerType::DontKnow) )
1759     {
1760         if ( mnWinStyle & WB_HORZ )
1761             aPos.setY( RULER_OFF + (mnVirHeight / 2) );
1762         else
1763             aPos.setX( RULER_OFF + (mnVirHeight / 2) );
1764 
1765         if ( ImplDoHitTest( aPos, pHitTest, false, RulerIndentStyle::Top, nTolerance ) )
1766         {
1767             if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1768                 return true;
1769         }
1770     }
1771 
1772     pHitTest->eType = RulerType::DontKnow;
1773 
1774     return false;
1775 }
1776 
ImplStartDrag(RulerSelection const * pHitTest,sal_uInt16 nModifier)1777 bool Ruler::ImplStartDrag( RulerSelection const * pHitTest, sal_uInt16 nModifier )
1778 {
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;
1783 
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();
1792 
1793     // call handler
1794     if (StartDrag())
1795     {
1796         // if the handler allows dragging, initialize dragging
1797         mbDrag = true;
1798         mnStartDragPos = mnDragPos;
1799         StartTracking();
1800         Invalidate(InvalidateFlags::NoErase);
1801         return true;
1802     }
1803     else
1804     {
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();
1812     }
1813 
1814     return false;
1815 }
1816 
ImplDrag(const Point & rPos)1817 void Ruler::ImplDrag( const Point& rPos )
1818 {
1819     tools::Long  nX;
1820     tools::Long  nY;
1821     tools::Long  nOutHeight;
1822 
1823     if ( mnWinStyle & WB_HORZ )
1824     {
1825         nX          = rPos.X();
1826         nY          = rPos.Y();
1827         nOutHeight  = mnHeight;
1828     }
1829     else
1830     {
1831         nX          = rPos.Y();
1832         nY          = rPos.X();
1833         nOutHeight  = mnWidth;
1834     }
1835 
1836     // calculate and fit X
1837     nX -= mnVirOff;
1838     if ( nX < mpData->nRulVirOff )
1839     {
1840         nX = mpData->nRulVirOff;
1841     }
1842     else if ( nX > mpData->nRulVirOff+mpData->nRulWidth )
1843     {
1844         nX = mpData->nRulVirOff+mpData->nRulWidth;
1845     }
1846     nX -= mpData->nNullVirOff;
1847 
1848     // if upper or left from ruler, then consider old values
1849     mbDragDelete = false;
1850     if ( nY < 0 )
1851     {
1852         if ( !mbDragCanceled )
1853         {
1854             // reset the data
1855             mbDragCanceled = true;
1856             ImplRulerData aTempData = *mpDragData;
1857             *mpDragData = *mpSaveData;
1858             mbCalc = true;
1859             mbFormat = true;
1860 
1861             // call handler
1862             mnDragPos = mnStartDragPos;
1863             Drag();
1864 
1865             // and redraw
1866             Invalidate(InvalidateFlags::NoErase);
1867 
1868             // reset the data as before cancel
1869             *mpDragData = std::move(aTempData);
1870         }
1871     }
1872     else
1873     {
1874         mbDragCanceled = false;
1875 
1876         // +2, so the tabs are not cleared too quickly
1877         if ( nY > nOutHeight + 2 )
1878             mbDragDelete = true;
1879 
1880         mnDragPos = nX;
1881 
1882         // call handler
1883         Drag();
1884 
1885         // redraw
1886         if (mbFormat)
1887             Invalidate(InvalidateFlags::NoErase);
1888     }
1889 }
1890 
ImplEndDrag()1891 void Ruler::ImplEndDrag()
1892 {
1893     // get values
1894     if ( mbDragCanceled )
1895         *mpDragData = *mpSaveData;
1896     else
1897         *mpSaveData = *mpDragData;
1898 
1899     mpData = mpSaveData.get();
1900     mbDrag = false;
1901 
1902     // call handler
1903     EndDrag();
1904 
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;
1914 
1915     // redraw
1916     Invalidate(InvalidateFlags::NoErase);
1917 }
1918 
MouseButtonDown(const MouseEvent & rMEvt)1919 void Ruler::MouseButtonDown( const MouseEvent& rMEvt )
1920 {
1921     if ( !rMEvt.IsLeft() || IsTracking() )
1922         return;
1923 
1924     Point   aMousePos = rMEvt.GetPosPixel();
1925     sal_uInt16  nMouseClicks = rMEvt.GetClicks();
1926     sal_uInt16  nMouseModifier = rMEvt.GetModifier();
1927 
1928     // update ruler
1929     if ( mbFormat )
1930     {
1931         Invalidate(InvalidateFlags::NoErase);
1932     }
1933 
1934     if ( maExtraRect.Contains( aMousePos ) )
1935     {
1936         ExtraDown();
1937     }
1938     else
1939     {
1940         RulerSelection aHitTest;
1941         bool bHitTestResult = ImplDoHitTest(aMousePos, &aHitTest);
1942 
1943         if ( nMouseClicks == 1 )
1944         {
1945             if ( bHitTestResult )
1946             {
1947                 ImplStartDrag( &aHitTest, nMouseModifier );
1948             }
1949             else
1950             {
1951                 // calculate position inside of ruler area
1952                 if ( aHitTest.eType == RulerType::DontKnow )
1953                 {
1954                     mnDragPos = aHitTest.nPos;
1955                     Click();
1956                     mnDragPos = 0;
1957 
1958                     // call HitTest again as a click, for example, could set a new tab
1959                     if ( ImplDoHitTest(aMousePos, &aHitTest) )
1960                         ImplStartDrag(&aHitTest, nMouseModifier);
1961                 }
1962             }
1963         }
1964         else
1965         {
1966             if (bHitTestResult)
1967             {
1968                 mnDragPos    = aHitTest.nPos;
1969                 mnDragAryPos = aHitTest.nAryPos;
1970             }
1971             meDragType = aHitTest.eType;
1972 
1973             DoubleClick();
1974 
1975             meDragType      = RulerType::DontKnow;
1976             mnDragPos       = 0;
1977             mnDragAryPos    = 0;
1978         }
1979     }
1980 }
1981 
MouseMove(const MouseEvent & rMEvt)1982 void Ruler::MouseMove( const MouseEvent& rMEvt )
1983 {
1984     PointerStyle ePtrStyle = PointerStyle::Arrow;
1985 
1986     mxPreviousHitTest.swap(mxCurrentHitTest);
1987 
1988     mxCurrentHitTest.reset(new RulerSelection);
1989 
1990     maHoverSelection.eType = RulerType::DontKnow;
1991 
1992     if (ImplDoHitTest( rMEvt.GetPosPixel(), mxCurrentHitTest.get() ))
1993     {
1994         maHoverSelection = *mxCurrentHitTest;
1995 
1996         if (mxCurrentHitTest->bSize)
1997         {
1998             if (mnWinStyle & WB_HORZ)
1999             {
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;
2006             }
2007             else
2008             {
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;
2015             }
2016         }
2017         else if (mxCurrentHitTest->bSizeBar)
2018         {
2019             if (mnWinStyle & WB_HORZ)
2020                 ePtrStyle = PointerStyle::HSizeBar;
2021             else
2022                 ePtrStyle = PointerStyle::VSizeBar;
2023         }
2024     }
2025 
2026     if (mxPreviousHitTest != nullptr && mxPreviousHitTest->eType != mxCurrentHitTest->eType)
2027     {
2028         mbFormat = true;
2029     }
2030 
2031     SetPointer( ePtrStyle );
2032 
2033     if (mbFormat)
2034     {
2035         Invalidate(InvalidateFlags::NoErase);
2036     }
2037 }
2038 
Tracking(const TrackingEvent & rTEvt)2039 void Ruler::Tracking( const TrackingEvent& rTEvt )
2040 {
2041     if ( rTEvt.IsTrackingEnded() )
2042     {
2043         // reset the old state at cancel
2044         if ( rTEvt.IsTrackingCanceled() )
2045         {
2046             mbDragCanceled = true;
2047             mbFormat       = true;
2048         }
2049 
2050         ImplEndDrag();
2051     }
2052     else
2053         ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() );
2054 }
2055 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)2056 void Ruler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2057 {
2058     ImplDraw(rRenderContext);
2059 
2060     // consider extra field
2061     if (mnWinStyle & WB_EXTRAFIELD)
2062         ImplDrawExtra(rRenderContext);
2063 }
2064 
Resize()2065 void Ruler::Resize()
2066 {
2067     Size aWinSize = GetOutputSizePixel();
2068 
2069     tools::Long nNewHeight;
2070     if ( mnWinStyle & WB_HORZ )
2071     {
2072         if ( aWinSize.Height() != mnHeight )
2073             nNewHeight = aWinSize.Height();
2074         else
2075             nNewHeight = 0;
2076     }
2077     else
2078     {
2079         if ( aWinSize.Width() != mnWidth )
2080             nNewHeight = aWinSize.Width();
2081         else
2082             nNewHeight = 0;
2083     }
2084 
2085     mbFormat = true;
2086 
2087     // clear lines
2088     bool bVisible = IsReallyVisible();
2089     if ( bVisible && !mpData->pLines.empty() )
2090     {
2091         mnUpdateFlags |= RULER_UPDATE_LINES;
2092         Invalidate(InvalidateFlags::NoErase);
2093     }
2094 
2095     // recalculate some values if the height/width changes
2096     // extra field should always be updated
2097     ImplInitExtraField( mpData->bTextRTL );
2098     if ( nNewHeight )
2099     {
2100         mbCalc = true;
2101         mnVirHeight = nNewHeight - mnBorderWidth - ( RULER_OFF * 2 );
2102     }
2103     else
2104     {
2105         if ( mpData->bAutoPageWidth )
2106             ImplUpdate( true );
2107         else if ( mbAutoWinWidth )
2108             mbCalc = true;
2109     }
2110 
2111     // clear part of the border
2112     if ( bVisible )
2113     {
2114         if ( nNewHeight )
2115             Invalidate(InvalidateFlags::NoErase);
2116         else if ( mpData->bAutoPageWidth )
2117         {
2118             // only at AutoPageWidth do we need to redraw
2119             tools::Rectangle aRect;
2120 
2121             if ( mnWinStyle & WB_HORZ )
2122             {
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 );
2130             }
2131             else
2132             {
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 );
2140             }
2141 
2142             Invalidate(aRect, InvalidateFlags::NoErase);
2143         }
2144     }
2145 
2146     mnWidth  = aWinSize.Width();
2147     mnHeight = aWinSize.Height();
2148 }
2149 
StateChanged(StateChangedType nType)2150 void Ruler::StateChanged( StateChangedType nType )
2151 {
2152     Window::StateChanged( nType );
2153 
2154     if ( nType == StateChangedType::InitShow )
2155         Invalidate();
2156     else if ( nType == StateChangedType::UpdateMode )
2157     {
2158         if ( IsReallyVisible() && IsUpdateMode() )
2159             Invalidate();
2160     }
2161     else if ( (nType == StateChangedType::Zoom) ||
2162               (nType == StateChangedType::ControlFont) )
2163     {
2164         ImplInitSettings( true, false, false );
2165         Invalidate();
2166     }
2167     else if ( nType == StateChangedType::ControlForeground )
2168     {
2169         ImplInitSettings( false, true, false );
2170         Invalidate();
2171     }
2172     else if ( nType == StateChangedType::ControlBackground )
2173     {
2174         ImplInitSettings( false, false, true );
2175         Invalidate();
2176     }
2177 }
2178 
DataChanged(const DataChangedEvent & rDCEvt)2179 void Ruler::DataChanged( const DataChangedEvent& rDCEvt )
2180 {
2181     Window::DataChanged( rDCEvt );
2182 
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)) )
2188     {
2189         mbFormat = true;
2190         ImplInitSettings( true, true, true );
2191         Invalidate();
2192     }
2193 }
2194 
StartDrag()2195 bool Ruler::StartDrag()
2196 {
2197     return false;
2198 }
2199 
Drag()2200 void Ruler::Drag()
2201 {
2202 }
2203 
EndDrag()2204 void Ruler::EndDrag()
2205 {
2206 }
2207 
Click()2208 void Ruler::Click()
2209 {
2210 }
2211 
DoubleClick()2212 void Ruler::DoubleClick()
2213 {
2214     maDoubleClickHdl.Call( this );
2215 }
2216 
ExtraDown()2217 void Ruler::ExtraDown()
2218 {
2219 }
2220 
Activate()2221 void Ruler::Activate()
2222 {
2223     mbActive = true;
2224 
2225     // update positionlines - draw is delayed
2226     mnUpdateFlags |= RULER_UPDATE_LINES;
2227     Invalidate(InvalidateFlags::NoErase);
2228 }
2229 
Deactivate()2230 void Ruler::Deactivate()
2231 {
2232     // clear positionlines
2233     Invalidate(InvalidateFlags::NoErase);
2234 
2235     mbActive = false;
2236 }
2237 
StartDocDrag(const MouseEvent & rMEvt,RulerType eDragType,tools::Long nTolerance)2238 bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType, tools::Long nTolerance )
2239 {
2240     if ( !mbDrag )
2241     {
2242         Point          aMousePos = rMEvt.GetPosPixel();
2243         sal_uInt16     nMouseClicks = rMEvt.GetClicks();
2244         sal_uInt16     nMouseModifier = rMEvt.GetModifier();
2245         RulerSelection aHitTest;
2246 
2247         if(eDragType != RulerType::DontKnow)
2248             aHitTest.bExpandTest = true;
2249 
2250         // update ruler
2251         if ( mbFormat )
2252         {
2253             if (!IsReallyVisible())
2254             {
2255                 // set mpData for ImplDocHitTest()
2256                 ImplFormat(*GetOutDev());
2257             }
2258 
2259             Invalidate(InvalidateFlags::NoErase);
2260         }
2261 
2262         if ( nMouseClicks == 1 )
2263         {
2264             if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest, nTolerance ) )
2265             {
2266                 PointerStyle aPtr = PointerStyle::Arrow;
2267 
2268                 if ( aHitTest.bSize )
2269                 {
2270                     if ( mnWinStyle & WB_HORZ )
2271                         aPtr = PointerStyle::ESize;
2272                     else
2273                         aPtr = PointerStyle::SSize;
2274                 }
2275                 else if ( aHitTest.bSizeBar )
2276                 {
2277                     if ( mnWinStyle & WB_HORZ )
2278                         aPtr = PointerStyle::HSizeBar;
2279                     else
2280                         aPtr = PointerStyle::VSizeBar;
2281                 }
2282                 SetPointer( aPtr );
2283                 return ImplStartDrag( &aHitTest, nMouseModifier );
2284             }
2285         }
2286         else if ( nMouseClicks == 2 )
2287         {
2288             if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest, nTolerance ) )
2289             {
2290                 mnDragPos    = aHitTest.nPos;
2291                 mnDragAryPos = aHitTest.nAryPos;
2292             }
2293 
2294             DoubleClick();
2295 
2296             mnDragPos       = 0;
2297             mnDragAryPos    = 0;
2298 
2299             return true;
2300         }
2301     }
2302 
2303     return false;
2304 }
2305 
CancelDrag()2306 void Ruler::CancelDrag()
2307 {
2308     if ( mbDrag )
2309     {
2310         ImplDrag( Point( -1, -1 ) );
2311         ImplEndDrag();
2312     }
2313 }
2314 
GetRulerType(const Point & rPos,sal_uInt16 * pAryPos)2315 RulerType Ruler::GetRulerType( const Point& rPos, sal_uInt16* pAryPos )
2316 {
2317     RulerSelection aHitTest;
2318 
2319     // update ruler
2320     if ( IsReallyVisible() && mbFormat )
2321     {
2322         Invalidate(InvalidateFlags::NoErase);
2323     }
2324 
2325     (void)ImplDoHitTest(rPos, &aHitTest);
2326 
2327     // return values
2328     if ( pAryPos )
2329         *pAryPos = aHitTest.nAryPos;
2330     return aHitTest.eType;
2331 }
2332 
SetWinPos(tools::Long nNewOff,tools::Long nNewWidth)2333 void Ruler::SetWinPos( tools::Long nNewOff, tools::Long nNewWidth )
2334 {
2335     // should widths be automatically calculated
2336     if ( !nNewWidth )
2337         mbAutoWinWidth = true;
2338     else
2339         mbAutoWinWidth = false;
2340 
2341     mnWinOff = nNewOff;
2342     mnWinWidth = nNewWidth;
2343     ImplUpdate( true );
2344 }
2345 
SetPagePos(tools::Long nNewOff,tools::Long nNewWidth)2346 void Ruler::SetPagePos( tools::Long nNewOff, tools::Long nNewWidth )
2347 {
2348     // should we do anything?
2349     if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) )
2350         return;
2351 
2352     // should widths be automatically calculated
2353     if ( !nNewWidth )
2354         mpData->bAutoPageWidth = true;
2355     else
2356         mpData->bAutoPageWidth = false;
2357 
2358     mpData->nPageOff     = nNewOff;
2359     mpData->nPageWidth   = nNewWidth;
2360     ImplUpdate( true );
2361 }
2362 
SetBorderPos(tools::Long nOff)2363 void Ruler::SetBorderPos( tools::Long nOff )
2364 {
2365     if ( mnWinStyle & WB_BORDER )
2366     {
2367         if ( mnBorderOff != nOff )
2368         {
2369             mnBorderOff = nOff;
2370 
2371             if ( IsReallyVisible() && IsUpdateMode() )
2372                 Invalidate(InvalidateFlags::NoErase);
2373         }
2374     }
2375 }
2376 
SetUnit(FieldUnit eNewUnit)2377 void Ruler::SetUnit( FieldUnit eNewUnit )
2378 {
2379     if ( meUnit == eNewUnit )
2380         return;
2381 
2382     meUnit = eNewUnit;
2383     switch ( meUnit )
2384     {
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;
2421     }
2422 
2423     maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit );
2424     ImplUpdate();
2425 }
2426 
SetZoom(const Fraction & rNewZoom)2427 void Ruler::SetZoom( const Fraction& rNewZoom )
2428 {
2429     DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" );
2430 
2431     if ( maZoom != rNewZoom )
2432     {
2433         maZoom = rNewZoom;
2434         maMapMode.SetScaleX( maZoom );
2435         maMapMode.SetScaleY( maZoom );
2436         ImplUpdate();
2437     }
2438 }
2439 
SetExtraType(RulerExtra eNewExtraType,sal_uInt16 nStyle)2440 void Ruler::SetExtraType( RulerExtra eNewExtraType, sal_uInt16 nStyle )
2441 {
2442     if ( mnWinStyle & WB_EXTRAFIELD )
2443     {
2444         meExtraType  = eNewExtraType;
2445         mnExtraStyle = nStyle;
2446         if (IsReallyVisible() && IsUpdateMode())
2447             Invalidate();
2448     }
2449 }
2450 
SetNullOffset(tools::Long nPos)2451 void Ruler::SetNullOffset( tools::Long nPos )
2452 {
2453     if ( mpData->nNullOff != nPos )
2454     {
2455         mpData->nNullVirOff += nPos - mpData->nNullOff;
2456         mpData->nNullOff = nPos;
2457         ImplUpdate();
2458     }
2459 }
2460 
SetLeftFrameMargin(tools::Long nPos)2461 void Ruler::SetLeftFrameMargin( tools::Long nPos )
2462 {
2463     if ( mpData->nLeftFrameMargin != nPos )
2464     {
2465         mpData->nLeftFrameMargin  = nPos;
2466         ImplUpdate();
2467     }
2468 }
2469 
SetRightFrameMargin(tools::Long nPos)2470 void Ruler::SetRightFrameMargin( tools::Long nPos )
2471 {
2472     if ( mpData->nRightFrameMargin != nPos )
2473     {
2474         mpData->nRightFrameMargin  = nPos;
2475         ImplUpdate();
2476     }
2477 }
2478 
SetMargin1(tools::Long nPos,RulerMarginStyle nMarginStyle)2479 void Ruler::SetMargin1( tools::Long nPos, RulerMarginStyle nMarginStyle )
2480 {
2481     if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) )
2482     {
2483         mpData->nMargin1      = nPos;
2484         mpData->nMargin1Style = nMarginStyle;
2485         ImplUpdate();
2486     }
2487 }
2488 
SetMargin2(tools::Long nPos,RulerMarginStyle nMarginStyle)2489 void Ruler::SetMargin2( tools::Long nPos, RulerMarginStyle nMarginStyle )
2490 {
2491     DBG_ASSERT( (nPos >= mpData->nMargin1) ||
2492                 (mpData->nMargin1Style & RulerMarginStyle::Invisible) ||
2493                 (mpData->nMargin2Style & RulerMarginStyle::Invisible),
2494                 "Ruler::SetMargin2() - Margin2 < Margin1" );
2495 
2496     if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) )
2497     {
2498         mpData->nMargin2      = nPos;
2499         mpData->nMargin2Style = nMarginStyle;
2500         ImplUpdate();
2501     }
2502 }
2503 
SetLines(sal_uInt32 aLineArraySize,const RulerLine * pLineArray)2504 void Ruler::SetLines( sal_uInt32 aLineArraySize, const RulerLine* pLineArray )
2505 {
2506     // To determine if what has changed
2507     if ( mpData->pLines.size() == aLineArraySize )
2508     {
2509         sal_uInt32           i = aLineArraySize;
2510         std::vector<RulerLine>::const_iterator aItr1 = mpData->pLines.begin();
2511         const RulerLine* pAry2 = pLineArray;
2512         while ( i )
2513         {
2514             if ( aItr1->nPos   != pAry2->nPos )
2515                 break;
2516             ++aItr1;
2517             ++pAry2;
2518             i--;
2519         }
2520         if ( !i )
2521             return;
2522     }
2523 
2524     // New values and new share issue
2525     bool bMustUpdate;
2526     bMustUpdate = IsReallyVisible() && IsUpdateMode();
2527 
2528     // Delete old lines
2529     if ( bMustUpdate )
2530         Invalidate(InvalidateFlags::NoErase);
2531 
2532     // New data set
2533     if ( !aLineArraySize || !pLineArray )
2534     {
2535         if ( mpData->pLines.empty() )
2536             return;
2537         mpData->pLines.clear();
2538     }
2539     else
2540     {
2541         if ( mpData->pLines.size() != aLineArraySize )
2542         {
2543             mpData->pLines.resize(aLineArraySize);
2544         }
2545 
2546         std::copy( pLineArray,
2547                    pLineArray + aLineArraySize,
2548                    mpData->pLines.begin() );
2549 
2550         if ( bMustUpdate )
2551             Invalidate(InvalidateFlags::NoErase);
2552     }
2553 }
2554 
SetBorders(sal_uInt32 aBorderArraySize,const RulerBorder * pBorderArray)2555 void Ruler::SetBorders( sal_uInt32 aBorderArraySize, const RulerBorder* pBorderArray )
2556 {
2557     if ( !aBorderArraySize || !pBorderArray )
2558     {
2559         if ( mpData->pBorders.empty() )
2560             return;
2561         mpData->pBorders.clear();
2562     }
2563     else
2564     {
2565         if ( mpData->pBorders.size() != aBorderArraySize )
2566         {
2567             mpData->pBorders.resize(aBorderArraySize);
2568         }
2569         else
2570         {
2571             sal_uInt32             i = aBorderArraySize;
2572             const RulerBorder* pAry1 = mpData->pBorders.data();
2573             const RulerBorder* pAry2 = pBorderArray;
2574             while ( i )
2575             {
2576                 if ( (pAry1->nPos   != pAry2->nPos)   ||
2577                      (pAry1->nWidth != pAry2->nWidth) ||
2578                      (pAry1->nStyle != pAry2->nStyle) )
2579                     break;
2580                 pAry1++;
2581                 pAry2++;
2582                 i--;
2583             }
2584             if ( !i )
2585                 return;
2586         }
2587         std::copy( pBorderArray,
2588                    pBorderArray + aBorderArraySize,
2589                    mpData->pBorders.begin() );
2590     }
2591 
2592     ImplUpdate();
2593 }
2594 
SetIndents(sal_uInt32 aIndentArraySize,const RulerIndent * pIndentArray)2595 void Ruler::SetIndents( sal_uInt32 aIndentArraySize, const RulerIndent* pIndentArray )
2596 {
2597 
2598     if ( !aIndentArraySize || !pIndentArray )
2599     {
2600         if ( mpData->pIndents.empty() )
2601             return;
2602         mpData->pIndents.clear();
2603     }
2604     else
2605     {
2606         if ( mpData->pIndents.size() != aIndentArraySize )
2607         {
2608             mpData->pIndents.resize(aIndentArraySize);
2609         }
2610         else
2611         {
2612             sal_uInt32             i = aIndentArraySize;
2613             const RulerIndent* pAry1 = mpData->pIndents.data();
2614             const RulerIndent* pAry2 = pIndentArray;
2615             while ( i )
2616             {
2617                 if ( (pAry1->nPos   != pAry2->nPos) ||
2618                      (pAry1->nStyle != pAry2->nStyle) )
2619                     break;
2620                 pAry1++;
2621                 pAry2++;
2622                 i--;
2623             }
2624             if ( !i )
2625                 return;
2626         }
2627 
2628         std::copy( pIndentArray,
2629                    pIndentArray + aIndentArraySize,
2630                    mpData->pIndents.begin() );
2631     }
2632 
2633     ImplUpdate();
2634 }
2635 
SetTabs(sal_uInt32 aTabArraySize,const RulerTab * pTabArray)2636 void Ruler::SetTabs( sal_uInt32 aTabArraySize, const RulerTab* pTabArray )
2637 {
2638     if ( aTabArraySize == 0 || pTabArray == nullptr )
2639     {
2640         if ( mpData->pTabs.empty() )
2641             return;
2642         mpData->pTabs.clear();
2643     }
2644     else
2645     {
2646         if ( mpData->pTabs.size() != aTabArraySize )
2647         {
2648             mpData->pTabs.resize(aTabArraySize);
2649         }
2650         else
2651         {
2652             sal_uInt32 i = aTabArraySize;
2653             std::vector<RulerTab>::iterator aTabIterator = mpData->pTabs.begin();
2654             const RulerTab* pInputArray = pTabArray;
2655             while ( i )
2656             {
2657                 RulerTab& aCurrent = *aTabIterator;
2658                 if ( aCurrent.nPos   != pInputArray->nPos ||
2659                      aCurrent.nStyle != pInputArray->nStyle )
2660                 {
2661                     break;
2662                 }
2663                 ++aTabIterator;
2664                 pInputArray++;
2665                 i--;
2666             }
2667             if ( !i )
2668                 return;
2669         }
2670         std::copy(pTabArray, pTabArray + aTabArraySize, mpData->pTabs.begin());
2671     }
2672 
2673     ImplUpdate();
2674 }
2675 
GetTabs() const2676 const std::vector<RulerTab>& Ruler::GetTabs() const
2677 {
2678     return mpData->pTabs;
2679 }
2680 
SetStyle(WinBits nStyle)2681 void Ruler::SetStyle( WinBits nStyle )
2682 {
2683     if ( mnWinStyle != nStyle )
2684     {
2685         mnWinStyle = nStyle;
2686         ImplInitExtraField( true );
2687     }
2688 }
2689 
DrawTab(vcl::RenderContext & rRenderContext,const Color & rFillColor,const Point & rPos,sal_uInt16 nStyle)2690 void Ruler::DrawTab(vcl::RenderContext& rRenderContext, const Color &rFillColor, const Point& rPos, sal_uInt16 nStyle)
2691 {
2692     Point aPos(rPos);
2693     sal_uInt16 nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL);
2694 
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();
2701 }
2702 
SetTextRTL(bool bRTL)2703 void Ruler::SetTextRTL(bool bRTL)
2704 {
2705     if(mpData->bTextRTL != bRTL)
2706     {
2707         mpData->bTextRTL = bRTL;
2708         if ( IsReallyVisible() && IsUpdateMode() )
2709             ImplInitExtraField( true );
2710     }
2711 
2712 }
2713 
GetPageOffset() const2714 tools::Long Ruler::GetPageOffset() const
2715 {
2716     return mpData->nPageOff;
2717 }
2718 
GetNullOffset() const2719 tools::Long Ruler::GetNullOffset() const
2720 {
2721     return mpData->nNullOff;
2722 }
2723 
GetMargin1() const2724 tools::Long Ruler::GetMargin1() const
2725 {
2726     return mpData->nMargin1;
2727 }
2728 
GetMargin2() const2729 tools::Long Ruler::GetMargin2() const
2730 {
2731     return mpData->nMargin2;
2732 }
2733 
2734 
GetTextRTL() const2735 bool Ruler::GetTextRTL() const
2736 {
2737     return mpData->bTextRTL;
2738 }
2739 
GetCurrentRulerUnit() const2740 const RulerUnitData& Ruler::GetCurrentRulerUnit() const
2741 {
2742     return aImplRulerUnitTab[mnUnitIndex];
2743 }
2744 
DrawTicks()2745 void Ruler::DrawTicks()
2746 {
2747     mbFormat = true;
2748     Invalidate(InvalidateFlags::NoErase);
2749 }
2750 
CreateAccessible()2751 uno::Reference< XAccessible > Ruler::CreateAccessible()
2752 {
2753     vcl::Window* pParent = GetAccessibleParentWindow();
2754     OSL_ENSURE( pParent, "-SvxRuler::CreateAccessible(): No Parent!" );
2755     uno::Reference< XAccessible >   xAccParent  = pParent->GetAccessible();
2756     if( xAccParent.is() )
2757     {
2758         // MT: Fixed compiler issue because the address from a temporary object was used.
2759         // BUT: Should it really be a Pointer, instead of const&???
2760         OUString aStr;
2761         if ( mnWinStyle & WB_HORZ )
2762         {
2763             aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME);
2764         }
2765         else
2766         {
2767             aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME);
2768         }
2769         mxAccContext = new SvtRulerAccessible( xAccParent, *this, aStr );
2770         SetAccessible(mxAccContext);
2771         return mxAccContext;
2772     }
2773     else
2774         return uno::Reference< XAccessible >();
2775 }
2776 
2777 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2778