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 std;
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::accessibility;
43 
44 #define RULER_OFF           3
45 #define RULER_RESIZE_OFF    4
46 #define RULER_MIN_SIZE      3
47 
48 #define RULER_VAR_SIZE      8
49 
50 #define RULER_UPDATE_LINES  0x01
51 
52 #define RULER_CLIP          150
53 
54 #define RULER_UNIT_MM       0
55 #define RULER_UNIT_CM       1
56 #define RULER_UNIT_M        2
57 #define RULER_UNIT_KM       3
58 #define RULER_UNIT_INCH     4
59 #define RULER_UNIT_FOOT     5
60 #define RULER_UNIT_MILE     6
61 #define RULER_UNIT_POINT    7
62 #define RULER_UNIT_PICA     8
63 #define RULER_UNIT_CHAR     9
64 #define RULER_UNIT_LINE    10
65 #define RULER_UNIT_COUNT   11
66 
67 namespace
68 {
69 /**
70  * Pre-calculates glyph items for rText on rRenderContext. Subsequent calls
71  * avoid the calculation and just return a pointer to rTextGlyphs.
72  */
lcl_GetRulerTextGlyphs(const vcl::RenderContext & rRenderContext,const OUString & rText,SalLayoutGlyphs & rTextGlyphs)73 SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext, const OUString& rText,
74                                         SalLayoutGlyphs& rTextGlyphs)
75 {
76     if (rTextGlyphs.IsValid())
77         // Use pre-calculated result.
78         return &rTextGlyphs;
79 
80     // Calculate glyph items.
81 
82     std::unique_ptr<SalLayout> pLayout = rRenderContext.ImplLayout(
83         rText, 0, rText.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly);
84     if (!pLayout)
85         return nullptr;
86 
87     // Remember the calculation result.
88     rTextGlyphs = pLayout->GetGlyphs();
89 
90     return &rTextGlyphs;
91 }
92 }
93 
94 class ImplRulerData
95 {
96     friend class Ruler;
97 
98 private:
99     vector<RulerLine>    pLines;
100     vector<RulerBorder>  pBorders;
101     vector<RulerIndent>  pIndents;
102     vector<RulerTab>     pTabs;
103 
104     tools::Long       nNullVirOff;
105     tools::Long       nRulVirOff;
106     tools::Long       nRulWidth;
107     tools::Long       nPageOff;
108     tools::Long       nPageWidth;
109     tools::Long       nNullOff;
110     tools::Long       nMargin1;
111     tools::Long       nMargin2;
112     // In this context, "frame margin" means paragraph margins (indents)
113     tools::Long       nLeftFrameMargin;
114     tools::Long       nRightFrameMargin;
115     RulerMarginStyle nMargin1Style;
116     RulerMarginStyle nMargin2Style;
117     bool       bAutoPageWidth;
118     bool       bTextRTL;
119 
120 public:
121     ImplRulerData();
122 };
123 
ImplRulerData()124 ImplRulerData::ImplRulerData() :
125     nNullVirOff       (0),
126     nRulVirOff        (0),
127     nRulWidth         (0),
128     nPageOff          (0),
129     nPageWidth        (0),
130     nNullOff          (0),
131     nMargin1          (0),
132     nMargin2          (0),
133     nLeftFrameMargin  (0),
134     nRightFrameMargin (0),
135     nMargin1Style     (RulerMarginStyle::NONE),
136     nMargin2Style     (RulerMarginStyle::NONE),
137     bAutoPageWidth    (true), // Page width == EditWin width
138     bTextRTL          (false)
139 {
140 }
141 
142 const RulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] =
143 {
144 { MapUnit::Map100thMM,        100,    25.0,    25.0,     50.0,    100.0,  " mm"    }, // MM
145 { MapUnit::Map100thMM,       1000,   100.0,   500.0,   1000.0,   1000.0,  " cm"    }, // CM
146 { MapUnit::MapMM,             1000,    10.0,   250.0,    500.0,   1000.0,  " m"     }, // M
147 { MapUnit::MapCM,           100000, 12500.0, 25000.0,  50000.0, 100000.0,  " km"    }, // KM
148 { MapUnit::Map1000thInch,    1000,    62.5,   125.0,    500.0,   1000.0,  "\""     }, // INCH
149 { MapUnit::Map100thInch,     1200,   120.0,   120.0,    600.0,   1200.0,  "'"      }, // FOOT
150 { MapUnit::Map10thInch,    633600, 63360.0, 63360.0, 316800.0, 633600.0,  " miles" }, // MILE
151 { MapUnit::MapPoint,             1,    12.0,    12.0,     12.0,     36.0,  " pt"    }, // POINT
152 { MapUnit::Map100thMM,        423,   423.0,   423.0,    423.0,    846.0,  " pc"    }, // PICA
153 { MapUnit::Map100thMM,        371,   371.0,   371.0,    371.0,    743.0,  " ch"    }, // CHAR
154 { MapUnit::Map100thMM,        551,   551.0,   551.0,    551.0,   1102.0,  " li"    }  // LINE
155 };
156 
157 static RulerTabData ruler_tab =
158 {
159     0, // DPIScaleFactor to be set
160     7, // ruler_tab_width
161     6, // ruler_tab_height
162     2, // ruler_tab_height2
163     2, // ruler_tab_width2
164     8, // ruler_tab_cwidth
165     4, // ruler_tab_cwidth2
166     4, // ruler_tab_cwidth3
167     2, // ruler_tab_cwidth4
168     4, // ruler_tab_dheight
169     1, // ruler_tab_dheight2
170     5, // ruler_tab_dwidth
171     3, // ruler_tab_dwidth2
172     3, // ruler_tab_dwidth3
173     1, // ruler_tab_dwidth4
174     5  // ruler_tab_textoff
175 };
176 
ImplInit(WinBits nWinBits)177 void Ruler::ImplInit( WinBits nWinBits )
178 {
179     // Set default WinBits
180     if ( !(nWinBits & WB_VERT) )
181     {
182         nWinBits |= WB_HORZ;
183 
184         // RTL: no UI mirroring for horizontal rulers, because
185         // the document is also not mirrored
186         EnableRTL( false );
187     }
188 
189     // Initialize variables
190     mnWinStyle      = nWinBits;             // Window-Style
191     mnBorderOff     = 0;                    // Border-Offset
192     mnWinOff        = 0;                    // EditWinOffset
193     mnWinWidth      = 0;                    // EditWinWidth
194     mnWidth         = 0;                    // Window width
195     mnHeight        = 0;                    // Window height
196     mnVirOff        = 0;                    // Offset of VirtualDevice from top-left corner
197     mnVirWidth      = 0;                    // width or height from VirtualDevice
198     mnVirHeight     = 0;                    // height of width from VirtualDevice
199     mnDragPos       = 0;                    // Drag-Position (Null point)
200     mnDragAryPos    = 0;                    // Drag-Array-Index
201     mnDragSize      = RulerDragSize::Move;  // Did size change at dragging
202     mnDragModifier  = 0;                    // Modifier key at dragging
203     mnExtraStyle    = 0;                    // Style of Extra field
204     mnCharWidth     = 371;
205     mnLineHeight    = 551;
206     mbCalc          = true;                 // Should recalculate page width
207     mbFormat        = true;                 // Should redraw
208     mbDrag          = false;                // Currently at dragging
209     mbDragDelete    = false;                // Has mouse left the dragging area
210     mbDragCanceled  = false;                // Dragging cancelled?
211     mbAutoWinWidth  = true;                 // EditWinWidth == RulerWidth
212     mbActive        = true;                 // Is ruler active
213     mnUpdateFlags   = 0;                    // What needs to be updated
214     mpData          = mpSaveData.get();     // Pointer to normal data
215     meExtraType     = RulerExtra::DontKnow; // What is in extra field
216     meDragType      = RulerType::DontKnow;  // Which element is dragged
217 
218     // Initialize Units
219     mnUnitIndex     = RULER_UNIT_CM;
220     meUnit          = FieldUnit::CM;
221     maZoom          = Fraction( 1, 1 );
222 
223     // Recalculate border widths
224     if ( nWinBits & WB_BORDER )
225         mnBorderWidth = 1;
226     else
227         mnBorderWidth = 0;
228 
229     // Settings
230     ImplInitSettings( true, true, true );
231 
232     // Setup the default size
233     tools::Rectangle aRect;
234     GetOutDev()->GetTextBoundRect( aRect, "0123456789" );
235     tools::Long nDefHeight = aRect.GetHeight() + RULER_OFF * 2 + ruler_tab.textoff * 2 + mnBorderWidth;
236 
237     Size aDefSize;
238     if ( nWinBits & WB_HORZ )
239         aDefSize.setHeight( nDefHeight );
240     else
241         aDefSize.setWidth( nDefHeight );
242     SetOutputSizePixel( aDefSize );
243     SetType(WindowType::RULER);
244 }
245 
Ruler(vcl::Window * pParent,WinBits nWinStyle)246 Ruler::Ruler( vcl::Window* pParent, WinBits nWinStyle ) :
247     Window( pParent, nWinStyle & WB_3DLOOK ),
248     maVirDev( VclPtr<VirtualDevice>::Create(*GetOutDev()) ),
249     maMapMode( MapUnit::Map100thMM ),
250     mpSaveData(new ImplRulerData),
251     mpData(nullptr),
252     mpDragData(new ImplRulerData)
253 {
254     // Check to see if the ruler constructor has
255     // already been called before otherwise
256     // we end up with over-scaled elements
257     if (ruler_tab.DPIScaleFactor == 0)
258     {
259         ruler_tab.DPIScaleFactor = GetDPIScaleFactor();
260         ruler_tab.width    *= ruler_tab.DPIScaleFactor;
261         ruler_tab.height   *= ruler_tab.DPIScaleFactor;
262         ruler_tab.height2  *= ruler_tab.DPIScaleFactor;
263         ruler_tab.width2   *= ruler_tab.DPIScaleFactor;
264         ruler_tab.cwidth   *= ruler_tab.DPIScaleFactor;
265         ruler_tab.cwidth2  *= ruler_tab.DPIScaleFactor;
266         ruler_tab.cwidth3  *= ruler_tab.DPIScaleFactor;
267         ruler_tab.cwidth4  *= ruler_tab.DPIScaleFactor;
268         ruler_tab.dheight  *= ruler_tab.DPIScaleFactor;
269         ruler_tab.dheight2 *= ruler_tab.DPIScaleFactor;
270         ruler_tab.dwidth   *= ruler_tab.DPIScaleFactor;
271         ruler_tab.dwidth2  *= ruler_tab.DPIScaleFactor;
272         ruler_tab.dwidth3  *= ruler_tab.DPIScaleFactor;
273         ruler_tab.dwidth4  *= ruler_tab.DPIScaleFactor;
274         ruler_tab.textoff  *= ruler_tab.DPIScaleFactor;
275     }
276 
277 
278     ImplInit( nWinStyle );
279 }
280 
~Ruler()281 Ruler::~Ruler()
282 {
283     disposeOnce();
284 }
285 
dispose()286 void Ruler::dispose()
287 {
288     mpSaveData.reset();
289     mpDragData.reset();
290     mxAccContext.clear();
291     Window::dispose();
292 }
293 
ImplVDrawLine(vcl::RenderContext & rRenderContext,tools::Long nX1,tools::Long nY1,tools::Long nX2,tools::Long nY2)294 void Ruler::ImplVDrawLine(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
295 {
296     if ( nX1 < -RULER_CLIP )
297     {
298         nX1 = -RULER_CLIP;
299         if ( nX2 < -RULER_CLIP )
300             return;
301     }
302     tools::Long nClip = mnVirWidth + RULER_CLIP;
303     if ( nX2 > nClip )
304     {
305         nX2 = nClip;
306         if ( nX1 > nClip )
307             return;
308     }
309 
310     if ( mnWinStyle & WB_HORZ )
311         rRenderContext.DrawLine( Point( nX1, nY1 ), Point( nX2, nY2 ) );
312     else
313         rRenderContext.DrawLine( Point( nY1, nX1 ), Point( nY2, nX2 ) );
314 }
315 
ImplVDrawRect(vcl::RenderContext & rRenderContext,tools::Long nX1,tools::Long nY1,tools::Long nX2,tools::Long nY2)316 void Ruler::ImplVDrawRect(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
317 {
318     if ( nX1 < -RULER_CLIP )
319     {
320         nX1 = -RULER_CLIP;
321         if ( nX2 < -RULER_CLIP )
322             return;
323     }
324     tools::Long nClip = mnVirWidth + RULER_CLIP;
325     if ( nX2 > nClip )
326     {
327         nX2 = nClip;
328         if ( nX1 > nClip )
329             return;
330     }
331 
332     if ( mnWinStyle & WB_HORZ )
333         rRenderContext.DrawRect(tools::Rectangle(nX1, nY1, nX2, nY2));
334     else
335         rRenderContext.DrawRect(tools::Rectangle(nY1, nX1, nY2, nX2));
336 }
337 
ImplVDrawText(vcl::RenderContext & rRenderContext,tools::Long nX,tools::Long nY,const OUString & rText,tools::Long nMin,tools::Long nMax)338 void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, tools::Long nY, const OUString& rText, tools::Long nMin, tools::Long nMax)
339 {
340     tools::Rectangle aRect;
341     SalLayoutGlyphs* pTextLayout
342         = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]);
343     rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, nullptr, pTextLayout);
344 
345     tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left();
346     tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top();
347 
348     if ( (nX > -RULER_CLIP) && (nX < mnVirWidth + RULER_CLIP) && ( nX < nMax - nShiftX ) && ( nX > nMin + nShiftX ) )
349     {
350         if ( mnWinStyle & WB_HORZ )
351             rRenderContext.DrawText(Point(nX - nShiftX, nY - nShiftY), rText, 0, -1, nullptr,
352                                     nullptr, pTextLayout);
353         else
354             rRenderContext.DrawText(Point(nY - nShiftX, nX - nShiftY), rText, 0, -1, nullptr,
355                                     nullptr, pTextLayout);
356     }
357 }
358 
ImplInvertLines(vcl::RenderContext & rRenderContext)359 void Ruler::ImplInvertLines(vcl::RenderContext& rRenderContext)
360 {
361     // Position lines
362     if (mpData->pLines.empty() || !mbActive || mbDrag || mbFormat || (mnUpdateFlags & RULER_UPDATE_LINES) )
363         return;
364 
365     tools::Long nNullWinOff = mpData->nNullVirOff + mnVirOff;
366     tools::Long nRulX1      = mpData->nRulVirOff  + mnVirOff;
367     tools::Long nRulX2      = nRulX1 + mpData->nRulWidth;
368     tools::Long nY          = (RULER_OFF * 2) + mnVirHeight - 1;
369 
370     // Calculate rectangle
371     tools::Rectangle aRect;
372     if (mnWinStyle & WB_HORZ)
373         aRect.SetBottom( nY );
374     else
375         aRect.SetRight( nY );
376 
377     // Draw lines
378     for (const RulerLine & rLine : mpData->pLines)
379     {
380         const tools::Long n = rLine.nPos + nNullWinOff;
381         if ((n >= nRulX1) && (n < nRulX2))
382         {
383             if (mnWinStyle & WB_HORZ )
384             {
385                 aRect.SetLeft( n );
386                 aRect.SetRight( n );
387             }
388             else
389             {
390                 aRect.SetTop( n );
391                 aRect.SetBottom( n );
392             }
393             tools::Rectangle aTempRect = aRect;
394 
395             if (mnWinStyle & WB_HORZ)
396                 aTempRect.SetBottom( RULER_OFF - 1 );
397             else
398                 aTempRect.SetRight( RULER_OFF - 1 );
399 
400             rRenderContext.Erase(aTempRect);
401 
402             if (mnWinStyle & WB_HORZ)
403             {
404                 aTempRect.SetBottom( aRect.Bottom() );
405                 aTempRect.SetTop( aTempRect.Bottom() - RULER_OFF + 1 );
406             }
407             else
408             {
409                 aTempRect.SetRight( aRect.Right() );
410                 aTempRect.SetLeft( aTempRect.Right() - RULER_OFF + 1 );
411             }
412             rRenderContext.Erase(aTempRect);
413             GetOutDev()->Invert(aRect);
414         }
415     }
416     mnUpdateFlags = 0;
417 }
418 
ImplDrawTicks(vcl::RenderContext & rRenderContext,tools::Long nMin,tools::Long nMax,tools::Long nStart,tools::Long nTop,tools::Long nBottom)419 void Ruler::ImplDrawTicks(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nStart, tools::Long nTop, tools::Long nBottom)
420 {
421     double nCenter = nTop + ((nBottom - nTop) / 2);
422 
423     tools::Long nTickLength3 = (nBottom - nTop) * 0.5;
424     tools::Long nTickLength2 = nTickLength3 * 0.66;
425     tools::Long nTickLength1 = nTickLength2 * 0.66;
426 
427     tools::Long nScale = ruler_tab.DPIScaleFactor;
428     tools::Long DPIOffset = nScale - 1;
429 
430     double nTick4 = aImplRulerUnitTab[mnUnitIndex].nTick4;
431     double nTick2 = 0;
432     double nTickCount = aImplRulerUnitTab[mnUnitIndex].nTick1 / nScale;
433     double nTickUnit = 0;
434     tools::Long nTickWidth;
435     bool bNoTicks = false;
436 
437     Size aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
438 
439     if (mnUnitIndex == RULER_UNIT_CHAR)
440     {
441         if (mnCharWidth == 0)
442             mnCharWidth = 371;
443         nTick4 = mnCharWidth * 2;
444         nTick2 = mnCharWidth;
445         nTickCount = mnCharWidth;
446         nTickUnit = mnCharWidth;
447     }
448     else if (mnUnitIndex == RULER_UNIT_LINE)
449     {
450         if (mnLineHeight == 0)
451             mnLineHeight = 551;
452         nTick4 = mnLineHeight * 2;
453         nTick2 = mnLineHeight;
454         nTickUnit = mnLineHeight;
455         nTickCount = mnLineHeight;
456     }
457 
458     if (mnWinStyle & WB_HORZ)
459     {
460         nTickWidth = aPixSize.Width();
461     }
462     else
463     {
464         vcl::Font aFont = rRenderContext.GetFont();
465         if (mnWinStyle & WB_RIGHT_ALIGNED)
466             aFont.SetOrientation(2700_deg10);
467         else
468             aFont.SetOrientation(900_deg10);
469         rRenderContext.SetFont(aFont);
470         nTickWidth = aPixSize.Height();
471     }
472 
473     tools::Long nMaxWidth = rRenderContext.PixelToLogic(Size(mpData->nPageWidth, 0), maMapMode).Width();
474     if (nMaxWidth < 0)
475         nMaxWidth = -nMaxWidth;
476 
477     if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
478         nMaxWidth /= nTickUnit;
479     else
480         nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit;
481 
482     OUString aNumString = OUString::number(nMaxWidth);
483     tools::Long nTxtWidth = rRenderContext.GetTextWidth( aNumString );
484     const tools::Long nTextOff = 4;
485 
486     // Determine the number divider for ruler drawn numbers - means which numbers
487     // should be shown on the ruler and which should be skipped because the ruler
488     // is not big enough to draw them
489     if (nTickWidth < nTxtWidth + nTextOff)
490     {
491         // Calculate the scale of the ruler
492         tools::Long nMulti = 1;
493         tools::Long nOrgTick4 = nTick4;
494 
495         while (nTickWidth < nTxtWidth + nTextOff)
496         {
497             tools::Long nOldMulti = nMulti;
498             if (nTickWidth == 0)
499                 nMulti *= 10;
500             else if (nMulti < 10)
501                 nMulti++;
502             else if (nMulti < 100)
503                 nMulti += 10;
504             else if (nMulti < 1000)
505                 nMulti += 100;
506             else
507                 nMulti += 1000;
508 
509             // Overflow - in this case don't draw ticks and exit
510             if (nMulti < nOldMulti)
511             {
512                 bNoTicks = true;
513                 break;
514             }
515 
516             nTick4 = nOrgTick4 * nMulti;
517             aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
518             if (mnWinStyle & WB_HORZ)
519                 nTickWidth = aPixSize.Width();
520             else
521                 nTickWidth = aPixSize.Height();
522         }
523         nTickCount = nTick4;
524     }
525     else
526     {
527         rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetShadowColor());
528     }
529 
530     if (bNoTicks)
531         return;
532 
533     tools::Long n = 0;
534     double nTick = 0.0;
535     double nTick3 = 0;
536 
537     if ((mnUnitIndex != RULER_UNIT_CHAR) && (mnUnitIndex != RULER_UNIT_LINE))
538     {
539         nTick2 = aImplRulerUnitTab[mnUnitIndex].nTick2;
540         nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3;
541     }
542 
543     Size nTickGapSize;
544 
545     nTickGapSize = rRenderContext.LogicToPixel(Size(nTickCount, nTickCount), maMapMode);
546     tools::Long nTickGap1 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
547     nTickGapSize = rRenderContext.LogicToPixel(Size(nTick2, nTick2), maMapMode);
548     tools::Long nTickGap2 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
549     nTickGapSize = rRenderContext.LogicToPixel(Size(nTick3, nTick3), maMapMode);
550     tools::Long nTickGap3 = mnWinStyle & WB_HORZ ? nTickGapSize.Width() : nTickGapSize.Height();
551 
552     while (((nStart - n) >= nMin) || ((nStart + n) <= nMax))
553     {
554         // Null point
555         if (nTick == 0.0)
556         {
557             if (nStart > nMin)
558             {
559                 // 0 is only painted when Margin1 is not equal to zero
560                 if ((mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin1 != 0))
561                 {
562                     aNumString = "0";
563                     ImplVDrawText(rRenderContext, nStart, nCenter, aNumString);
564                 }
565             }
566         }
567         else
568         {
569             aPixSize = rRenderContext.LogicToPixel(Size(nTick, nTick), maMapMode);
570 
571             if (mnWinStyle & WB_HORZ)
572                 n = aPixSize.Width();
573             else
574                 n = aPixSize.Height();
575 
576             // Tick4 - Output (Text)
577             double aStep = nTick / nTick4;
578             double aRest = std::abs(aStep - std::floor(aStep));
579             double nAcceptanceDelta = 0.0001;
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 }
999 
ImplInitSettings(bool bFont,bool bForeground,bool bBackground)1000 void Ruler::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1001 {
1002     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1003 
1004     if (bFont)
1005     {
1006         vcl::Font aFont = rStyleSettings.GetToolFont();
1007         // make the font a bit smaller than default
1008         Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
1009         aFont.SetFontSize(aSize);
1010 
1011         ApplyControlFont(*GetOutDev(), aFont);
1012     }
1013 
1014     if (bForeground || bFont)
1015     {
1016         ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
1017         SetTextFillColor();
1018     }
1019 
1020     if (bBackground)
1021     {
1022         Color aColor;
1023         svtools::ColorConfig aColorConfig;
1024         aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
1025         ApplyControlBackground(*GetOutDev(), aColor);
1026     }
1027 
1028     maVirDev->SetSettings( GetSettings() );
1029     maVirDev->SetBackground( GetBackground() );
1030     vcl::Font aFont = GetFont();
1031 
1032     if (mnWinStyle & WB_VERT)
1033         aFont.SetOrientation(900_deg10);
1034 
1035     maVirDev->SetFont(aFont);
1036     maVirDev->SetTextColor(GetTextColor());
1037     maVirDev->SetTextFillColor(GetTextFillColor());
1038 }
1039 
ImplCalc()1040 void Ruler::ImplCalc()
1041 {
1042     // calculate offset
1043     mpData->nRulVirOff = mnWinOff + mpData->nPageOff;
1044     if ( mpData->nRulVirOff > mnVirOff )
1045         mpData->nRulVirOff -= mnVirOff;
1046     else
1047         mpData->nRulVirOff = 0;
1048     tools::Long nRulWinOff = mpData->nRulVirOff+mnVirOff;
1049 
1050     // calculate non-visual part of the page
1051     tools::Long nNotVisPageWidth;
1052     if ( mpData->nPageOff < 0 )
1053     {
1054         nNotVisPageWidth = -(mpData->nPageOff);
1055         if ( nRulWinOff < mnWinOff )
1056             nNotVisPageWidth -= mnWinOff-nRulWinOff;
1057     }
1058     else
1059         nNotVisPageWidth = 0;
1060 
1061     // calculate width
1062     if ( mnWinStyle & WB_HORZ )
1063     {
1064         if ( mbAutoWinWidth )
1065             mnWinWidth = mnWidth - mnVirOff;
1066         if ( mpData->bAutoPageWidth )
1067             mpData->nPageWidth = mnWinWidth;
1068         mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1069         if ( nRulWinOff+mpData->nRulWidth > mnWidth )
1070             mpData->nRulWidth = mnWidth-nRulWinOff;
1071     }
1072     else
1073     {
1074         if ( mbAutoWinWidth )
1075             mnWinWidth = mnHeight - mnVirOff;
1076         if ( mpData->bAutoPageWidth )
1077             mpData->nPageWidth = mnWinWidth;
1078         mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1079         if ( nRulWinOff+mpData->nRulWidth > mnHeight )
1080             mpData->nRulWidth = mnHeight-nRulWinOff;
1081     }
1082 
1083     mbCalc = false;
1084 }
1085 
ImplFormat(vcl::RenderContext const & rRenderContext)1086 void Ruler::ImplFormat(vcl::RenderContext const & rRenderContext)
1087 {
1088     // if already formatted, don't do it again
1089     if (!mbFormat)
1090         return;
1091 
1092     // don't do anything if the window still has no size
1093     if (!mnVirWidth)
1094         return;
1095 
1096     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1097     tools::Long    nP1;            // pixel position of Page1
1098     tools::Long    nP2;            // pixel position of Page2
1099     tools::Long    nM1;            // pixel position of Margin1
1100     tools::Long    nM2;            // pixel position of Margin2
1101     tools::Long    nVirTop;        // top/left corner
1102     tools::Long    nVirBottom;     // bottom/right corner
1103     tools::Long    nVirLeft;       // left/top corner
1104     tools::Long    nVirRight;      // right/bottom corner
1105     tools::Long    nNullVirOff;    // for faster calculation
1106 
1107     // calculate values
1108     if (mbCalc)
1109         ImplCalc();
1110 
1111     mpData->nNullVirOff = mnWinOff + mpData->nPageOff + mpData->nNullOff - mnVirOff;
1112 
1113     nNullVirOff = mpData->nNullVirOff;
1114     nVirLeft    = mpData->nRulVirOff;
1115     nVirRight   = nVirLeft + mpData->nRulWidth - 1;
1116     nVirTop     = 0;
1117     nVirBottom  = mnVirHeight - 1;
1118 
1119     if (!IsReallyVisible())
1120         return;
1121 
1122     Size aVirDevSize;
1123 
1124     // initialize VirtualDevice
1125     if (mnWinStyle & WB_HORZ)
1126     {
1127         aVirDevSize.setWidth( mnVirWidth );
1128         aVirDevSize.setHeight( mnVirHeight );
1129     }
1130     else
1131     {
1132         aVirDevSize.setHeight( mnVirWidth );
1133         aVirDevSize.setWidth( mnVirHeight );
1134     }
1135     if (aVirDevSize != maVirDev->GetOutputSizePixel())
1136         maVirDev->SetOutputSizePixel(aVirDevSize);
1137     else
1138         maVirDev->Erase();
1139 
1140     // calculate margins
1141     if (!(mpData->nMargin1Style & RulerMarginStyle::Invisible))
1142     {
1143         nM1 = mpData->nMargin1 + nNullVirOff;
1144         if (mpData->bAutoPageWidth)
1145         {
1146             nP1 = nVirLeft;
1147             if (nM1 < nVirLeft)
1148                 nP1--;
1149         }
1150         else
1151             nP1 = nNullVirOff - mpData->nNullOff;
1152     }
1153     else
1154     {
1155         nM1 = nVirLeft-1;
1156         nP1 = nM1;
1157     }
1158     if (!(mpData->nMargin2Style & RulerMarginStyle::Invisible))
1159     {
1160         nM2 = mpData->nMargin2 + nNullVirOff;
1161         if (mpData->bAutoPageWidth)
1162         {
1163             nP2 = nVirRight;
1164             if (nM2 > nVirRight)
1165                 nP2++;
1166         }
1167         else
1168             nP2 = nNullVirOff - mpData->nNullOff + mpData->nPageWidth;
1169         if (nM2 > nP2)
1170             nM2 = nP2;
1171     }
1172     else
1173     {
1174         nM2 = nVirRight+1;
1175         nP2 = nM2;
1176     }
1177 
1178     // top/bottom border
1179     maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1180     ImplVDrawLine(*maVirDev, nVirLeft, nVirTop + 1, nM1,     nVirTop + 1); //top left line
1181     ImplVDrawLine(*maVirDev, nM2,      nVirTop + 1, nP2 - 1, nVirTop + 1); //top right line
1182 
1183     nVirTop++;
1184     nVirBottom--;
1185 
1186     // draw margin1, margin2 and in-between
1187     maVirDev->SetLineColor();
1188     maVirDev->SetFillColor(rStyleSettings.GetDialogColor());
1189     if (nM1 > nVirLeft)
1190         ImplVDrawRect(*maVirDev, nP1, nVirTop + 1, nM1, nVirBottom); //left gray rectangle
1191     if (nM2 < nP2)
1192         ImplVDrawRect(*maVirDev, nM2, nVirTop + 1, nP2, nVirBottom); //right gray rectangle
1193     if (nM2 - nM1 > 0)
1194     {
1195         maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1196         ImplVDrawRect(*maVirDev, nM1 + 1, nVirTop, nM2 - 1, nVirBottom); //center rectangle
1197     }
1198     maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1199     if (nM1 > nVirLeft)
1200     {
1201         ImplVDrawLine(*maVirDev, nM1, nVirTop + 1, nM1, nVirBottom); //right line of the left rectangle
1202         ImplVDrawLine(*maVirDev, nP1, nVirBottom,  nM1, nVirBottom); //bottom line of the left rectangle
1203         if (nP1 >= nVirLeft)
1204         {
1205             ImplVDrawLine(*maVirDev, nP1, nVirTop + 1, nP1,     nVirBottom); //left line of the left rectangle
1206             ImplVDrawLine(*maVirDev, nP1, nVirBottom,  nP1 + 1, nVirBottom); //?
1207         }
1208     }
1209     if (nM2 < nP2)
1210     {
1211         ImplVDrawLine(*maVirDev, nM2, nVirBottom,  nP2 - 1, nVirBottom); //bottom line of the right rectangle
1212         ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nM2,     nVirBottom); //left line of the right rectangle
1213         if (nP2 <= nVirRight + 1)
1214             ImplVDrawLine(*maVirDev, nP2 - 1, nVirTop + 1, nP2 - 1, nVirBottom); //right line of the right rectangle
1215     }
1216 
1217     tools::Long nMin = nVirLeft;
1218     tools::Long nMax = nP2;
1219     tools::Long nStart = 0;
1220 
1221     if (mpData->bTextRTL)
1222         nStart = mpData->nRightFrameMargin + nNullVirOff;
1223     else
1224         nStart = mpData->nLeftFrameMargin + nNullVirOff;
1225 
1226     if (nP1 > nVirLeft)
1227         nMin++;
1228 
1229     if (nP2 < nVirRight)
1230         nMax--;
1231 
1232     // Draw captions
1233     ImplDrawTicks(*maVirDev, nMin, nMax, nStart, nVirTop, nVirBottom);
1234 
1235     // Draw borders
1236     if (!mpData->pBorders.empty())
1237         ImplDrawBorders(*maVirDev, nVirLeft, nP2, nVirTop, nVirBottom);
1238 
1239     // Draw indents
1240     if (!mpData->pIndents.empty())
1241         ImplDrawIndents(*maVirDev, nVirLeft, nP2, nVirTop - 1, nVirBottom + 1);
1242 
1243     // Tabs
1244     if (!mpData->pTabs.empty())
1245         ImplDrawTabs(*maVirDev, nVirLeft, nP2, nVirTop-1, nVirBottom + 1);
1246 
1247     mbFormat = false;
1248 }
1249 
ImplInitExtraField(bool bUpdate)1250 void Ruler::ImplInitExtraField( bool bUpdate )
1251 {
1252     Size aWinSize = GetOutputSizePixel();
1253 
1254     // extra field evaluate
1255     if ( mnWinStyle & WB_EXTRAFIELD )
1256     {
1257         maExtraRect.SetLeft( RULER_OFF );
1258         maExtraRect.SetTop( RULER_OFF );
1259         maExtraRect.SetRight( RULER_OFF + mnVirHeight - 1 );
1260         maExtraRect.SetBottom( RULER_OFF + mnVirHeight - 1 );
1261         if(mpData->bTextRTL)
1262         {
1263             if(mnWinStyle & WB_HORZ)
1264                 maExtraRect.Move(aWinSize.Width() - maExtraRect.GetWidth() - maExtraRect.Left(), 0);
1265             else
1266                 maExtraRect.Move(0, aWinSize.Height() - maExtraRect.GetHeight() - maExtraRect.Top());
1267             mnVirOff = 0;
1268         }
1269         else
1270             mnVirOff = maExtraRect.Right()+1;
1271 
1272     }
1273     else
1274     {
1275         maExtraRect.SetEmpty();
1276         mnVirOff = 0;
1277     }
1278 
1279     // mnVirWidth depends on mnVirOff
1280     if ( (mnVirWidth > RULER_MIN_SIZE) ||
1281      ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) )
1282     {
1283         if ( mnWinStyle & WB_HORZ )
1284             mnVirWidth = aWinSize.Width()-mnVirOff;
1285         else
1286             mnVirWidth = aWinSize.Height()-mnVirOff;
1287 
1288         if ( mnVirWidth < RULER_MIN_SIZE )
1289             mnVirWidth = 0;
1290     }
1291 
1292     if ( bUpdate )
1293     {
1294         mbCalc      = true;
1295         mbFormat    = true;
1296         Invalidate();
1297     }
1298 }
1299 
ImplDraw(vcl::RenderContext & rRenderContext)1300 void Ruler::ImplDraw(vcl::RenderContext& rRenderContext)
1301 {
1302     if (mbFormat)
1303     {
1304         ImplFormat(rRenderContext);
1305     }
1306 
1307     if (!IsReallyVisible())
1308         return;
1309 
1310     // output the ruler to the virtual device
1311     Point aOffPos;
1312     Size aVirDevSize = maVirDev->GetOutputSizePixel();
1313 
1314     if (mnWinStyle & WB_HORZ)
1315     {
1316         aOffPos.setX( mnVirOff );
1317         if (mpData->bTextRTL)
1318             aVirDevSize.AdjustWidth( -(maExtraRect.GetWidth()) );
1319 
1320         aOffPos.setY( RULER_OFF );
1321     }
1322     else
1323     {
1324         aOffPos.setX( RULER_OFF );
1325         aOffPos.setY( mnVirOff );
1326     }
1327     rRenderContext.DrawOutDev(aOffPos, aVirDevSize, Point(), aVirDevSize, *maVirDev);
1328 
1329     // redraw positionlines
1330     ImplInvertLines(rRenderContext);
1331 }
1332 
ImplDrawExtra(vcl::RenderContext & rRenderContext)1333 void Ruler::ImplDrawExtra(vcl::RenderContext& rRenderContext)
1334 {
1335     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1336     tools::Rectangle aRect = maExtraRect;
1337     bool bEraseRect = false;
1338 
1339     aRect.AdjustLeft(2 );
1340     aRect.AdjustTop(2 );
1341     aRect.AdjustRight( -2 );
1342     aRect.AdjustBottom( -2 );
1343 
1344     if (mnExtraStyle & RULER_STYLE_HIGHLIGHT)
1345     {
1346         rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
1347         bEraseRect = true;
1348     }
1349 
1350     if (bEraseRect)
1351     {
1352         rRenderContext.SetLineColor();
1353         rRenderContext.DrawRect(aRect);
1354     }
1355 
1356     // output content
1357     if (meExtraType == RulerExtra::NullOffset)
1358     {
1359         rRenderContext.SetLineColor(rStyleSettings.GetButtonTextColor());
1360         rRenderContext.DrawLine(Point(aRect.Left() + 1, aRect.Top() + 4),
1361                                 Point(aRect.Right() - 1, aRect.Top() + 4));
1362         rRenderContext.DrawLine(Point(aRect.Left() + 4, aRect.Top() + 1),
1363                                 Point(aRect.Left() + 4, aRect.Bottom() - 1));
1364     }
1365     else if (meExtraType == RulerExtra::Tab)
1366     {
1367         sal_uInt16 nTabStyle = mnExtraStyle & RULER_TAB_STYLE;
1368         if (mpData->bTextRTL)
1369             nTabStyle |= RULER_TAB_RTL;
1370         Point aCenter = aRect.Center();
1371         Point aDraw(aCenter);
1372         ImplCenterTabPos(aDraw, nTabStyle);
1373         WinBits nWinBits = GetStyle();
1374         if (0 == (nWinBits & WB_HORZ))
1375         {
1376             if ((nWinBits & WB_RIGHT_ALIGNED) != 0)
1377                 aDraw.setY( 2 * aCenter.Y() - aDraw.Y() );
1378 
1379             if (mpData->bTextRTL)
1380             {
1381                 tools::Long nTemp = aDraw.X();
1382                 aDraw.setX( aDraw.Y() );
1383                 aDraw.setY( nTemp );
1384             }
1385         }
1386         ImplDrawTab(rRenderContext, aDraw, nTabStyle);
1387     }
1388 }
1389 
ImplUpdate(bool bMustCalc)1390 void Ruler::ImplUpdate( bool bMustCalc )
1391 {
1392     // clear lines in this place so they aren't considered at recalculation
1393     if (!mbFormat)
1394         Invalidate(InvalidateFlags::NoErase);
1395 
1396     // set flags
1397     if (bMustCalc)
1398         mbCalc = true;
1399     mbFormat = true;
1400 
1401     // abort if we are dragging as drag-handler will update the ruler after drag is finished
1402     if (mbDrag)
1403         return;
1404 
1405     // otherwise trigger update
1406     if (IsReallyVisible() && IsUpdateMode())
1407     {
1408         Invalidate(InvalidateFlags::NoErase);
1409     }
1410 }
1411 
ImplDoHitTest(const Point & rPos,RulerSelection * pHitTest,bool bRequireStyle,RulerIndentStyle nRequiredStyle) const1412 bool Ruler::ImplDoHitTest( const Point& rPos, RulerSelection* pHitTest,
1413                          bool bRequireStyle, RulerIndentStyle nRequiredStyle ) const
1414 {
1415     sal_Int32   i;
1416     sal_uInt16  nStyle;
1417     tools::Long        nHitBottom;
1418     tools::Long        nX;
1419     tools::Long        nY;
1420     tools::Long        n1;
1421 
1422     if ( !mbActive )
1423         return false;
1424 
1425     // determine positions
1426     bool bIsHori = 0 != (mnWinStyle & WB_HORZ);
1427     if ( bIsHori )
1428     {
1429         nX = rPos.X();
1430         nY = rPos.Y();
1431     }
1432     else
1433     {
1434         nX = rPos.Y();
1435         nY = rPos.X();
1436     }
1437     nHitBottom = mnVirHeight + (RULER_OFF * 2);
1438 
1439     // #i32608#
1440     pHitTest->nAryPos = 0;
1441     pHitTest->mnDragSize = RulerDragSize::Move;
1442     pHitTest->bSize = false;
1443     pHitTest->bSizeBar = false;
1444 
1445     // so that leftover tabs and indents are taken into account
1446     tools::Long nXExtraOff;
1447     if ( !mpData->pTabs.empty() || !mpData->pIndents.empty() )
1448         nXExtraOff = (mnVirHeight / 2) - 4;
1449     else
1450         nXExtraOff = 0;
1451 
1452     // test if outside
1453     nX -= mnVirOff;
1454     if ( (nX < mpData->nRulVirOff - nXExtraOff) ||
1455          (nX > mpData->nRulVirOff + mpData->nRulWidth + nXExtraOff) ||
1456          (nY < 0) ||
1457          (nY > nHitBottom) )
1458     {
1459         pHitTest->nPos = 0;
1460         pHitTest->eType = RulerType::Outside;
1461         return false;
1462     }
1463 
1464     nX -= mpData->nNullVirOff;
1465     pHitTest->nPos  = nX;
1466     pHitTest->eType = RulerType::DontKnow;
1467 
1468     // first test the tabs
1469     tools::Rectangle aRect;
1470     if ( !mpData->pTabs.empty() )
1471     {
1472         aRect.SetBottom( nHitBottom );
1473         aRect.SetTop( aRect.Bottom() - ruler_tab.height - RULER_OFF );
1474 
1475         for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1476         {
1477             nStyle = mpData->pTabs[i].nStyle;
1478             if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1479             {
1480                 nStyle &= RULER_TAB_STYLE;
1481 
1482                 // default tabs are only shown (no action)
1483                 if ( nStyle != RULER_TAB_DEFAULT )
1484                 {
1485                     n1 = mpData->pTabs[i].nPos;
1486 
1487                     if ( nStyle == RULER_TAB_LEFT )
1488                     {
1489                         aRect.SetLeft( n1 );
1490                         aRect.SetRight( n1 + ruler_tab.width - 1 );
1491                     }
1492                     else if ( nStyle == RULER_TAB_RIGHT )
1493                     {
1494                         aRect.SetRight( n1 );
1495                         aRect.SetLeft( n1 - ruler_tab.width - 1 );
1496                     }
1497                     else
1498                     {
1499                         aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1500                         aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1501                     }
1502 
1503                     if ( aRect.IsInside( Point( nX, nY ) ) )
1504                     {
1505                         pHitTest->eType   = RulerType::Tab;
1506                         pHitTest->nAryPos = i;
1507                         return true;
1508                     }
1509                 }
1510             }
1511         }
1512     }
1513 
1514     // Indents
1515     if ( !mpData->pIndents.empty() )
1516     {
1517         tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
1518         tools::Long nIndentWidth2 = nIndentHeight - 3;
1519 
1520         for ( i = mpData->pIndents.size(); i; i-- )
1521         {
1522             RulerIndentStyle nIndentStyle = mpData->pIndents[i-1].nStyle;
1523             if ( (! bRequireStyle || nIndentStyle == nRequiredStyle) &&
1524                  !mpData->pIndents[i-1].bInvisible )
1525             {
1526                 n1 = mpData->pIndents[i-1].nPos;
1527 
1528                 if ( (nIndentStyle == RulerIndentStyle::Bottom) != !bIsHori )
1529                 {
1530                     aRect.SetLeft( n1-nIndentWidth2 );
1531                     aRect.SetRight( n1+nIndentWidth2 );
1532                     aRect.SetTop( nHitBottom-nIndentHeight-RULER_OFF+1 );
1533                     aRect.SetBottom( nHitBottom );
1534                 }
1535                 else
1536                 {
1537                     aRect.SetLeft( n1-nIndentWidth2 );
1538                     aRect.SetRight( n1+nIndentWidth2 );
1539                     aRect.SetTop( 0 );
1540                     aRect.SetBottom( nIndentHeight+RULER_OFF-1 );
1541                 }
1542 
1543                 if ( aRect.IsInside( Point( nX, nY ) ) )
1544                 {
1545                     pHitTest->eType     = RulerType::Indent;
1546                     pHitTest->nAryPos   = i-1;
1547                     return true;
1548                 }
1549             }
1550         }
1551     }
1552 
1553     // test the borders
1554     int nBorderTolerance = 1;
1555     if(pHitTest->bExpandTest)
1556     {
1557         nBorderTolerance++;
1558     }
1559 
1560     for ( i = mpData->pBorders.size(); i; i-- )
1561     {
1562         n1 = mpData->pBorders[i-1].nPos;
1563         tools::Long n2 = n1 + mpData->pBorders[i-1].nWidth;
1564 
1565         // borders have at least 3 pixel padding
1566         if ( !mpData->pBorders[i-1].nWidth )
1567         {
1568              n1 -= nBorderTolerance;
1569              n2 += nBorderTolerance;
1570 
1571         }
1572 
1573         if ( (nX >= n1) && (nX <= n2) )
1574         {
1575             RulerBorderStyle nBorderStyle = mpData->pBorders[i-1].nStyle;
1576             if ( !(nBorderStyle & RulerBorderStyle::Invisible) )
1577             {
1578                 pHitTest->eType     = RulerType::Border;
1579                 pHitTest->nAryPos   = i-1;
1580 
1581                 if ( !(nBorderStyle & RulerBorderStyle::Sizeable) )
1582                 {
1583                     if ( nBorderStyle & RulerBorderStyle::Moveable )
1584                     {
1585                         pHitTest->bSizeBar = true;
1586                         pHitTest->mnDragSize = RulerDragSize::Move;
1587                     }
1588                 }
1589                 else
1590                 {
1591                     tools::Long nMOff = RULER_MOUSE_BORDERWIDTH;
1592                     while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) )
1593                     {
1594                         if ( nMOff < 2 )
1595                         {
1596                             nMOff = 0;
1597                             break;
1598                         }
1599                         else
1600                             nMOff--;
1601                     }
1602 
1603                     if ( nX <= n1+nMOff )
1604                     {
1605                         pHitTest->bSize = true;
1606                         pHitTest->mnDragSize = RulerDragSize::N1;
1607                     }
1608                     else if ( nX >= n2-nMOff )
1609                     {
1610                         pHitTest->bSize = true;
1611                         pHitTest->mnDragSize = RulerDragSize::N2;
1612                     }
1613                     else
1614                     {
1615                         if ( nBorderStyle & RulerBorderStyle::Moveable )
1616                         {
1617                             pHitTest->bSizeBar = true;
1618                             pHitTest->mnDragSize = RulerDragSize::Move;
1619                         }
1620                     }
1621                 }
1622 
1623                 return true;
1624             }
1625         }
1626     }
1627 
1628     // Margins
1629     int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH;
1630 
1631     if ( (mpData->nMargin1Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1632     {
1633         n1 = mpData->nMargin1;
1634         if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1635         {
1636             pHitTest->eType = RulerType::Margin1;
1637             pHitTest->bSize = true;
1638             return true;
1639         }
1640     }
1641     if ( (mpData->nMargin2Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1642     {
1643         n1 = mpData->nMargin2;
1644         if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1645         {
1646             pHitTest->eType = RulerType::Margin2;
1647             pHitTest->bSize = true;
1648             return true;
1649         }
1650     }
1651 
1652     // test tabs again
1653     if ( !mpData->pTabs.empty() )
1654     {
1655         aRect.SetTop( RULER_OFF );
1656         aRect.SetBottom( nHitBottom );
1657 
1658         for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1659         {
1660             nStyle = mpData->pTabs[i].nStyle;
1661             if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1662             {
1663                 nStyle &= RULER_TAB_STYLE;
1664 
1665                 // default tabs are only shown (no action)
1666                 if ( nStyle != RULER_TAB_DEFAULT )
1667                 {
1668                     n1 = mpData->pTabs[i].nPos;
1669 
1670                     if ( nStyle == RULER_TAB_LEFT )
1671                     {
1672                         aRect.SetLeft( n1 );
1673                         aRect.SetRight( n1 + ruler_tab.width - 1 );
1674                     }
1675                     else if ( nStyle == RULER_TAB_RIGHT )
1676                     {
1677                         aRect.SetRight( n1 );
1678                         aRect.SetLeft( n1 - ruler_tab.width - 1 );
1679                     }
1680                     else
1681                     {
1682                         aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1683                         aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1684                     }
1685 
1686                     aRect.AdjustLeft( -1 );
1687                     aRect.AdjustRight( 1 );
1688 
1689                     if ( aRect.IsInside( Point( nX, nY ) ) )
1690                     {
1691                         pHitTest->eType   = RulerType::Tab;
1692                         pHitTest->nAryPos = i;
1693                         return true;
1694                     }
1695                 }
1696             }
1697         }
1698     }
1699 
1700     return false;
1701 }
1702 
ImplDocHitTest(const Point & rPos,RulerType eDragType,RulerSelection * pHitTest) const1703 bool Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType,
1704                                 RulerSelection* pHitTest ) const
1705 {
1706     Point aPos = rPos;
1707     bool bRequiredStyle = false;
1708     RulerIndentStyle nRequiredStyle = RulerIndentStyle::Top;
1709 
1710     if (eDragType == RulerType::Indent)
1711     {
1712         bRequiredStyle = true;
1713         nRequiredStyle = RulerIndentStyle::Bottom;
1714     }
1715 
1716     if ( mnWinStyle & WB_HORZ )
1717         aPos.AdjustX(mnWinOff );
1718     else
1719         aPos.AdjustY(mnWinOff );
1720 
1721     if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::DontKnow) )
1722     {
1723         if ( mnWinStyle & WB_HORZ )
1724             aPos.setY( RULER_OFF + 1 );
1725         else
1726             aPos.setX( RULER_OFF + 1 );
1727 
1728         if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) )
1729         {
1730             if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1731                 return true;
1732         }
1733     }
1734 
1735     if ( (eDragType == RulerType::Indent) ||
1736          (eDragType == RulerType::Tab) ||
1737          (eDragType == RulerType::DontKnow) )
1738     {
1739         if ( mnWinStyle & WB_HORZ )
1740             aPos.setY( mnHeight - RULER_OFF - 1 );
1741         else
1742             aPos.setX( mnWidth - RULER_OFF - 1 );
1743 
1744         if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) )
1745         {
1746             if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1747                 return true;
1748         }
1749     }
1750 
1751     if ( (eDragType == RulerType::Margin1) || (eDragType == RulerType::Margin2) ||
1752          (eDragType == RulerType::Border) || (eDragType == RulerType::DontKnow) )
1753     {
1754         if ( mnWinStyle & WB_HORZ )
1755             aPos.setY( RULER_OFF + (mnVirHeight / 2) );
1756         else
1757             aPos.setX( RULER_OFF + (mnVirHeight / 2) );
1758 
1759         if ( ImplDoHitTest( aPos, pHitTest ) )
1760         {
1761             if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1762                 return true;
1763         }
1764     }
1765 
1766     pHitTest->eType = RulerType::DontKnow;
1767 
1768     return false;
1769 }
1770 
ImplStartDrag(RulerSelection const * pHitTest,sal_uInt16 nModifier)1771 bool Ruler::ImplStartDrag( RulerSelection const * pHitTest, sal_uInt16 nModifier )
1772 {
1773     // don't trigger drag if a border that was clicked can not be changed
1774     if ( (pHitTest->eType == RulerType::Border) &&
1775          !pHitTest->bSize && !pHitTest->bSizeBar )
1776         return false;
1777 
1778     // Set drag data
1779     meDragType      = pHitTest->eType;
1780     mnDragPos       = pHitTest->nPos;
1781     mnDragAryPos    = pHitTest->nAryPos;
1782     mnDragSize      = pHitTest->mnDragSize;
1783     mnDragModifier  = nModifier;
1784     *mpDragData     = *mpSaveData;
1785     mpData          = mpDragData.get();
1786 
1787     // call handler
1788     if (StartDrag())
1789     {
1790         // if the handler allows dragging, initialize dragging
1791         mbDrag = true;
1792         mnStartDragPos = mnDragPos;
1793         StartTracking();
1794         Invalidate(InvalidateFlags::NoErase);
1795         return true;
1796     }
1797     else
1798     {
1799         // otherwise reset the data
1800         meDragType      = RulerType::DontKnow;
1801         mnDragPos       = 0;
1802         mnDragAryPos    = 0;
1803         mnDragSize      = RulerDragSize::Move;
1804         mnDragModifier  = 0;
1805         mpData          = mpSaveData.get();
1806     }
1807 
1808     return false;
1809 }
1810 
ImplDrag(const Point & rPos)1811 void Ruler::ImplDrag( const Point& rPos )
1812 {
1813     tools::Long  nX;
1814     tools::Long  nY;
1815     tools::Long  nOutHeight;
1816 
1817     if ( mnWinStyle & WB_HORZ )
1818     {
1819         nX          = rPos.X();
1820         nY          = rPos.Y();
1821         nOutHeight  = mnHeight;
1822     }
1823     else
1824     {
1825         nX          = rPos.Y();
1826         nY          = rPos.X();
1827         nOutHeight  = mnWidth;
1828     }
1829 
1830     // calculate and fit X
1831     nX -= mnVirOff;
1832     if ( nX < mpData->nRulVirOff )
1833     {
1834         nX = mpData->nRulVirOff;
1835     }
1836     else if ( nX > mpData->nRulVirOff+mpData->nRulWidth )
1837     {
1838         nX = mpData->nRulVirOff+mpData->nRulWidth;
1839     }
1840     nX -= mpData->nNullVirOff;
1841 
1842     // if upper or left from ruler, then consider old values
1843     mbDragDelete = false;
1844     if ( nY < 0 )
1845     {
1846         if ( !mbDragCanceled )
1847         {
1848             // reset the data
1849             mbDragCanceled = true;
1850             ImplRulerData aTempData = *mpDragData;
1851             *mpDragData = *mpSaveData;
1852             mbCalc = true;
1853             mbFormat = true;
1854 
1855             // call handler
1856             mnDragPos = mnStartDragPos;
1857             Drag();
1858 
1859             // and redraw
1860             Invalidate(InvalidateFlags::NoErase);
1861 
1862             // reset the data as before cancel
1863             *mpDragData = aTempData;
1864         }
1865     }
1866     else
1867     {
1868         mbDragCanceled = false;
1869 
1870         // +2, so the tabs are not cleared too quickly
1871         if ( nY > nOutHeight + 2 )
1872             mbDragDelete = true;
1873 
1874         mnDragPos = nX;
1875 
1876         // call handler
1877         Drag();
1878 
1879         // redraw
1880         if (mbFormat)
1881             Invalidate(InvalidateFlags::NoErase);
1882     }
1883 }
1884 
ImplEndDrag()1885 void Ruler::ImplEndDrag()
1886 {
1887     // get values
1888     if ( mbDragCanceled )
1889         *mpDragData = *mpSaveData;
1890     else
1891         *mpSaveData = *mpDragData;
1892 
1893     mpData = mpSaveData.get();
1894     mbDrag = false;
1895 
1896     // call handler
1897     EndDrag();
1898 
1899     // reset drag values
1900     meDragType      = RulerType::DontKnow;
1901     mnDragPos       = 0;
1902     mnDragAryPos    = 0;
1903     mnDragSize      = RulerDragSize::Move;
1904     mbDragCanceled  = false;
1905     mbDragDelete    = false;
1906     mnDragModifier  = 0;
1907     mnStartDragPos  = 0;
1908 
1909     // redraw
1910     Invalidate(InvalidateFlags::NoErase);
1911 }
1912 
MouseButtonDown(const MouseEvent & rMEvt)1913 void Ruler::MouseButtonDown( const MouseEvent& rMEvt )
1914 {
1915     if ( !rMEvt.IsLeft() || IsTracking() )
1916         return;
1917 
1918     Point   aMousePos = rMEvt.GetPosPixel();
1919     sal_uInt16  nMouseClicks = rMEvt.GetClicks();
1920     sal_uInt16  nMouseModifier = rMEvt.GetModifier();
1921 
1922     // update ruler
1923     if ( mbFormat )
1924     {
1925         Invalidate(InvalidateFlags::NoErase);
1926     }
1927 
1928     if ( maExtraRect.IsInside( aMousePos ) )
1929     {
1930         ExtraDown();
1931     }
1932     else
1933     {
1934         RulerSelection aHitTest;
1935         bool bHitTestResult = ImplDoHitTest(aMousePos, &aHitTest);
1936 
1937         if ( nMouseClicks == 1 )
1938         {
1939             if ( bHitTestResult )
1940             {
1941                 ImplStartDrag( &aHitTest, nMouseModifier );
1942             }
1943             else
1944             {
1945                 // calculate position inside of ruler area
1946                 if ( aHitTest.eType == RulerType::DontKnow )
1947                 {
1948                     mnDragPos = aHitTest.nPos;
1949                     Click();
1950                     mnDragPos = 0;
1951 
1952                     // call HitTest again as a click, for example, could set a new tab
1953                     if ( ImplDoHitTest(aMousePos, &aHitTest) )
1954                         ImplStartDrag(&aHitTest, nMouseModifier);
1955                 }
1956             }
1957         }
1958         else
1959         {
1960             if (bHitTestResult)
1961             {
1962                 mnDragPos    = aHitTest.nPos;
1963                 mnDragAryPos = aHitTest.nAryPos;
1964             }
1965             meDragType = aHitTest.eType;
1966 
1967             DoubleClick();
1968 
1969             meDragType      = RulerType::DontKnow;
1970             mnDragPos       = 0;
1971             mnDragAryPos    = 0;
1972         }
1973     }
1974 }
1975 
MouseMove(const MouseEvent & rMEvt)1976 void Ruler::MouseMove( const MouseEvent& rMEvt )
1977 {
1978     PointerStyle ePtrStyle = PointerStyle::Arrow;
1979 
1980     mxPreviousHitTest.swap(mxCurrentHitTest);
1981 
1982     mxCurrentHitTest.reset(new RulerSelection);
1983 
1984     maHoverSelection.eType = RulerType::DontKnow;
1985 
1986     if (ImplDoHitTest( rMEvt.GetPosPixel(), mxCurrentHitTest.get() ))
1987     {
1988         maHoverSelection = *mxCurrentHitTest;
1989 
1990         if (mxCurrentHitTest->bSize)
1991         {
1992             if (mnWinStyle & WB_HORZ)
1993             {
1994                 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
1995                     ePtrStyle = PointerStyle::TabSelectW;
1996                 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
1997                     ePtrStyle = PointerStyle::TabSelectE;
1998                 else
1999                     ePtrStyle = PointerStyle::ESize;
2000             }
2001             else
2002             {
2003                 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
2004                     ePtrStyle = PointerStyle::WindowNSize;
2005                 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2006                     ePtrStyle = PointerStyle::WindowSSize;
2007                 else
2008                     ePtrStyle = PointerStyle::SSize;
2009             }
2010         }
2011         else if (mxCurrentHitTest->bSizeBar)
2012         {
2013             if (mnWinStyle & WB_HORZ)
2014                 ePtrStyle = PointerStyle::HSizeBar;
2015             else
2016                 ePtrStyle = PointerStyle::VSizeBar;
2017         }
2018     }
2019 
2020     if (mxPreviousHitTest != nullptr && mxPreviousHitTest->eType != mxCurrentHitTest->eType)
2021     {
2022         mbFormat = true;
2023     }
2024 
2025     SetPointer( ePtrStyle );
2026 
2027     if (mbFormat)
2028     {
2029         Invalidate(InvalidateFlags::NoErase);
2030     }
2031 }
2032 
Tracking(const TrackingEvent & rTEvt)2033 void Ruler::Tracking( const TrackingEvent& rTEvt )
2034 {
2035     if ( rTEvt.IsTrackingEnded() )
2036     {
2037         // reset the old state at cancel
2038         if ( rTEvt.IsTrackingCanceled() )
2039         {
2040             mbDragCanceled = true;
2041             mbFormat       = true;
2042         }
2043 
2044         ImplEndDrag();
2045     }
2046     else
2047         ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() );
2048 }
2049 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)2050 void Ruler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2051 {
2052     ImplDraw(rRenderContext);
2053 
2054     // consider extra field
2055     if (mnWinStyle & WB_EXTRAFIELD)
2056         ImplDrawExtra(rRenderContext);
2057 }
2058 
Resize()2059 void Ruler::Resize()
2060 {
2061     Size aWinSize = GetOutputSizePixel();
2062 
2063     tools::Long nNewHeight;
2064     if ( mnWinStyle & WB_HORZ )
2065     {
2066         if ( aWinSize.Height() != mnHeight )
2067             nNewHeight = aWinSize.Height();
2068         else
2069             nNewHeight = 0;
2070     }
2071     else
2072     {
2073         if ( aWinSize.Width() != mnWidth )
2074             nNewHeight = aWinSize.Width();
2075         else
2076             nNewHeight = 0;
2077     }
2078 
2079     mbFormat = true;
2080 
2081     // clear lines
2082     bool bVisible = IsReallyVisible();
2083     if ( bVisible && !mpData->pLines.empty() )
2084     {
2085         mnUpdateFlags |= RULER_UPDATE_LINES;
2086         Invalidate(InvalidateFlags::NoErase);
2087     }
2088 
2089     // recalculate some values if the height/width changes
2090     // extra field should always be updated
2091     ImplInitExtraField( mpData->bTextRTL );
2092     if ( nNewHeight )
2093     {
2094         mbCalc = true;
2095         mnVirHeight = nNewHeight - mnBorderWidth - ( RULER_OFF * 2 );
2096     }
2097     else
2098     {
2099         if ( mpData->bAutoPageWidth )
2100             ImplUpdate( true );
2101         else if ( mbAutoWinWidth )
2102             mbCalc = true;
2103     }
2104 
2105     // clear part of the border
2106     if ( bVisible )
2107     {
2108         if ( nNewHeight )
2109             Invalidate(InvalidateFlags::NoErase);
2110         else if ( mpData->bAutoPageWidth )
2111         {
2112             // only at AutoPageWidth do we need to redraw
2113             tools::Rectangle aRect;
2114 
2115             if ( mnWinStyle & WB_HORZ )
2116             {
2117                 if ( mnWidth < aWinSize.Width() )
2118                     aRect.SetLeft( mnWidth - RULER_RESIZE_OFF );
2119                 else
2120                     aRect.SetLeft( aWinSize.Width() - RULER_RESIZE_OFF );
2121                 aRect.SetRight( aRect.Left() + RULER_RESIZE_OFF );
2122                 aRect.SetTop( RULER_OFF );
2123                 aRect.SetBottom( RULER_OFF + mnVirHeight );
2124             }
2125             else
2126             {
2127                 if ( mnHeight < aWinSize.Height() )
2128                     aRect.SetTop( mnHeight-RULER_RESIZE_OFF );
2129                 else
2130                     aRect.SetTop( aWinSize.Height()-RULER_RESIZE_OFF );
2131                 aRect.SetBottom( aRect.Top() + RULER_RESIZE_OFF );
2132                 aRect.SetLeft( RULER_OFF );
2133                 aRect.SetRight( RULER_OFF + mnVirHeight );
2134             }
2135 
2136             Invalidate(aRect, InvalidateFlags::NoErase);
2137         }
2138     }
2139 
2140     mnWidth  = aWinSize.Width();
2141     mnHeight = aWinSize.Height();
2142 }
2143 
StateChanged(StateChangedType nType)2144 void Ruler::StateChanged( StateChangedType nType )
2145 {
2146     Window::StateChanged( nType );
2147 
2148     if ( nType == StateChangedType::InitShow )
2149         Invalidate();
2150     else if ( nType == StateChangedType::UpdateMode )
2151     {
2152         if ( IsReallyVisible() && IsUpdateMode() )
2153             Invalidate();
2154     }
2155     else if ( (nType == StateChangedType::Zoom) ||
2156               (nType == StateChangedType::ControlFont) )
2157     {
2158         ImplInitSettings( true, false, false );
2159         Invalidate();
2160     }
2161     else if ( nType == StateChangedType::ControlForeground )
2162     {
2163         ImplInitSettings( false, true, false );
2164         Invalidate();
2165     }
2166     else if ( nType == StateChangedType::ControlBackground )
2167     {
2168         ImplInitSettings( false, false, true );
2169         Invalidate();
2170     }
2171 }
2172 
DataChanged(const DataChangedEvent & rDCEvt)2173 void Ruler::DataChanged( const DataChangedEvent& rDCEvt )
2174 {
2175     Window::DataChanged( rDCEvt );
2176 
2177     if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2178          (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
2179          (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2180          ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2181           (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2182     {
2183         mbFormat = true;
2184         ImplInitSettings( true, true, true );
2185         Invalidate();
2186     }
2187 }
2188 
StartDrag()2189 bool Ruler::StartDrag()
2190 {
2191     return false;
2192 }
2193 
Drag()2194 void Ruler::Drag()
2195 {
2196 }
2197 
EndDrag()2198 void Ruler::EndDrag()
2199 {
2200 }
2201 
Click()2202 void Ruler::Click()
2203 {
2204 }
2205 
DoubleClick()2206 void Ruler::DoubleClick()
2207 {
2208     maDoubleClickHdl.Call( this );
2209 }
2210 
ExtraDown()2211 void Ruler::ExtraDown()
2212 {
2213 }
2214 
Activate()2215 void Ruler::Activate()
2216 {
2217     mbActive = true;
2218 
2219     // update positionlines - draw is delayed
2220     mnUpdateFlags |= RULER_UPDATE_LINES;
2221     Invalidate(InvalidateFlags::NoErase);
2222 }
2223 
Deactivate()2224 void Ruler::Deactivate()
2225 {
2226     // clear positionlines
2227     Invalidate(InvalidateFlags::NoErase);
2228 
2229     mbActive = false;
2230 }
2231 
StartDocDrag(const MouseEvent & rMEvt,RulerType eDragType)2232 bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType )
2233 {
2234     if ( !mbDrag )
2235     {
2236         Point          aMousePos = rMEvt.GetPosPixel();
2237         sal_uInt16     nMouseClicks = rMEvt.GetClicks();
2238         sal_uInt16     nMouseModifier = rMEvt.GetModifier();
2239         RulerSelection aHitTest;
2240 
2241         if(eDragType != RulerType::DontKnow)
2242             aHitTest.bExpandTest = true;
2243 
2244         // update ruler
2245         if ( mbFormat )
2246         {
2247             if (!IsReallyVisible())
2248             {
2249                 // set mpData for ImplDocHitTest()
2250                 ImplFormat(*GetOutDev());
2251             }
2252 
2253             Invalidate(InvalidateFlags::NoErase);
2254         }
2255 
2256         if ( nMouseClicks == 1 )
2257         {
2258             if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) )
2259             {
2260                 PointerStyle aPtr = PointerStyle::Arrow;
2261 
2262                 if ( aHitTest.bSize )
2263                 {
2264                     if ( mnWinStyle & WB_HORZ )
2265                         aPtr = PointerStyle::ESize;
2266                     else
2267                         aPtr = PointerStyle::SSize;
2268                 }
2269                 else if ( aHitTest.bSizeBar )
2270                 {
2271                     if ( mnWinStyle & WB_HORZ )
2272                         aPtr = PointerStyle::HSizeBar;
2273                     else
2274                         aPtr = PointerStyle::VSizeBar;
2275                 }
2276                 SetPointer( aPtr );
2277                 return ImplStartDrag( &aHitTest, nMouseModifier );
2278             }
2279         }
2280         else if ( nMouseClicks == 2 )
2281         {
2282             if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) )
2283             {
2284                 mnDragPos    = aHitTest.nPos;
2285                 mnDragAryPos = aHitTest.nAryPos;
2286             }
2287 
2288             DoubleClick();
2289 
2290             mnDragPos       = 0;
2291             mnDragAryPos    = 0;
2292 
2293             return true;
2294         }
2295     }
2296 
2297     return false;
2298 }
2299 
CancelDrag()2300 void Ruler::CancelDrag()
2301 {
2302     if ( mbDrag )
2303     {
2304         ImplDrag( Point( -1, -1 ) );
2305         ImplEndDrag();
2306     }
2307 }
2308 
GetRulerType(const Point & rPos,sal_uInt16 * pAryPos)2309 RulerType Ruler::GetRulerType( const Point& rPos, sal_uInt16* pAryPos )
2310 {
2311     RulerSelection aHitTest;
2312 
2313     // update ruler
2314     if ( IsReallyVisible() && mbFormat )
2315     {
2316         Invalidate(InvalidateFlags::NoErase);
2317     }
2318 
2319     (void)ImplDoHitTest(rPos, &aHitTest);
2320 
2321     // return values
2322     if ( pAryPos )
2323         *pAryPos = aHitTest.nAryPos;
2324     return aHitTest.eType;
2325 }
2326 
SetWinPos(tools::Long nNewOff,tools::Long nNewWidth)2327 void Ruler::SetWinPos( tools::Long nNewOff, tools::Long nNewWidth )
2328 {
2329     // should widths be automatically calculated
2330     if ( !nNewWidth )
2331         mbAutoWinWidth = true;
2332     else
2333         mbAutoWinWidth = false;
2334 
2335     mnWinOff = nNewOff;
2336     mnWinWidth = nNewWidth;
2337     ImplUpdate( true );
2338 }
2339 
SetPagePos(tools::Long nNewOff,tools::Long nNewWidth)2340 void Ruler::SetPagePos( tools::Long nNewOff, tools::Long nNewWidth )
2341 {
2342     // should we do anything?
2343     if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) )
2344         return;
2345 
2346     // should widths be automatically calculated
2347     if ( !nNewWidth )
2348         mpData->bAutoPageWidth = true;
2349     else
2350         mpData->bAutoPageWidth = false;
2351 
2352     mpData->nPageOff     = nNewOff;
2353     mpData->nPageWidth   = nNewWidth;
2354     ImplUpdate( true );
2355 }
2356 
SetBorderPos(tools::Long nOff)2357 void Ruler::SetBorderPos( tools::Long nOff )
2358 {
2359     if ( mnWinStyle & WB_BORDER )
2360     {
2361         if ( mnBorderOff != nOff )
2362         {
2363             mnBorderOff = nOff;
2364 
2365             if ( IsReallyVisible() && IsUpdateMode() )
2366                 Invalidate(InvalidateFlags::NoErase);
2367         }
2368     }
2369 }
2370 
SetUnit(FieldUnit eNewUnit)2371 void Ruler::SetUnit( FieldUnit eNewUnit )
2372 {
2373     if ( meUnit == eNewUnit )
2374         return;
2375 
2376     meUnit = eNewUnit;
2377     switch ( meUnit )
2378     {
2379         case FieldUnit::MM:
2380             mnUnitIndex = RULER_UNIT_MM;
2381             break;
2382         case FieldUnit::CM:
2383             mnUnitIndex = RULER_UNIT_CM;
2384             break;
2385         case FieldUnit::M:
2386             mnUnitIndex = RULER_UNIT_M;
2387             break;
2388         case FieldUnit::KM:
2389             mnUnitIndex = RULER_UNIT_KM;
2390             break;
2391         case FieldUnit::INCH:
2392             mnUnitIndex = RULER_UNIT_INCH;
2393             break;
2394         case FieldUnit::FOOT:
2395             mnUnitIndex = RULER_UNIT_FOOT;
2396             break;
2397         case FieldUnit::MILE:
2398             mnUnitIndex = RULER_UNIT_MILE;
2399             break;
2400         case FieldUnit::POINT:
2401             mnUnitIndex = RULER_UNIT_POINT;
2402             break;
2403         case FieldUnit::PICA:
2404             mnUnitIndex = RULER_UNIT_PICA;
2405             break;
2406         case FieldUnit::CHAR:
2407             mnUnitIndex = RULER_UNIT_CHAR;
2408             break;
2409         case FieldUnit::LINE:
2410             mnUnitIndex = RULER_UNIT_LINE;
2411             break;
2412         default:
2413             SAL_WARN( "svtools.control", "Ruler::SetUnit() - Wrong Unit" );
2414             break;
2415     }
2416 
2417     maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit );
2418     ImplUpdate();
2419 }
2420 
SetZoom(const Fraction & rNewZoom)2421 void Ruler::SetZoom( const Fraction& rNewZoom )
2422 {
2423     DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" );
2424 
2425     if ( maZoom != rNewZoom )
2426     {
2427         maZoom = rNewZoom;
2428         maMapMode.SetScaleX( maZoom );
2429         maMapMode.SetScaleY( maZoom );
2430         ImplUpdate();
2431     }
2432 }
2433 
SetExtraType(RulerExtra eNewExtraType,sal_uInt16 nStyle)2434 void Ruler::SetExtraType( RulerExtra eNewExtraType, sal_uInt16 nStyle )
2435 {
2436     if ( mnWinStyle & WB_EXTRAFIELD )
2437     {
2438         meExtraType  = eNewExtraType;
2439         mnExtraStyle = nStyle;
2440         if (IsReallyVisible() && IsUpdateMode())
2441             Invalidate();
2442     }
2443 }
2444 
SetNullOffset(tools::Long nPos)2445 void Ruler::SetNullOffset( tools::Long nPos )
2446 {
2447     if ( mpData->nNullOff != nPos )
2448     {
2449         mpData->nNullVirOff += nPos - mpData->nNullOff;
2450         mpData->nNullOff = nPos;
2451         ImplUpdate();
2452     }
2453 }
2454 
SetLeftFrameMargin(tools::Long nPos)2455 void Ruler::SetLeftFrameMargin( tools::Long nPos )
2456 {
2457     if ( mpData->nLeftFrameMargin != nPos )
2458     {
2459         mpData->nLeftFrameMargin  = nPos;
2460         ImplUpdate();
2461     }
2462 }
2463 
SetRightFrameMargin(tools::Long nPos)2464 void Ruler::SetRightFrameMargin( tools::Long nPos )
2465 {
2466     if ( mpData->nRightFrameMargin != nPos )
2467     {
2468         mpData->nRightFrameMargin  = nPos;
2469         ImplUpdate();
2470     }
2471 }
2472 
SetMargin1(tools::Long nPos,RulerMarginStyle nMarginStyle)2473 void Ruler::SetMargin1( tools::Long nPos, RulerMarginStyle nMarginStyle )
2474 {
2475     if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) )
2476     {
2477         mpData->nMargin1      = nPos;
2478         mpData->nMargin1Style = nMarginStyle;
2479         ImplUpdate();
2480     }
2481 }
2482 
SetMargin2(tools::Long nPos,RulerMarginStyle nMarginStyle)2483 void Ruler::SetMargin2( tools::Long nPos, RulerMarginStyle nMarginStyle )
2484 {
2485     DBG_ASSERT( (nPos >= mpData->nMargin1) ||
2486                 (mpData->nMargin1Style & RulerMarginStyle::Invisible) ||
2487                 (mpData->nMargin2Style & RulerMarginStyle::Invisible),
2488                 "Ruler::SetMargin2() - Margin2 < Margin1" );
2489 
2490     if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) )
2491     {
2492         mpData->nMargin2      = nPos;
2493         mpData->nMargin2Style = nMarginStyle;
2494         ImplUpdate();
2495     }
2496 }
2497 
SetLines(sal_uInt32 aLineArraySize,const RulerLine * pLineArray)2498 void Ruler::SetLines( sal_uInt32 aLineArraySize, const RulerLine* pLineArray )
2499 {
2500     // To determine if what has changed
2501     if ( mpData->pLines.size() == aLineArraySize )
2502     {
2503         sal_uInt32           i = aLineArraySize;
2504         vector<RulerLine>::const_iterator aItr1 = mpData->pLines.begin();
2505         const RulerLine* pAry2 = pLineArray;
2506         while ( i )
2507         {
2508             if ( aItr1->nPos   != pAry2->nPos )
2509                 break;
2510             ++aItr1;
2511             ++pAry2;
2512             i--;
2513         }
2514         if ( !i )
2515             return;
2516     }
2517 
2518     // New values and new share issue
2519     bool bMustUpdate;
2520     bMustUpdate = IsReallyVisible() && IsUpdateMode();
2521 
2522     // Delete old lines
2523     if ( bMustUpdate )
2524         Invalidate(InvalidateFlags::NoErase);
2525 
2526     // New data set
2527     if ( !aLineArraySize || !pLineArray )
2528     {
2529         if ( mpData->pLines.empty() )
2530             return;
2531         mpData->pLines.clear();
2532     }
2533     else
2534     {
2535         if ( mpData->pLines.size() != aLineArraySize )
2536         {
2537             mpData->pLines.resize(aLineArraySize);
2538         }
2539 
2540         std::copy( pLineArray,
2541                    pLineArray + aLineArraySize,
2542                    mpData->pLines.begin() );
2543 
2544         if ( bMustUpdate )
2545             Invalidate(InvalidateFlags::NoErase);
2546     }
2547 }
2548 
SetBorders(sal_uInt32 aBorderArraySize,const RulerBorder * pBorderArray)2549 void Ruler::SetBorders( sal_uInt32 aBorderArraySize, const RulerBorder* pBorderArray )
2550 {
2551     if ( !aBorderArraySize || !pBorderArray )
2552     {
2553         if ( mpData->pBorders.empty() )
2554             return;
2555         mpData->pBorders.clear();
2556     }
2557     else
2558     {
2559         if ( mpData->pBorders.size() != aBorderArraySize )
2560         {
2561             mpData->pBorders.resize(aBorderArraySize);
2562         }
2563         else
2564         {
2565             sal_uInt32             i = aBorderArraySize;
2566             const RulerBorder* pAry1 = mpData->pBorders.data();
2567             const RulerBorder* pAry2 = pBorderArray;
2568             while ( i )
2569             {
2570                 if ( (pAry1->nPos   != pAry2->nPos)   ||
2571                      (pAry1->nWidth != pAry2->nWidth) ||
2572                      (pAry1->nStyle != pAry2->nStyle) )
2573                     break;
2574                 pAry1++;
2575                 pAry2++;
2576                 i--;
2577             }
2578             if ( !i )
2579                 return;
2580         }
2581         std::copy( pBorderArray,
2582                    pBorderArray + aBorderArraySize,
2583                    mpData->pBorders.begin() );
2584     }
2585 
2586     ImplUpdate();
2587 }
2588 
SetIndents(sal_uInt32 aIndentArraySize,const RulerIndent * pIndentArray)2589 void Ruler::SetIndents( sal_uInt32 aIndentArraySize, const RulerIndent* pIndentArray )
2590 {
2591 
2592     if ( !aIndentArraySize || !pIndentArray )
2593     {
2594         if ( mpData->pIndents.empty() )
2595             return;
2596         mpData->pIndents.clear();
2597     }
2598     else
2599     {
2600         if ( mpData->pIndents.size() != aIndentArraySize )
2601         {
2602             mpData->pIndents.resize(aIndentArraySize);
2603         }
2604         else
2605         {
2606             sal_uInt32             i = aIndentArraySize;
2607             const RulerIndent* pAry1 = mpData->pIndents.data();
2608             const RulerIndent* pAry2 = pIndentArray;
2609             while ( i )
2610             {
2611                 if ( (pAry1->nPos   != pAry2->nPos) ||
2612                      (pAry1->nStyle != pAry2->nStyle) )
2613                     break;
2614                 pAry1++;
2615                 pAry2++;
2616                 i--;
2617             }
2618             if ( !i )
2619                 return;
2620         }
2621 
2622         std::copy( pIndentArray,
2623                    pIndentArray + aIndentArraySize,
2624                    mpData->pIndents.begin() );
2625     }
2626 
2627     ImplUpdate();
2628 }
2629 
SetTabs(sal_uInt32 aTabArraySize,const RulerTab * pTabArray)2630 void Ruler::SetTabs( sal_uInt32 aTabArraySize, const RulerTab* pTabArray )
2631 {
2632     if ( aTabArraySize == 0 || pTabArray == nullptr )
2633     {
2634         if ( mpData->pTabs.empty() )
2635             return;
2636         mpData->pTabs.clear();
2637     }
2638     else
2639     {
2640         if ( mpData->pTabs.size() != aTabArraySize )
2641         {
2642             mpData->pTabs.resize(aTabArraySize);
2643         }
2644         else
2645         {
2646             sal_uInt32 i = aTabArraySize;
2647             vector<RulerTab>::iterator aTabIterator = mpData->pTabs.begin();
2648             const RulerTab* pInputArray = pTabArray;
2649             while ( i )
2650             {
2651                 RulerTab& aCurrent = *aTabIterator;
2652                 if ( aCurrent.nPos   != pInputArray->nPos ||
2653                      aCurrent.nStyle != pInputArray->nStyle )
2654                 {
2655                     break;
2656                 }
2657                 ++aTabIterator;
2658                 pInputArray++;
2659                 i--;
2660             }
2661             if ( !i )
2662                 return;
2663         }
2664         std::copy(pTabArray, pTabArray + aTabArraySize, mpData->pTabs.begin());
2665     }
2666 
2667     ImplUpdate();
2668 }
2669 
GetTabs() const2670 const std::vector<RulerTab>& Ruler::GetTabs() const
2671 {
2672     return mpData->pTabs;
2673 }
2674 
SetStyle(WinBits nStyle)2675 void Ruler::SetStyle( WinBits nStyle )
2676 {
2677     if ( mnWinStyle != nStyle )
2678     {
2679         mnWinStyle = nStyle;
2680         ImplInitExtraField( true );
2681     }
2682 }
2683 
DrawTab(vcl::RenderContext & rRenderContext,const Color & rFillColor,const Point & rPos,sal_uInt16 nStyle)2684 void Ruler::DrawTab(vcl::RenderContext& rRenderContext, const Color &rFillColor, const Point& rPos, sal_uInt16 nStyle)
2685 {
2686     Point aPos(rPos);
2687     sal_uInt16 nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL);
2688 
2689     rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
2690     rRenderContext.SetLineColor();
2691     rRenderContext.SetFillColor(rFillColor);
2692     ImplCenterTabPos(aPos, nTabStyle);
2693     ImplDrawRulerTab(rRenderContext, aPos, nTabStyle, nStyle);
2694     rRenderContext.Pop();
2695 }
2696 
SetTextRTL(bool bRTL)2697 void Ruler::SetTextRTL(bool bRTL)
2698 {
2699     if(mpData->bTextRTL != bRTL)
2700     {
2701         mpData->bTextRTL = bRTL;
2702         if ( IsReallyVisible() && IsUpdateMode() )
2703             ImplInitExtraField( true );
2704     }
2705 
2706 }
2707 
GetPageOffset() const2708 tools::Long Ruler::GetPageOffset() const
2709 {
2710     return mpData->nPageOff;
2711 }
2712 
GetNullOffset() const2713 tools::Long Ruler::GetNullOffset() const
2714 {
2715     return mpData->nNullOff;
2716 }
2717 
GetMargin1() const2718 tools::Long Ruler::GetMargin1() const
2719 {
2720     return mpData->nMargin1;
2721 }
2722 
GetMargin2() const2723 tools::Long Ruler::GetMargin2() const
2724 {
2725     return mpData->nMargin2;
2726 }
2727 
2728 
GetTextRTL() const2729 bool Ruler::GetTextRTL() const
2730 {
2731     return mpData->bTextRTL;
2732 }
2733 
GetCurrentRulerUnit() const2734 const RulerUnitData& Ruler::GetCurrentRulerUnit() const
2735 {
2736     return aImplRulerUnitTab[mnUnitIndex];
2737 }
2738 
DrawTicks()2739 void Ruler::DrawTicks()
2740 {
2741     mbFormat = true;
2742     Invalidate(InvalidateFlags::NoErase);
2743 }
2744 
CreateAccessible()2745 uno::Reference< XAccessible > Ruler::CreateAccessible()
2746 {
2747     vcl::Window* pParent = GetAccessibleParentWindow();
2748     OSL_ENSURE( pParent, "-SvxRuler::CreateAccessible(): No Parent!" );
2749     uno::Reference< XAccessible >   xAccParent  = pParent->GetAccessible();
2750     if( xAccParent.is() )
2751     {
2752         // MT: Fixed compiler issue because the address from a temporary object was used.
2753         // BUT: Should it really be a Pointer, instead of const&???
2754         OUString aStr;
2755         if ( mnWinStyle & WB_HORZ )
2756         {
2757             aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME);
2758         }
2759         else
2760         {
2761             aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME);
2762         }
2763         mxAccContext = new SvtRulerAccessible( xAccParent, *this, aStr );
2764         SetAccessible(mxAccContext);
2765         return mxAccContext;
2766     }
2767     else
2768         return uno::Reference< XAccessible >();
2769 }
2770 
2771 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2772