android: Update app-specific/MIME type icons
[LibreOffice.git] / svtools / source / control / ruler.cxx
blob6ddac0ccd7d34d3305f18edf827da8fda6ce520f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/debug.hxx>
21 #include <tools/poly.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/vcllayout.hxx>
25 #include <vcl/virdev.hxx>
26 #include <vcl/ptrstyle.hxx>
27 #include <sal/log.hxx>
29 #include <svtools/ruler.hxx>
30 #include <svtools/svtresid.hxx>
31 #include <svtools/strings.hrc>
32 #include <svtools/colorcfg.hxx>
33 #include "accessibleruler.hxx"
35 #include <memory>
36 #include <vector>
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::accessibility;
43 #define RULER_OFF 3
44 #define RULER_RESIZE_OFF 4
45 #define RULER_MIN_SIZE 3
47 #define RULER_VAR_SIZE 8
49 #define RULER_UPDATE_LINES 0x01
51 #define RULER_CLIP 150
53 #define RULER_UNIT_MM 0
54 #define RULER_UNIT_CM 1
55 #define RULER_UNIT_M 2
56 #define RULER_UNIT_KM 3
57 #define RULER_UNIT_INCH 4
58 #define RULER_UNIT_FOOT 5
59 #define RULER_UNIT_MILE 6
60 #define RULER_UNIT_POINT 7
61 #define RULER_UNIT_PICA 8
62 #define RULER_UNIT_CHAR 9
63 #define RULER_UNIT_LINE 10
64 #define RULER_UNIT_COUNT 11
66 namespace
68 /**
69 * Pre-calculates glyph items for rText on rRenderContext. Subsequent calls
70 * avoid the calculation and just return a pointer to rTextGlyphs.
72 SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext, const OUString& rText,
73 SalLayoutGlyphs& rTextGlyphs)
75 if (rTextGlyphs.IsValid())
76 // Use pre-calculated result.
77 return &rTextGlyphs;
79 // Calculate glyph items.
81 std::unique_ptr<SalLayout> pLayout = rRenderContext.ImplLayout(
82 rText, 0, rText.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly);
83 if (!pLayout)
84 return nullptr;
86 // Remember the calculation result.
87 rTextGlyphs = pLayout->GetGlyphs();
89 return &rTextGlyphs;
93 class ImplRulerData
95 friend class Ruler;
97 private:
98 std::vector<RulerLine> pLines;
99 std::vector<RulerBorder> pBorders;
100 std::vector<RulerIndent> pIndents;
101 std::vector<RulerTab> pTabs;
103 tools::Long nNullVirOff;
104 tools::Long nRulVirOff;
105 tools::Long nRulWidth;
106 tools::Long nPageOff;
107 tools::Long nPageWidth;
108 tools::Long nNullOff;
109 tools::Long nMargin1;
110 tools::Long nMargin2;
111 // In this context, "frame margin" means paragraph margins (indents)
112 tools::Long nLeftFrameMargin;
113 tools::Long nRightFrameMargin;
114 RulerMarginStyle nMargin1Style;
115 RulerMarginStyle nMargin2Style;
116 bool bAutoPageWidth;
117 bool bTextRTL;
119 public:
120 ImplRulerData();
123 ImplRulerData::ImplRulerData() :
124 nNullVirOff (0),
125 nRulVirOff (0),
126 nRulWidth (0),
127 nPageOff (0),
128 nPageWidth (0),
129 nNullOff (0),
130 nMargin1 (0),
131 nMargin2 (0),
132 nLeftFrameMargin (0),
133 nRightFrameMargin (0),
134 nMargin1Style (RulerMarginStyle::NONE),
135 nMargin2Style (RulerMarginStyle::NONE),
136 bAutoPageWidth (true), // Page width == EditWin width
137 bTextRTL (false)
141 const RulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] =
143 { MapUnit::Map100thMM, 100, 25.0, 25.0, 50.0, 100.0, " mm" }, // MM
144 { MapUnit::Map100thMM, 1000, 100.0, 500.0, 1000.0, 1000.0, " cm" }, // CM
145 { MapUnit::MapMM, 1000, 10.0, 250.0, 500.0, 1000.0, " m" }, // M
146 { MapUnit::MapCM, 100000, 12500.0, 25000.0, 50000.0, 100000.0, " km" }, // KM
147 { MapUnit::Map1000thInch, 1000, 62.5, 125.0, 500.0, 1000.0, "\"" }, // INCH
148 { MapUnit::Map100thInch, 1200, 120.0, 120.0, 600.0, 1200.0, "'" }, // FOOT
149 { MapUnit::Map10thInch, 633600, 63360.0, 63360.0, 316800.0, 633600.0, " miles" }, // MILE
150 { MapUnit::MapPoint, 1, 12.0, 12.0, 12.0, 36.0, " pt" }, // POINT
151 { MapUnit::Map100thMM, 423, 423.0, 423.0, 423.0, 846.0, " pc" }, // PICA
152 { MapUnit::Map100thMM, 371, 371.0, 371.0, 371.0, 743.0, " ch" }, // CHAR
153 { MapUnit::Map100thMM, 551, 551.0, 551.0, 551.0, 1102.0, " li" } // LINE
156 static RulerTabData ruler_tab =
158 0, // DPIScaleFactor to be set
159 7, // ruler_tab_width
160 6, // ruler_tab_height
161 2, // ruler_tab_height2
162 2, // ruler_tab_width2
163 8, // ruler_tab_cwidth
164 4, // ruler_tab_cwidth2
165 4, // ruler_tab_cwidth3
166 2, // ruler_tab_cwidth4
167 4, // ruler_tab_dheight
168 1, // ruler_tab_dheight2
169 5, // ruler_tab_dwidth
170 3, // ruler_tab_dwidth2
171 3, // ruler_tab_dwidth3
172 1, // ruler_tab_dwidth4
173 5 // ruler_tab_textoff
176 void Ruler::ImplInit( WinBits nWinBits )
178 // Set default WinBits
179 if ( !(nWinBits & WB_VERT) )
181 nWinBits |= WB_HORZ;
183 // RTL: no UI mirroring for horizontal rulers, because
184 // the document is also not mirrored
185 EnableRTL( false );
188 // Initialize variables
189 mnWinStyle = nWinBits; // Window-Style
190 mnBorderOff = 0; // Border-Offset
191 mnWinOff = 0; // EditWinOffset
192 mnWinWidth = 0; // EditWinWidth
193 mnWidth = 0; // Window width
194 mnHeight = 0; // Window height
195 mnVirOff = 0; // Offset of VirtualDevice from top-left corner
196 mnVirWidth = 0; // width or height from VirtualDevice
197 mnVirHeight = 0; // height of width from VirtualDevice
198 mnDragPos = 0; // Drag-Position (Null point)
199 mnDragAryPos = 0; // Drag-Array-Index
200 mnDragSize = RulerDragSize::Move; // Did size change at dragging
201 mnDragModifier = 0; // Modifier key at dragging
202 mnExtraStyle = 0; // Style of Extra field
203 mnCharWidth = 371;
204 mnLineHeight = 551;
205 mbCalc = true; // Should recalculate page width
206 mbFormat = true; // Should redraw
207 mbDrag = false; // Currently at dragging
208 mbDragDelete = false; // Has mouse left the dragging area
209 mbDragCanceled = false; // Dragging cancelled?
210 mbAutoWinWidth = true; // EditWinWidth == RulerWidth
211 mbActive = true; // Is ruler active
212 mnUpdateFlags = 0; // What needs to be updated
213 mpData = mpSaveData.get(); // Pointer to normal data
214 meExtraType = RulerExtra::DontKnow; // What is in extra field
215 meDragType = RulerType::DontKnow; // Which element is dragged
217 // Initialize Units
218 mnUnitIndex = RULER_UNIT_CM;
219 meUnit = FieldUnit::CM;
220 maZoom = Fraction( 1, 1 );
222 // Recalculate border widths
223 if ( nWinBits & WB_BORDER )
224 mnBorderWidth = 1;
225 else
226 mnBorderWidth = 0;
228 // Settings
229 ImplInitSettings( true, true, true );
231 // Setup the default size
232 tools::Rectangle aRect;
233 GetOutDev()->GetTextBoundRect( aRect, "0123456789" );
234 tools::Long nDefHeight = aRect.GetHeight() + RULER_OFF * 2 + ruler_tab.textoff * 2 + mnBorderWidth;
236 Size aDefSize;
237 if ( nWinBits & WB_HORZ )
238 aDefSize.setHeight( nDefHeight );
239 else
240 aDefSize.setWidth( nDefHeight );
241 SetOutputSizePixel( aDefSize );
242 SetType(WindowType::RULER);
245 Ruler::Ruler( vcl::Window* pParent, WinBits nWinStyle ) :
246 Window( pParent, nWinStyle & WB_3DLOOK ),
247 maVirDev( VclPtr<VirtualDevice>::Create(*GetOutDev()) ),
248 maMapMode( MapUnit::Map100thMM ),
249 mpSaveData(new ImplRulerData),
250 mpData(nullptr),
251 mpDragData(new ImplRulerData)
253 // Check to see if the ruler constructor has
254 // already been called before otherwise
255 // we end up with over-scaled elements
256 if (ruler_tab.DPIScaleFactor == 0)
258 ruler_tab.DPIScaleFactor = GetDPIScaleFactor();
259 ruler_tab.width *= ruler_tab.DPIScaleFactor;
260 ruler_tab.height *= ruler_tab.DPIScaleFactor;
261 ruler_tab.height2 *= ruler_tab.DPIScaleFactor;
262 ruler_tab.width2 *= ruler_tab.DPIScaleFactor;
263 ruler_tab.cwidth *= ruler_tab.DPIScaleFactor;
264 ruler_tab.cwidth2 *= ruler_tab.DPIScaleFactor;
265 ruler_tab.cwidth3 *= ruler_tab.DPIScaleFactor;
266 ruler_tab.cwidth4 *= ruler_tab.DPIScaleFactor;
267 ruler_tab.dheight *= ruler_tab.DPIScaleFactor;
268 ruler_tab.dheight2 *= ruler_tab.DPIScaleFactor;
269 ruler_tab.dwidth *= ruler_tab.DPIScaleFactor;
270 ruler_tab.dwidth2 *= ruler_tab.DPIScaleFactor;
271 ruler_tab.dwidth3 *= ruler_tab.DPIScaleFactor;
272 ruler_tab.dwidth4 *= ruler_tab.DPIScaleFactor;
273 ruler_tab.textoff *= ruler_tab.DPIScaleFactor;
277 ImplInit( nWinStyle );
280 Ruler::~Ruler()
282 disposeOnce();
285 void Ruler::dispose()
287 mpSaveData.reset();
288 mpDragData.reset();
289 mxAccContext.clear();
290 Window::dispose();
293 void Ruler::ImplVDrawLine(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
295 if ( nX1 < -RULER_CLIP )
297 nX1 = -RULER_CLIP;
298 if ( nX2 < -RULER_CLIP )
299 return;
301 tools::Long nClip = mnVirWidth + RULER_CLIP;
302 if ( nX2 > nClip )
304 nX2 = nClip;
305 if ( nX1 > nClip )
306 return;
309 if ( mnWinStyle & WB_HORZ )
310 rRenderContext.DrawLine( Point( nX1, nY1 ), Point( nX2, nY2 ) );
311 else
312 rRenderContext.DrawLine( Point( nY1, nX1 ), Point( nY2, nX2 ) );
315 void Ruler::ImplVDrawRect(vcl::RenderContext& rRenderContext, tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
317 if ( nX1 < -RULER_CLIP )
319 nX1 = -RULER_CLIP;
320 if ( nX2 < -RULER_CLIP )
321 return;
323 tools::Long nClip = mnVirWidth + RULER_CLIP;
324 if ( nX2 > nClip )
326 nX2 = nClip;
327 if ( nX1 > nClip )
328 return;
331 if ( mnWinStyle & WB_HORZ )
332 rRenderContext.DrawRect(tools::Rectangle(nX1, nY1, nX2, nY2));
333 else
334 rRenderContext.DrawRect(tools::Rectangle(nY1, nX1, nY2, nX2));
337 void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, tools::Long nY, const OUString& rText, tools::Long nMin, tools::Long nMax)
339 tools::Rectangle aRect;
340 SalLayoutGlyphs* pTextLayout
341 = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]);
342 rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, {}, {}, pTextLayout);
344 tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left();
345 tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top();
347 if ( (nX > -RULER_CLIP) && (nX < mnVirWidth + RULER_CLIP) && ( nX < nMax - nShiftX ) && ( nX > nMin + nShiftX ) )
349 if ( mnWinStyle & WB_HORZ )
350 rRenderContext.DrawText(Point(nX - nShiftX, nY - nShiftY), rText, 0, -1, nullptr,
351 nullptr, pTextLayout);
352 else
353 rRenderContext.DrawText(Point(nY - nShiftX, nX - nShiftY), rText, 0, -1, nullptr,
354 nullptr, pTextLayout);
358 void Ruler::ImplInvertLines(vcl::RenderContext& rRenderContext)
360 // Position lines
361 if (mpData->pLines.empty() || !mbActive || mbDrag || mbFormat || (mnUpdateFlags & RULER_UPDATE_LINES) )
362 return;
364 tools::Long nNullWinOff = mpData->nNullVirOff + mnVirOff;
365 tools::Long nRulX1 = mpData->nRulVirOff + mnVirOff;
366 tools::Long nRulX2 = nRulX1 + mpData->nRulWidth;
367 tools::Long nY = (RULER_OFF * 2) + mnVirHeight - 1;
369 // Calculate rectangle
370 tools::Rectangle aRect;
371 if (mnWinStyle & WB_HORZ)
372 aRect.SetBottom( nY );
373 else
374 aRect.SetRight( nY );
376 // Draw lines
377 for (const RulerLine & rLine : mpData->pLines)
379 const tools::Long n = rLine.nPos + nNullWinOff;
380 if ((n >= nRulX1) && (n < nRulX2))
382 if (mnWinStyle & WB_HORZ )
384 aRect.SetLeft( n );
385 aRect.SetRight( n );
387 else
389 aRect.SetTop( n );
390 aRect.SetBottom( n );
392 tools::Rectangle aTempRect = aRect;
394 if (mnWinStyle & WB_HORZ)
395 aTempRect.SetBottom( RULER_OFF - 1 );
396 else
397 aTempRect.SetRight( RULER_OFF - 1 );
399 rRenderContext.Erase(aTempRect);
401 if (mnWinStyle & WB_HORZ)
403 aTempRect.SetBottom( aRect.Bottom() );
404 aTempRect.SetTop( aTempRect.Bottom() - RULER_OFF + 1 );
406 else
408 aTempRect.SetRight( aRect.Right() );
409 aTempRect.SetLeft( aTempRect.Right() - RULER_OFF + 1 );
411 rRenderContext.Erase(aTempRect);
412 GetOutDev()->Invert(aRect);
415 mnUpdateFlags = 0;
418 void Ruler::ImplDrawTicks(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nStart, tools::Long nTop, tools::Long nBottom)
420 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
421 double nCenter = nTop + ((nBottom - nTop) / 2);
423 tools::Long nTickLength3 = (nBottom - nTop) * 0.5;
424 tools::Long nTickLength2 = nTickLength3 * 0.66;
425 tools::Long nTickLength1 = nTickLength2 * 0.66;
427 tools::Long nScale = ruler_tab.DPIScaleFactor;
428 tools::Long DPIOffset = nScale - 1;
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;
437 Size aPixSize = rRenderContext.LogicToPixel(Size(nTick4, nTick4), maMapMode);
439 if (mnUnitIndex == RULER_UNIT_CHAR)
441 if (mnCharWidth == 0)
442 mnCharWidth = 371;
443 nTick4 = mnCharWidth * 2;
444 nTick2 = mnCharWidth;
445 nTickCount = mnCharWidth;
446 nTickUnit = mnCharWidth;
448 else if (mnUnitIndex == RULER_UNIT_LINE)
450 if (mnLineHeight == 0)
451 mnLineHeight = 551;
452 nTick4 = mnLineHeight * 2;
453 nTick2 = mnLineHeight;
454 nTickUnit = mnLineHeight;
455 nTickCount = mnLineHeight;
458 if (mnWinStyle & WB_HORZ)
460 nTickWidth = aPixSize.Width();
462 else
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();
473 tools::Long nMaxWidth = rRenderContext.PixelToLogic(Size(mpData->nPageWidth, 0), maMapMode).Width();
474 if (nMaxWidth < 0)
475 nMaxWidth = -nMaxWidth;
477 if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
478 nMaxWidth /= nTickUnit;
479 else
480 nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit;
482 OUString aNumString = OUString::number(nMaxWidth);
483 tools::Long nTxtWidth = rRenderContext.GetTextWidth( aNumString );
484 const tools::Long nTextOff = 4;
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)
491 // Calculate the scale of the ruler
492 tools::Long nMulti = 1;
493 tools::Long nOrgTick4 = nTick4;
495 while (nTickWidth < nTxtWidth + nTextOff)
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;
509 // Overflow - in this case don't draw ticks and exit
510 if (nMulti < nOldMulti)
512 bNoTicks = true;
513 break;
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();
523 nTickCount = nTick4;
525 else
527 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
530 if (bNoTicks)
531 return;
533 tools::Long n = 0;
534 double nTick = 0.0;
535 double nTick3 = 0;
537 if ((mnUnitIndex != RULER_UNIT_CHAR) && (mnUnitIndex != RULER_UNIT_LINE))
539 nTick2 = aImplRulerUnitTab[mnUnitIndex].nTick2;
540 nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3;
543 Size nTickGapSize;
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();
552 while (((nStart - n) >= nMin) || ((nStart + n) <= nMax))
554 // Null point
555 if (nTick == 0.0)
557 if (nStart > nMin)
559 // 0 is only painted when Margin1 is not equal to zero
560 if ((mpData->nMargin1Style & RulerMarginStyle::Invisible) || (mpData->nMargin1 != 0))
562 aNumString = "0";
563 ImplVDrawText(rRenderContext, nStart, nCenter, aNumString);
567 else
569 aPixSize = rRenderContext.LogicToPixel(Size(nTick, nTick), maMapMode);
571 if (mnWinStyle & WB_HORZ)
572 n = aPixSize.Width();
573 else
574 n = aPixSize.Height();
576 // Tick4 - Output (Text)
577 double aStep = nTick / nTick4;
578 double aRest = std::abs(aStep - std::floor(aStep));
579 double nAcceptanceDelta = 0.0001;
580 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
582 if (aRest < nAcceptanceDelta)
584 if ((mnUnitIndex == RULER_UNIT_CHAR) || (mnUnitIndex == RULER_UNIT_LINE))
585 aNumString = OUString::number(nTick / nTickUnit);
586 else
587 aNumString = OUString::number(nTick / aImplRulerUnitTab[mnUnitIndex].nTickUnit);
589 tools::Long nHorizontalLocation = nStart + n;
590 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
592 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
594 ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom - 1 * nScale, nHorizontalLocation + DPIOffset, nBottom);
595 ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop, nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
598 nHorizontalLocation = nStart - n;
599 ImplVDrawText(rRenderContext, nHorizontalLocation, nCenter, aNumString, nMin, nMax);
601 if (nMin < nHorizontalLocation && nHorizontalLocation < nMax)
603 ImplVDrawRect(rRenderContext, nHorizontalLocation, nBottom,
604 nHorizontalLocation + DPIOffset, nBottom - 1 * nScale);
605 ImplVDrawRect(rRenderContext, nHorizontalLocation, nTop,
606 nHorizontalLocation + DPIOffset, nTop + 1 * nScale);
609 // Tick/Tick2 - Output (Strokes)
610 else
612 tools::Long nTickLength = nTickLength1;
614 aStep = (nTick / nTick2);
615 aRest = std::abs(aStep - std::floor(aStep));
616 if (aRest < nAcceptanceDelta)
617 nTickLength = nTickLength2;
619 aStep = (nTick / nTick3);
620 aRest = std::abs(aStep - std::floor(aStep));
621 if (aRest < nAcceptanceDelta )
622 nTickLength = nTickLength3;
624 if ((nTickLength == nTickLength1 && nTickGap1 > 6) ||
625 (nTickLength == nTickLength2 && nTickGap2 > 6) ||
626 (nTickLength == nTickLength3 && nTickGap3 > 6))
628 tools::Long nT1 = nCenter - (nTickLength / 2.0);
629 tools::Long nT2 = nT1 + nTickLength - 1;
630 tools::Long nT;
632 nT = nStart + n;
634 if (nT < nMax)
635 ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2);
636 nT = nStart - n;
637 if (nT > nMin)
638 ImplVDrawRect(rRenderContext, nT, nT1, nT + DPIOffset, nT2);
642 nTick += nTickCount;
646 void Ruler::ImplDrawBorders(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
648 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
649 tools::Long n;
650 tools::Long n1;
651 tools::Long n2;
652 tools::Long nTemp1;
653 tools::Long nTemp2;
655 for (std::vector<RulerBorder>::size_type i = 0; i < mpData->pBorders.size(); i++)
657 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Invisible)
658 continue;
660 n1 = mpData->pBorders[i].nPos + mpData->nNullVirOff;
661 n2 = n1 + mpData->pBorders[i].nWidth;
663 if (((n1 >= nMin) && (n1 <= nMax)) || ((n2 >= nMin) && (n2 <= nMax)))
665 if ((n2 - n1) > 3)
667 rRenderContext.SetLineColor();
668 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
669 ImplVDrawRect(rRenderContext, n1, nVirTop, n2, nVirBottom);
671 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
672 ImplVDrawLine(rRenderContext, n1 + 1, nVirTop, n1 + 1, nVirBottom);
673 ImplVDrawLine(rRenderContext, n1, nVirTop, n2, nVirTop);
675 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
676 ImplVDrawLine(rRenderContext, n1, nVirTop, n1, nVirBottom);
677 ImplVDrawLine(rRenderContext, n1, nVirBottom, n2, nVirBottom);
678 ImplVDrawLine(rRenderContext, n2 - 1, nVirTop, n2 - 1, nVirBottom);
680 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
681 ImplVDrawLine(rRenderContext, n2, nVirTop, n2, nVirBottom);
683 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Variable)
685 if (n2 - n1 > RULER_VAR_SIZE + 4)
687 nTemp1 = n1 + (((n2 - n1 + 1) - RULER_VAR_SIZE) / 2);
688 nTemp2 = nVirTop + (((nVirBottom - nVirTop + 1) - RULER_VAR_SIZE) / 2);
689 tools::Long nTemp3 = nTemp1 + RULER_VAR_SIZE - 1;
690 tools::Long nTemp4 = nTemp2 + RULER_VAR_SIZE - 1;
691 tools::Long nTempY = nTemp2;
693 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
694 while (nTempY <= nTemp4)
696 ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
697 nTempY += 2;
700 nTempY = nTemp2 + 1;
701 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
702 while (nTempY <= nTemp4)
704 ImplVDrawLine(rRenderContext, nTemp1, nTempY, nTemp3, nTempY);
705 nTempY += 2;
710 if (mpData->pBorders[i].nStyle & RulerBorderStyle::Sizeable)
712 if (n2 - n1 > RULER_VAR_SIZE + 10)
714 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
715 ImplVDrawLine(rRenderContext, n1 + 4, nVirTop + 3, n1 + 4, nVirBottom - 3);
716 ImplVDrawLine(rRenderContext, n2 - 5, nVirTop + 3, n2 - 5, nVirBottom - 3);
717 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
718 ImplVDrawLine(rRenderContext, n1 + 5, nVirTop + 3, n1 + 5, nVirBottom - 3);
719 ImplVDrawLine(rRenderContext, n2 - 4, nVirTop + 3, n2 - 4, nVirBottom - 3);
723 else
725 n = n1 + ((n2 - n1) / 2);
726 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
728 ImplVDrawLine(rRenderContext, n - 1, nVirTop, n - 1, nVirBottom);
729 ImplVDrawLine(rRenderContext, n + 1, nVirTop, n + 1, nVirBottom);
730 rRenderContext.SetLineColor();
731 rRenderContext.SetFillColor(rStyleSettings.GetWindowColor());
732 ImplVDrawRect(rRenderContext, n, nVirTop, n, nVirBottom);
738 void Ruler::ImplDrawIndent(vcl::RenderContext& rRenderContext, const tools::Polygon& rPoly, bool bIsHit)
740 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
742 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
743 rRenderContext.SetFillColor(bIsHit ? rStyleSettings.GetDarkShadowColor() : rStyleSettings.GetWorkspaceColor());
744 tools::Polygon aPolygon(rPoly);
745 aPolygon.Optimize(PolyOptimizeFlags::CLOSE);
746 rRenderContext.DrawPolygon(aPolygon);
749 void Ruler::ImplDrawIndents(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
751 tools::Long n;
752 tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
753 tools::Long nIndentWidth2 = nIndentHeight-3;
755 tools::Polygon aPoly(5);
757 for (std::vector<RulerIndent>::size_type j = 0; j < mpData->pIndents.size(); j++)
759 if (mpData->pIndents[j].bInvisible)
760 continue;
762 RulerIndentStyle nIndentStyle = mpData->pIndents[j].nStyle;
764 n = mpData->pIndents[j].nPos+mpData->nNullVirOff;
766 if ((n >= nMin) && (n <= nMax))
768 if (nIndentStyle == RulerIndentStyle::Bottom)
770 aPoly.SetPoint(Point(n + 0, nVirBottom - nIndentHeight), 0);
771 aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom - 3), 1);
772 aPoly.SetPoint(Point(n - nIndentWidth2, nVirBottom), 2);
773 aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom), 3);
774 aPoly.SetPoint(Point(n + nIndentWidth2, nVirBottom - 3), 4);
776 else
778 aPoly.SetPoint(Point(n + 0, nVirTop + nIndentHeight), 0);
779 aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop + 3), 1);
780 aPoly.SetPoint(Point(n - nIndentWidth2, nVirTop), 2);
781 aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop), 3);
782 aPoly.SetPoint(Point(n + nIndentWidth2, nVirTop + 3), 4);
785 if (0 == (mnWinStyle & WB_HORZ))
787 Point aTmp;
788 for (sal_uInt16 i = 0; i < 5; i++)
790 aTmp = aPoly[i];
791 Point aSet(nVirBottom - aTmp.Y(), aTmp.X());
792 aPoly[i] = aSet;
795 bool bIsHit = false;
796 if (mxCurrentHitTest != nullptr && mxCurrentHitTest->eType == RulerType::Indent)
798 bIsHit = mxCurrentHitTest->nAryPos == j;
800 else if(mbDrag && meDragType == RulerType::Indent)
802 bIsHit = mnDragAryPos == j;
804 ImplDrawIndent(rRenderContext, aPoly, bIsHit);
809 static void ImplCenterTabPos(Point& rPos, sal_uInt16 nTabStyle)
811 bool bRTL = 0 != (nTabStyle & RULER_TAB_RTL);
812 nTabStyle &= RULER_TAB_STYLE;
813 rPos.AdjustY(ruler_tab.height/2 );
815 if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) ||
816 ( bRTL && nTabStyle == RULER_TAB_RIGHT) )
818 rPos.AdjustX( -(ruler_tab.width / 2) );
820 else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) ||
821 ( bRTL && nTabStyle == RULER_TAB_LEFT) )
823 rPos.AdjustX(ruler_tab.width / 2 );
827 static void lcl_RotateRect_Impl(tools::Rectangle& rRect, const tools::Long nReference, bool bRightAligned)
829 if (rRect.IsEmpty())
830 return;
832 tools::Rectangle aTmp(rRect);
833 rRect.SetTop( aTmp.Left() );
834 rRect.SetBottom( aTmp.Right() );
835 rRect.SetLeft( aTmp.Top() );
836 rRect.SetRight( aTmp.Bottom() );
838 if (bRightAligned)
840 tools::Long nRef = 2 * nReference;
841 rRect.SetLeft( nRef - rRect.Left() );
842 rRect.SetRight( nRef - rRect.Right() );
846 static void ImplDrawRulerTab(vcl::RenderContext& rRenderContext, const Point& rPos,
847 sal_uInt16 nStyle, WinBits nWinBits)
849 if (nStyle & RULER_STYLE_INVISIBLE)
850 return;
852 sal_uInt16 nTabStyle = nStyle & RULER_TAB_STYLE;
853 bool bRTL = 0 != (nStyle & RULER_TAB_RTL);
855 // Scale by the screen DPI scaling factor
856 // However when doing this some of the rectangles
857 // drawn become asymmetric due to the +1 offsets
858 sal_uInt16 DPIOffset = rRenderContext.GetDPIScaleFactor() - 1;
860 // A tabstop is drawn using three rectangles
861 tools::Rectangle aRect1; // A horizontal short line
862 tools::Rectangle aRect2; // A vertical short line
863 tools::Rectangle aRect3; // A small square
865 aRect3.SetEmpty();
867 if (nTabStyle == RULER_TAB_DEFAULT)
869 aRect1.SetLeft( rPos.X() - ruler_tab.dwidth2 + 1 );
870 aRect1.SetTop( rPos.Y() - ruler_tab.dheight2 + 1 );
871 aRect1.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth + DPIOffset );
872 aRect1.SetBottom( rPos.Y() );
874 aRect2.SetLeft( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 );
875 aRect2.SetTop( rPos.Y() - ruler_tab.dheight + 1 );
876 aRect2.SetRight( rPos.X() - ruler_tab.dwidth2 + ruler_tab.dwidth3 + ruler_tab.dwidth4 - 1 );
877 aRect2.SetBottom( rPos.Y() );
880 else if ((!bRTL && nTabStyle == RULER_TAB_LEFT) || (bRTL && nTabStyle == RULER_TAB_RIGHT))
882 aRect1.SetLeft( rPos.X() );
883 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
884 aRect1.SetRight( rPos.X() + ruler_tab.width - 1 );
885 aRect1.SetBottom( rPos.Y() );
887 aRect2.SetLeft( rPos.X() );
888 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
889 aRect2.SetRight( rPos.X() + ruler_tab.width2 - 1 );
890 aRect2.SetBottom( rPos.Y() );
892 else if ((!bRTL && nTabStyle == RULER_TAB_RIGHT) || (bRTL && nTabStyle == RULER_TAB_LEFT))
894 aRect1.SetLeft( rPos.X() - ruler_tab.width + 1 );
895 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
896 aRect1.SetRight( rPos.X() );
897 aRect1.SetBottom( rPos.Y() );
899 aRect2.SetLeft( rPos.X() - ruler_tab.width2 + 1 );
900 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
901 aRect2.SetRight( rPos.X() );
902 aRect2.SetBottom( rPos.Y() );
904 else
906 aRect1.SetLeft( rPos.X() - ruler_tab.cwidth2 + 1 );
907 aRect1.SetTop( rPos.Y() - ruler_tab.height2 + 1 );
908 aRect1.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset );
909 aRect1.SetBottom( rPos.Y() );
911 aRect2.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 );
912 aRect2.SetTop( rPos.Y() - ruler_tab.height + 1 );
913 aRect2.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth3 + ruler_tab.cwidth4 - 1 );
914 aRect2.SetBottom( rPos.Y() );
916 if (nTabStyle == RULER_TAB_DECIMAL)
918 aRect3.SetLeft( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth - 1 );
919 aRect3.SetTop( rPos.Y() - ruler_tab.height + 1 + 1 - DPIOffset );
920 aRect3.SetRight( rPos.X() - ruler_tab.cwidth2 + ruler_tab.cwidth + DPIOffset );
921 aRect3.SetBottom( rPos.Y() - ruler_tab.height + 1 + 2 );
924 if (0 == (nWinBits & WB_HORZ))
926 bool bRightAligned = 0 != (nWinBits & WB_RIGHT_ALIGNED);
927 lcl_RotateRect_Impl(aRect1, rPos.Y(), bRightAligned);
928 lcl_RotateRect_Impl(aRect2, rPos.Y(), bRightAligned);
929 lcl_RotateRect_Impl(aRect3, rPos.Y(), bRightAligned);
931 rRenderContext.DrawRect(aRect1);
932 rRenderContext.DrawRect(aRect2);
934 if (!aRect3.IsEmpty())
935 rRenderContext.DrawRect(aRect3);
938 void Ruler::ImplDrawTab(vcl::RenderContext& rRenderContext, const Point& rPos, sal_uInt16 nStyle)
940 if (nStyle & RULER_STYLE_INVISIBLE)
941 return;
943 rRenderContext.SetLineColor();
945 if (nStyle & RULER_STYLE_DONTKNOW)
946 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceColor());
947 else
948 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor());
950 if (mpData->bTextRTL)
951 nStyle |= RULER_TAB_RTL;
953 ImplDrawRulerTab(rRenderContext, rPos, nStyle, GetStyle());
956 void Ruler::ImplDrawTabs(vcl::RenderContext& rRenderContext, tools::Long nMin, tools::Long nMax, tools::Long nVirTop, tools::Long nVirBottom)
958 for (const RulerTab & rTab : mpData->pTabs)
960 if (rTab.nStyle & RULER_STYLE_INVISIBLE)
961 continue;
963 tools::Long aPosition;
964 aPosition = rTab.nPos;
965 aPosition += +mpData->nNullVirOff;
966 tools::Long nTopBottom = (GetStyle() & WB_RIGHT_ALIGNED) ? nVirTop : nVirBottom;
967 if (nMin <= aPosition && aPosition <= nMax)
968 ImplDrawTab(rRenderContext, Point( aPosition, nTopBottom ), rTab.nStyle);
972 static int adjustSize(int nOrig)
974 if (nOrig <= 0)
975 return 0;
977 // make sure we return an odd number, that looks better in the ruler
978 return ( (3*nOrig) / 8) * 2 + 1;
981 void Ruler::ApplySettings(vcl::RenderContext& rRenderContext)
983 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
985 vcl::Font aFont = rStyleSettings.GetToolFont();
986 // make the font a bit smaller than default
987 Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
988 aFont.SetFontSize(aSize);
990 ApplyControlFont(rRenderContext, aFont);
992 ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
993 SetTextFillColor();
995 Color aColor;
996 svtools::ColorConfig aColorConfig;
997 aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
998 ApplyControlBackground(rRenderContext, aColor);
999 // A hack to get it to change the non-ruler application background to change immediately
1000 if (aColor != maVirDev->GetBackground().GetColor())
1002 maVirDev->SetBackground(aColor);
1003 Resize();
1007 void Ruler::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1009 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1011 if (bFont)
1013 vcl::Font aFont = rStyleSettings.GetToolFont();
1014 // make the font a bit smaller than default
1015 Size aSize(adjustSize(aFont.GetFontSize().Width()), adjustSize(aFont.GetFontSize().Height()));
1016 aFont.SetFontSize(aSize);
1018 ApplyControlFont(*GetOutDev(), aFont);
1021 if (bForeground || bFont)
1023 ApplyControlForeground(*GetOutDev(), rStyleSettings.GetDarkShadowColor());
1024 SetTextFillColor();
1027 if (bBackground)
1029 Color aColor;
1030 svtools::ColorConfig aColorConfig;
1031 aColor = aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor;
1032 ApplyControlBackground(*GetOutDev(), aColor);
1035 maVirDev->SetSettings( GetSettings() );
1036 maVirDev->SetBackground( GetBackground() );
1037 vcl::Font aFont = GetFont();
1039 if (mnWinStyle & WB_VERT)
1040 aFont.SetOrientation(900_deg10);
1042 maVirDev->SetFont(aFont);
1043 maVirDev->SetTextColor(GetTextColor());
1044 maVirDev->SetTextFillColor(GetTextFillColor());
1047 void Ruler::ImplCalc()
1049 // calculate offset
1050 mpData->nRulVirOff = mnWinOff + mpData->nPageOff;
1051 if ( mpData->nRulVirOff > mnVirOff )
1052 mpData->nRulVirOff -= mnVirOff;
1053 else
1054 mpData->nRulVirOff = 0;
1055 tools::Long nRulWinOff = mpData->nRulVirOff+mnVirOff;
1057 // calculate non-visual part of the page
1058 tools::Long nNotVisPageWidth;
1059 if ( mpData->nPageOff < 0 )
1061 nNotVisPageWidth = -(mpData->nPageOff);
1062 if ( nRulWinOff < mnWinOff )
1063 nNotVisPageWidth -= mnWinOff-nRulWinOff;
1065 else
1066 nNotVisPageWidth = 0;
1068 // calculate width
1069 if ( mnWinStyle & WB_HORZ )
1071 if ( mbAutoWinWidth )
1072 mnWinWidth = mnWidth - mnVirOff;
1073 if ( mpData->bAutoPageWidth )
1074 mpData->nPageWidth = mnWinWidth;
1075 mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1076 if ( nRulWinOff+mpData->nRulWidth > mnWidth )
1077 mpData->nRulWidth = mnWidth-nRulWinOff;
1079 else
1081 if ( mbAutoWinWidth )
1082 mnWinWidth = mnHeight - mnVirOff;
1083 if ( mpData->bAutoPageWidth )
1084 mpData->nPageWidth = mnWinWidth;
1085 mpData->nRulWidth = std::min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth );
1086 if ( nRulWinOff+mpData->nRulWidth > mnHeight )
1087 mpData->nRulWidth = mnHeight-nRulWinOff;
1090 mbCalc = false;
1093 void Ruler::ImplFormat(vcl::RenderContext const & rRenderContext)
1095 // if already formatted, don't do it again
1096 if (!mbFormat)
1097 return;
1099 // don't do anything if the window still has no size
1100 if (!mnVirWidth)
1101 return;
1103 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1104 tools::Long nP1; // pixel position of Page1
1105 tools::Long nP2; // pixel position of Page2
1106 tools::Long nM1; // pixel position of Margin1
1107 tools::Long nM2; // pixel position of Margin2
1108 tools::Long nVirTop; // top/left corner
1109 tools::Long nVirBottom; // bottom/right corner
1110 tools::Long nVirLeft; // left/top corner
1111 tools::Long nVirRight; // right/bottom corner
1112 tools::Long nNullVirOff; // for faster calculation
1114 // calculate values
1115 if (mbCalc)
1116 ImplCalc();
1118 mpData->nNullVirOff = mnWinOff + mpData->nPageOff + mpData->nNullOff - mnVirOff;
1120 nNullVirOff = mpData->nNullVirOff;
1121 nVirLeft = mpData->nRulVirOff;
1122 nVirRight = nVirLeft + mpData->nRulWidth - 1;
1123 nVirTop = 0;
1124 nVirBottom = mnVirHeight - 1;
1126 if (!IsReallyVisible())
1127 return;
1129 Size aVirDevSize;
1131 // initialize VirtualDevice
1132 if (mnWinStyle & WB_HORZ)
1134 aVirDevSize.setWidth( mnVirWidth );
1135 aVirDevSize.setHeight( mnVirHeight );
1137 else
1139 aVirDevSize.setHeight( mnVirWidth );
1140 aVirDevSize.setWidth( mnVirHeight );
1142 if (aVirDevSize != maVirDev->GetOutputSizePixel())
1143 maVirDev->SetOutputSizePixel(aVirDevSize);
1144 else
1145 maVirDev->Erase();
1147 // calculate margins
1148 if (!(mpData->nMargin1Style & RulerMarginStyle::Invisible))
1150 nM1 = mpData->nMargin1 + nNullVirOff;
1151 if (mpData->bAutoPageWidth)
1153 nP1 = nVirLeft;
1154 if (nM1 < nVirLeft)
1155 nP1--;
1157 else
1158 nP1 = nNullVirOff - mpData->nNullOff;
1160 else
1162 nM1 = nVirLeft-1;
1163 nP1 = nM1;
1165 if (!(mpData->nMargin2Style & RulerMarginStyle::Invisible))
1167 nM2 = mpData->nMargin2 + nNullVirOff;
1168 if (mpData->bAutoPageWidth)
1170 nP2 = nVirRight;
1171 if (nM2 > nVirRight)
1172 nP2++;
1174 else
1175 nP2 = nNullVirOff - mpData->nNullOff + mpData->nPageWidth;
1176 if (nM2 > nP2)
1177 nM2 = nP2;
1179 else
1181 nM2 = nVirRight+1;
1182 nP2 = nM2;
1185 // top/bottom border
1186 maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1187 ImplVDrawLine(*maVirDev, nVirLeft, nVirTop + 1, nM1, nVirTop + 1); //top left line
1188 ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nP2 - 1, nVirTop + 1); //top right line
1190 nVirTop++;
1191 nVirBottom--;
1193 // draw margin1, margin2 and in-between
1194 maVirDev->SetLineColor();
1195 maVirDev->SetFillColor(rStyleSettings.GetDialogColor());
1196 if (nM1 > nVirLeft)
1197 ImplVDrawRect(*maVirDev, nP1, nVirTop + 1, nM1, nVirBottom); //left gray rectangle
1198 if (nM2 < nP2)
1199 ImplVDrawRect(*maVirDev, nM2, nVirTop + 1, nP2, nVirBottom); //right gray rectangle
1200 if (nM2 - nM1 > 0)
1202 maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1203 ImplVDrawRect(*maVirDev, nM1 + 1, nVirTop, nM2 - 1, nVirBottom); //center rectangle
1205 maVirDev->SetLineColor(rStyleSettings.GetShadowColor());
1206 if (nM1 > nVirLeft)
1208 ImplVDrawLine(*maVirDev, nM1, nVirTop + 1, nM1, nVirBottom); //right line of the left rectangle
1209 ImplVDrawLine(*maVirDev, nP1, nVirBottom, nM1, nVirBottom); //bottom line of the left rectangle
1210 if (nP1 >= nVirLeft)
1212 ImplVDrawLine(*maVirDev, nP1, nVirTop + 1, nP1, nVirBottom); //left line of the left rectangle
1213 ImplVDrawLine(*maVirDev, nP1, nVirBottom, nP1 + 1, nVirBottom); //?
1216 if (nM2 < nP2)
1218 ImplVDrawLine(*maVirDev, nM2, nVirBottom, nP2 - 1, nVirBottom); //bottom line of the right rectangle
1219 ImplVDrawLine(*maVirDev, nM2, nVirTop + 1, nM2, nVirBottom); //left line of the right rectangle
1220 if (nP2 <= nVirRight + 1)
1221 ImplVDrawLine(*maVirDev, nP2 - 1, nVirTop + 1, nP2 - 1, nVirBottom); //right line of the right rectangle
1224 tools::Long nMin = nVirLeft;
1225 tools::Long nMax = nP2;
1226 tools::Long nStart = 0;
1228 if (mpData->bTextRTL)
1229 nStart = mpData->nRightFrameMargin + nNullVirOff;
1230 else
1231 nStart = mpData->nLeftFrameMargin + nNullVirOff;
1233 if (nP1 > nVirLeft)
1234 nMin++;
1236 if (nP2 < nVirRight)
1237 nMax--;
1239 // Draw captions
1240 ImplDrawTicks(*maVirDev, nMin, nMax, nStart, nVirTop, nVirBottom);
1242 // Draw borders
1243 if (!mpData->pBorders.empty())
1244 ImplDrawBorders(*maVirDev, nVirLeft, nP2, nVirTop, nVirBottom);
1246 // Draw indents
1247 if (!mpData->pIndents.empty())
1248 ImplDrawIndents(*maVirDev, nVirLeft, nP2, nVirTop - 1, nVirBottom + 1);
1250 // Tabs
1251 if (!mpData->pTabs.empty())
1252 ImplDrawTabs(*maVirDev, nVirLeft, nP2, nVirTop-1, nVirBottom + 1);
1254 mbFormat = false;
1257 void Ruler::ImplInitExtraField( bool bUpdate )
1259 Size aWinSize = GetOutputSizePixel();
1261 // extra field evaluate
1262 if ( mnWinStyle & WB_EXTRAFIELD )
1264 maExtraRect.SetLeft( RULER_OFF );
1265 maExtraRect.SetTop( RULER_OFF );
1266 maExtraRect.SetRight( RULER_OFF + mnVirHeight - 1 );
1267 maExtraRect.SetBottom( RULER_OFF + mnVirHeight - 1 );
1268 if(mpData->bTextRTL)
1270 if(mnWinStyle & WB_HORZ)
1271 maExtraRect.Move(aWinSize.Width() - maExtraRect.GetWidth() - maExtraRect.Left(), 0);
1272 else
1273 maExtraRect.Move(0, aWinSize.Height() - maExtraRect.GetHeight() - maExtraRect.Top());
1274 mnVirOff = 0;
1276 else
1277 mnVirOff = maExtraRect.Right()+1;
1280 else
1282 maExtraRect.SetEmpty();
1283 mnVirOff = 0;
1286 // mnVirWidth depends on mnVirOff
1287 if ( (mnVirWidth > RULER_MIN_SIZE) ||
1288 ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) )
1290 if ( mnWinStyle & WB_HORZ )
1291 mnVirWidth = aWinSize.Width()-mnVirOff;
1292 else
1293 mnVirWidth = aWinSize.Height()-mnVirOff;
1295 if ( mnVirWidth < RULER_MIN_SIZE )
1296 mnVirWidth = 0;
1299 if ( bUpdate )
1301 mbCalc = true;
1302 mbFormat = true;
1303 Invalidate();
1307 void Ruler::ImplDraw(vcl::RenderContext& rRenderContext)
1309 if (mbFormat)
1311 ImplFormat(rRenderContext);
1314 if (!IsReallyVisible())
1315 return;
1317 // output the ruler to the virtual device
1318 Point aOffPos;
1319 Size aVirDevSize = maVirDev->GetOutputSizePixel();
1321 if (mnWinStyle & WB_HORZ)
1323 aOffPos.setX( mnVirOff );
1324 if (mpData->bTextRTL)
1325 aVirDevSize.AdjustWidth( -(maExtraRect.GetWidth()) );
1327 aOffPos.setY( RULER_OFF );
1329 else
1331 aOffPos.setX( RULER_OFF );
1332 aOffPos.setY( mnVirOff );
1334 rRenderContext.DrawOutDev(aOffPos, aVirDevSize, Point(), aVirDevSize, *maVirDev);
1336 // redraw positionlines
1337 ImplInvertLines(rRenderContext);
1340 void Ruler::ImplDrawExtra(vcl::RenderContext& rRenderContext)
1342 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1343 tools::Rectangle aRect = maExtraRect;
1344 bool bEraseRect = false;
1346 aRect.AdjustLeft(2 );
1347 aRect.AdjustTop(2 );
1348 aRect.AdjustRight( -2 );
1349 aRect.AdjustBottom( -2 );
1351 if (mnExtraStyle & RULER_STYLE_HIGHLIGHT)
1353 rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
1354 bEraseRect = true;
1357 if (bEraseRect)
1359 rRenderContext.SetLineColor();
1360 rRenderContext.DrawRect(aRect);
1363 // output content
1364 if (meExtraType == RulerExtra::NullOffset)
1366 rRenderContext.SetLineColor(rStyleSettings.GetButtonTextColor());
1367 rRenderContext.DrawLine(Point(aRect.Left() + 1, aRect.Top() + 4),
1368 Point(aRect.Right() - 1, aRect.Top() + 4));
1369 rRenderContext.DrawLine(Point(aRect.Left() + 4, aRect.Top() + 1),
1370 Point(aRect.Left() + 4, aRect.Bottom() - 1));
1372 else if (meExtraType == RulerExtra::Tab)
1374 sal_uInt16 nTabStyle = mnExtraStyle & RULER_TAB_STYLE;
1375 if (mpData->bTextRTL)
1376 nTabStyle |= RULER_TAB_RTL;
1377 Point aCenter = aRect.Center();
1378 Point aDraw(aCenter);
1379 ImplCenterTabPos(aDraw, nTabStyle);
1380 WinBits nWinBits = GetStyle();
1381 if (0 == (nWinBits & WB_HORZ))
1383 if ((nWinBits & WB_RIGHT_ALIGNED) != 0)
1384 aDraw.setY( 2 * aCenter.Y() - aDraw.Y() );
1386 if (mpData->bTextRTL)
1388 tools::Long nTemp = aDraw.X();
1389 aDraw.setX( aDraw.Y() );
1390 aDraw.setY( nTemp );
1393 ImplDrawTab(rRenderContext, aDraw, nTabStyle);
1397 void Ruler::ImplUpdate( bool bMustCalc )
1399 // clear lines in this place so they aren't considered at recalculation
1400 if (!mbFormat)
1401 Invalidate(InvalidateFlags::NoErase);
1403 // set flags
1404 if (bMustCalc)
1405 mbCalc = true;
1406 mbFormat = true;
1408 // abort if we are dragging as drag-handler will update the ruler after drag is finished
1409 if (mbDrag)
1410 return;
1412 // otherwise trigger update
1413 if (IsReallyVisible() && IsUpdateMode())
1415 Invalidate(InvalidateFlags::NoErase);
1419 bool Ruler::ImplDoHitTest( const Point& rPos, RulerSelection* pHitTest,
1420 bool bRequireStyle, RulerIndentStyle nRequiredStyle ) const
1422 sal_Int32 i;
1423 sal_uInt16 nStyle;
1424 tools::Long nHitBottom;
1425 tools::Long nX;
1426 tools::Long nY;
1427 tools::Long n1;
1429 if ( !mbActive )
1430 return false;
1432 // determine positions
1433 bool bIsHori = 0 != (mnWinStyle & WB_HORZ);
1434 if ( bIsHori )
1436 nX = rPos.X();
1437 nY = rPos.Y();
1439 else
1441 nX = rPos.Y();
1442 nY = rPos.X();
1444 nHitBottom = mnVirHeight + (RULER_OFF * 2);
1446 // #i32608#
1447 pHitTest->nAryPos = 0;
1448 pHitTest->mnDragSize = RulerDragSize::Move;
1449 pHitTest->bSize = false;
1450 pHitTest->bSizeBar = false;
1452 // so that leftover tabs and indents are taken into account
1453 tools::Long nXExtraOff;
1454 if ( !mpData->pTabs.empty() || !mpData->pIndents.empty() )
1455 nXExtraOff = (mnVirHeight / 2) - 4;
1456 else
1457 nXExtraOff = 0;
1459 // test if outside
1460 nX -= mnVirOff;
1461 if ( (nX < mpData->nRulVirOff - nXExtraOff) ||
1462 (nX > mpData->nRulVirOff + mpData->nRulWidth + nXExtraOff) ||
1463 (nY < 0) ||
1464 (nY > nHitBottom) )
1466 pHitTest->nPos = 0;
1467 pHitTest->eType = RulerType::Outside;
1468 return false;
1471 nX -= mpData->nNullVirOff;
1472 pHitTest->nPos = nX;
1473 pHitTest->eType = RulerType::DontKnow;
1475 // first test the tabs
1476 tools::Rectangle aRect;
1477 if ( !mpData->pTabs.empty() )
1479 aRect.SetBottom( nHitBottom );
1480 aRect.SetTop( aRect.Bottom() - ruler_tab.height - RULER_OFF );
1482 for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1484 nStyle = mpData->pTabs[i].nStyle;
1485 if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1487 nStyle &= RULER_TAB_STYLE;
1489 // default tabs are only shown (no action)
1490 if ( nStyle != RULER_TAB_DEFAULT )
1492 n1 = mpData->pTabs[i].nPos;
1494 if ( nStyle == RULER_TAB_LEFT )
1496 aRect.SetLeft( n1 );
1497 aRect.SetRight( n1 + ruler_tab.width - 1 );
1499 else if ( nStyle == RULER_TAB_RIGHT )
1501 aRect.SetRight( n1 );
1502 aRect.SetLeft( n1 - ruler_tab.width - 1 );
1504 else
1506 aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1507 aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1510 if ( aRect.Contains( Point( nX, nY ) ) )
1512 pHitTest->eType = RulerType::Tab;
1513 pHitTest->nAryPos = i;
1514 return true;
1521 // Indents
1522 if ( !mpData->pIndents.empty() )
1524 tools::Long nIndentHeight = (mnVirHeight / 2) - 1;
1525 tools::Long nIndentWidth2 = nIndentHeight - 3;
1527 for ( i = mpData->pIndents.size(); i; i-- )
1529 RulerIndentStyle nIndentStyle = mpData->pIndents[i-1].nStyle;
1530 if ( (! bRequireStyle || nIndentStyle == nRequiredStyle) &&
1531 !mpData->pIndents[i-1].bInvisible )
1533 n1 = mpData->pIndents[i-1].nPos;
1535 if ( (nIndentStyle == RulerIndentStyle::Bottom) != !bIsHori )
1537 aRect.SetLeft( n1-nIndentWidth2 );
1538 aRect.SetRight( n1+nIndentWidth2 );
1539 aRect.SetTop( nHitBottom-nIndentHeight-RULER_OFF+1 );
1540 aRect.SetBottom( nHitBottom );
1542 else
1544 aRect.SetLeft( n1-nIndentWidth2 );
1545 aRect.SetRight( n1+nIndentWidth2 );
1546 aRect.SetTop( 0 );
1547 aRect.SetBottom( nIndentHeight+RULER_OFF-1 );
1550 if ( aRect.Contains( Point( nX, nY ) ) )
1552 pHitTest->eType = RulerType::Indent;
1553 pHitTest->nAryPos = i-1;
1554 return true;
1560 // test the borders
1561 int nBorderTolerance = 1;
1562 if(pHitTest->bExpandTest)
1564 nBorderTolerance++;
1567 for ( i = mpData->pBorders.size(); i; i-- )
1569 n1 = mpData->pBorders[i-1].nPos;
1570 tools::Long n2 = n1 + mpData->pBorders[i-1].nWidth;
1572 // borders have at least 3 pixel padding
1573 if ( !mpData->pBorders[i-1].nWidth )
1575 n1 -= nBorderTolerance;
1576 n2 += nBorderTolerance;
1580 if ( (nX >= n1) && (nX <= n2) )
1582 RulerBorderStyle nBorderStyle = mpData->pBorders[i-1].nStyle;
1583 if ( !(nBorderStyle & RulerBorderStyle::Invisible) )
1585 pHitTest->eType = RulerType::Border;
1586 pHitTest->nAryPos = i-1;
1588 if ( !(nBorderStyle & RulerBorderStyle::Sizeable) )
1590 if ( nBorderStyle & RulerBorderStyle::Moveable )
1592 pHitTest->bSizeBar = true;
1593 pHitTest->mnDragSize = RulerDragSize::Move;
1596 else
1598 tools::Long nMOff = RULER_MOUSE_BORDERWIDTH;
1599 while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) )
1601 if ( nMOff < 2 )
1603 nMOff = 0;
1604 break;
1606 else
1607 nMOff--;
1610 if ( nX <= n1+nMOff )
1612 pHitTest->bSize = true;
1613 pHitTest->mnDragSize = RulerDragSize::N1;
1615 else if ( nX >= n2-nMOff )
1617 pHitTest->bSize = true;
1618 pHitTest->mnDragSize = RulerDragSize::N2;
1620 else
1622 if ( nBorderStyle & RulerBorderStyle::Moveable )
1624 pHitTest->bSizeBar = true;
1625 pHitTest->mnDragSize = RulerDragSize::Move;
1630 return true;
1635 // Margins
1636 int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH;
1638 if ( (mpData->nMargin1Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1640 n1 = mpData->nMargin1;
1641 if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1643 pHitTest->eType = RulerType::Margin1;
1644 pHitTest->bSize = true;
1645 return true;
1648 if ( (mpData->nMargin2Style & (RulerMarginStyle::Sizeable | RulerMarginStyle::Invisible)) == RulerMarginStyle::Sizeable )
1650 n1 = mpData->nMargin2;
1651 if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) )
1653 pHitTest->eType = RulerType::Margin2;
1654 pHitTest->bSize = true;
1655 return true;
1659 // test tabs again
1660 if ( !mpData->pTabs.empty() )
1662 aRect.SetTop( RULER_OFF );
1663 aRect.SetBottom( nHitBottom );
1665 for ( i = mpData->pTabs.size() - 1; i >= 0; i-- )
1667 nStyle = mpData->pTabs[i].nStyle;
1668 if ( !(nStyle & RULER_STYLE_INVISIBLE) )
1670 nStyle &= RULER_TAB_STYLE;
1672 // default tabs are only shown (no action)
1673 if ( nStyle != RULER_TAB_DEFAULT )
1675 n1 = mpData->pTabs[i].nPos;
1677 if ( nStyle == RULER_TAB_LEFT )
1679 aRect.SetLeft( n1 );
1680 aRect.SetRight( n1 + ruler_tab.width - 1 );
1682 else if ( nStyle == RULER_TAB_RIGHT )
1684 aRect.SetRight( n1 );
1685 aRect.SetLeft( n1 - ruler_tab.width - 1 );
1687 else
1689 aRect.SetLeft( n1 - ruler_tab.cwidth2 + 1 );
1690 aRect.SetRight( n1 - ruler_tab.cwidth2 + ruler_tab.cwidth );
1693 aRect.AdjustLeft( -1 );
1694 aRect.AdjustRight( 1 );
1696 if ( aRect.Contains( Point( nX, nY ) ) )
1698 pHitTest->eType = RulerType::Tab;
1699 pHitTest->nAryPos = i;
1700 return true;
1707 return false;
1710 bool Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType,
1711 RulerSelection* pHitTest ) const
1713 Point aPos = rPos;
1714 bool bRequiredStyle = false;
1715 RulerIndentStyle nRequiredStyle = RulerIndentStyle::Top;
1717 if (eDragType == RulerType::Indent)
1719 bRequiredStyle = true;
1720 nRequiredStyle = RulerIndentStyle::Bottom;
1723 if ( mnWinStyle & WB_HORZ )
1724 aPos.AdjustX(mnWinOff );
1725 else
1726 aPos.AdjustY(mnWinOff );
1728 if ( (eDragType == RulerType::Indent) || (eDragType == RulerType::DontKnow) )
1730 if ( mnWinStyle & WB_HORZ )
1731 aPos.setY( RULER_OFF + 1 );
1732 else
1733 aPos.setX( RULER_OFF + 1 );
1735 if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) )
1737 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1738 return true;
1742 if ( (eDragType == RulerType::Indent) ||
1743 (eDragType == RulerType::Tab) ||
1744 (eDragType == RulerType::DontKnow) )
1746 if ( mnWinStyle & WB_HORZ )
1747 aPos.setY( mnHeight - RULER_OFF - 1 );
1748 else
1749 aPos.setX( mnWidth - RULER_OFF - 1 );
1751 if ( ImplDoHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) )
1753 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1754 return true;
1758 if ( (eDragType == RulerType::Margin1) || (eDragType == RulerType::Margin2) ||
1759 (eDragType == RulerType::Border) || (eDragType == RulerType::DontKnow) )
1761 if ( mnWinStyle & WB_HORZ )
1762 aPos.setY( RULER_OFF + (mnVirHeight / 2) );
1763 else
1764 aPos.setX( RULER_OFF + (mnVirHeight / 2) );
1766 if ( ImplDoHitTest( aPos, pHitTest ) )
1768 if ( (pHitTest->eType == eDragType) || (eDragType == RulerType::DontKnow) )
1769 return true;
1773 pHitTest->eType = RulerType::DontKnow;
1775 return false;
1778 bool Ruler::ImplStartDrag( RulerSelection const * pHitTest, sal_uInt16 nModifier )
1780 // don't trigger drag if a border that was clicked can not be changed
1781 if ( (pHitTest->eType == RulerType::Border) &&
1782 !pHitTest->bSize && !pHitTest->bSizeBar )
1783 return false;
1785 // Set drag data
1786 meDragType = pHitTest->eType;
1787 mnDragPos = pHitTest->nPos;
1788 mnDragAryPos = pHitTest->nAryPos;
1789 mnDragSize = pHitTest->mnDragSize;
1790 mnDragModifier = nModifier;
1791 *mpDragData = *mpSaveData;
1792 mpData = mpDragData.get();
1794 // call handler
1795 if (StartDrag())
1797 // if the handler allows dragging, initialize dragging
1798 mbDrag = true;
1799 mnStartDragPos = mnDragPos;
1800 StartTracking();
1801 Invalidate(InvalidateFlags::NoErase);
1802 return true;
1804 else
1806 // otherwise reset the data
1807 meDragType = RulerType::DontKnow;
1808 mnDragPos = 0;
1809 mnDragAryPos = 0;
1810 mnDragSize = RulerDragSize::Move;
1811 mnDragModifier = 0;
1812 mpData = mpSaveData.get();
1815 return false;
1818 void Ruler::ImplDrag( const Point& rPos )
1820 tools::Long nX;
1821 tools::Long nY;
1822 tools::Long nOutHeight;
1824 if ( mnWinStyle & WB_HORZ )
1826 nX = rPos.X();
1827 nY = rPos.Y();
1828 nOutHeight = mnHeight;
1830 else
1832 nX = rPos.Y();
1833 nY = rPos.X();
1834 nOutHeight = mnWidth;
1837 // calculate and fit X
1838 nX -= mnVirOff;
1839 if ( nX < mpData->nRulVirOff )
1841 nX = mpData->nRulVirOff;
1843 else if ( nX > mpData->nRulVirOff+mpData->nRulWidth )
1845 nX = mpData->nRulVirOff+mpData->nRulWidth;
1847 nX -= mpData->nNullVirOff;
1849 // if upper or left from ruler, then consider old values
1850 mbDragDelete = false;
1851 if ( nY < 0 )
1853 if ( !mbDragCanceled )
1855 // reset the data
1856 mbDragCanceled = true;
1857 ImplRulerData aTempData = *mpDragData;
1858 *mpDragData = *mpSaveData;
1859 mbCalc = true;
1860 mbFormat = true;
1862 // call handler
1863 mnDragPos = mnStartDragPos;
1864 Drag();
1866 // and redraw
1867 Invalidate(InvalidateFlags::NoErase);
1869 // reset the data as before cancel
1870 *mpDragData = aTempData;
1873 else
1875 mbDragCanceled = false;
1877 // +2, so the tabs are not cleared too quickly
1878 if ( nY > nOutHeight + 2 )
1879 mbDragDelete = true;
1881 mnDragPos = nX;
1883 // call handler
1884 Drag();
1886 // redraw
1887 if (mbFormat)
1888 Invalidate(InvalidateFlags::NoErase);
1892 void Ruler::ImplEndDrag()
1894 // get values
1895 if ( mbDragCanceled )
1896 *mpDragData = *mpSaveData;
1897 else
1898 *mpSaveData = *mpDragData;
1900 mpData = mpSaveData.get();
1901 mbDrag = false;
1903 // call handler
1904 EndDrag();
1906 // reset drag values
1907 meDragType = RulerType::DontKnow;
1908 mnDragPos = 0;
1909 mnDragAryPos = 0;
1910 mnDragSize = RulerDragSize::Move;
1911 mbDragCanceled = false;
1912 mbDragDelete = false;
1913 mnDragModifier = 0;
1914 mnStartDragPos = 0;
1916 // redraw
1917 Invalidate(InvalidateFlags::NoErase);
1920 void Ruler::MouseButtonDown( const MouseEvent& rMEvt )
1922 if ( !rMEvt.IsLeft() || IsTracking() )
1923 return;
1925 Point aMousePos = rMEvt.GetPosPixel();
1926 sal_uInt16 nMouseClicks = rMEvt.GetClicks();
1927 sal_uInt16 nMouseModifier = rMEvt.GetModifier();
1929 // update ruler
1930 if ( mbFormat )
1932 Invalidate(InvalidateFlags::NoErase);
1935 if ( maExtraRect.Contains( aMousePos ) )
1937 ExtraDown();
1939 else
1941 RulerSelection aHitTest;
1942 bool bHitTestResult = ImplDoHitTest(aMousePos, &aHitTest);
1944 if ( nMouseClicks == 1 )
1946 if ( bHitTestResult )
1948 ImplStartDrag( &aHitTest, nMouseModifier );
1950 else
1952 // calculate position inside of ruler area
1953 if ( aHitTest.eType == RulerType::DontKnow )
1955 mnDragPos = aHitTest.nPos;
1956 Click();
1957 mnDragPos = 0;
1959 // call HitTest again as a click, for example, could set a new tab
1960 if ( ImplDoHitTest(aMousePos, &aHitTest) )
1961 ImplStartDrag(&aHitTest, nMouseModifier);
1965 else
1967 if (bHitTestResult)
1969 mnDragPos = aHitTest.nPos;
1970 mnDragAryPos = aHitTest.nAryPos;
1972 meDragType = aHitTest.eType;
1974 DoubleClick();
1976 meDragType = RulerType::DontKnow;
1977 mnDragPos = 0;
1978 mnDragAryPos = 0;
1983 void Ruler::MouseMove( const MouseEvent& rMEvt )
1985 PointerStyle ePtrStyle = PointerStyle::Arrow;
1987 mxPreviousHitTest.swap(mxCurrentHitTest);
1989 mxCurrentHitTest.reset(new RulerSelection);
1991 maHoverSelection.eType = RulerType::DontKnow;
1993 if (ImplDoHitTest( rMEvt.GetPosPixel(), mxCurrentHitTest.get() ))
1995 maHoverSelection = *mxCurrentHitTest;
1997 if (mxCurrentHitTest->bSize)
1999 if (mnWinStyle & WB_HORZ)
2001 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
2002 ePtrStyle = PointerStyle::TabSelectW;
2003 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2004 ePtrStyle = PointerStyle::TabSelectE;
2005 else
2006 ePtrStyle = PointerStyle::ESize;
2008 else
2010 if (mxCurrentHitTest->mnDragSize == RulerDragSize::N1)
2011 ePtrStyle = PointerStyle::WindowNSize;
2012 else if (mxCurrentHitTest->mnDragSize == RulerDragSize::N2)
2013 ePtrStyle = PointerStyle::WindowSSize;
2014 else
2015 ePtrStyle = PointerStyle::SSize;
2018 else if (mxCurrentHitTest->bSizeBar)
2020 if (mnWinStyle & WB_HORZ)
2021 ePtrStyle = PointerStyle::HSizeBar;
2022 else
2023 ePtrStyle = PointerStyle::VSizeBar;
2027 if (mxPreviousHitTest != nullptr && mxPreviousHitTest->eType != mxCurrentHitTest->eType)
2029 mbFormat = true;
2032 SetPointer( ePtrStyle );
2034 if (mbFormat)
2036 Invalidate(InvalidateFlags::NoErase);
2040 void Ruler::Tracking( const TrackingEvent& rTEvt )
2042 if ( rTEvt.IsTrackingEnded() )
2044 // reset the old state at cancel
2045 if ( rTEvt.IsTrackingCanceled() )
2047 mbDragCanceled = true;
2048 mbFormat = true;
2051 ImplEndDrag();
2053 else
2054 ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() );
2057 void Ruler::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2059 ImplDraw(rRenderContext);
2061 // consider extra field
2062 if (mnWinStyle & WB_EXTRAFIELD)
2063 ImplDrawExtra(rRenderContext);
2066 void Ruler::Resize()
2068 Size aWinSize = GetOutputSizePixel();
2070 tools::Long nNewHeight;
2071 if ( mnWinStyle & WB_HORZ )
2073 if ( aWinSize.Height() != mnHeight )
2074 nNewHeight = aWinSize.Height();
2075 else
2076 nNewHeight = 0;
2078 else
2080 if ( aWinSize.Width() != mnWidth )
2081 nNewHeight = aWinSize.Width();
2082 else
2083 nNewHeight = 0;
2086 mbFormat = true;
2088 // clear lines
2089 bool bVisible = IsReallyVisible();
2090 if ( bVisible && !mpData->pLines.empty() )
2092 mnUpdateFlags |= RULER_UPDATE_LINES;
2093 Invalidate(InvalidateFlags::NoErase);
2096 // recalculate some values if the height/width changes
2097 // extra field should always be updated
2098 ImplInitExtraField( mpData->bTextRTL );
2099 if ( nNewHeight )
2101 mbCalc = true;
2102 mnVirHeight = nNewHeight - mnBorderWidth - ( RULER_OFF * 2 );
2104 else
2106 if ( mpData->bAutoPageWidth )
2107 ImplUpdate( true );
2108 else if ( mbAutoWinWidth )
2109 mbCalc = true;
2112 // clear part of the border
2113 if ( bVisible )
2115 if ( nNewHeight )
2116 Invalidate(InvalidateFlags::NoErase);
2117 else if ( mpData->bAutoPageWidth )
2119 // only at AutoPageWidth do we need to redraw
2120 tools::Rectangle aRect;
2122 if ( mnWinStyle & WB_HORZ )
2124 if ( mnWidth < aWinSize.Width() )
2125 aRect.SetLeft( mnWidth - RULER_RESIZE_OFF );
2126 else
2127 aRect.SetLeft( aWinSize.Width() - RULER_RESIZE_OFF );
2128 aRect.SetRight( aRect.Left() + RULER_RESIZE_OFF );
2129 aRect.SetTop( RULER_OFF );
2130 aRect.SetBottom( RULER_OFF + mnVirHeight );
2132 else
2134 if ( mnHeight < aWinSize.Height() )
2135 aRect.SetTop( mnHeight-RULER_RESIZE_OFF );
2136 else
2137 aRect.SetTop( aWinSize.Height()-RULER_RESIZE_OFF );
2138 aRect.SetBottom( aRect.Top() + RULER_RESIZE_OFF );
2139 aRect.SetLeft( RULER_OFF );
2140 aRect.SetRight( RULER_OFF + mnVirHeight );
2143 Invalidate(aRect, InvalidateFlags::NoErase);
2147 mnWidth = aWinSize.Width();
2148 mnHeight = aWinSize.Height();
2151 void Ruler::StateChanged( StateChangedType nType )
2153 Window::StateChanged( nType );
2155 if ( nType == StateChangedType::InitShow )
2156 Invalidate();
2157 else if ( nType == StateChangedType::UpdateMode )
2159 if ( IsReallyVisible() && IsUpdateMode() )
2160 Invalidate();
2162 else if ( (nType == StateChangedType::Zoom) ||
2163 (nType == StateChangedType::ControlFont) )
2165 ImplInitSettings( true, false, false );
2166 Invalidate();
2168 else if ( nType == StateChangedType::ControlForeground )
2170 ImplInitSettings( false, true, false );
2171 Invalidate();
2173 else if ( nType == StateChangedType::ControlBackground )
2175 ImplInitSettings( false, false, true );
2176 Invalidate();
2180 void Ruler::DataChanged( const DataChangedEvent& rDCEvt )
2182 Window::DataChanged( rDCEvt );
2184 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2185 (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
2186 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2187 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2188 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2190 mbFormat = true;
2191 ImplInitSettings( true, true, true );
2192 Invalidate();
2196 bool Ruler::StartDrag()
2198 return false;
2201 void Ruler::Drag()
2205 void Ruler::EndDrag()
2209 void Ruler::Click()
2213 void Ruler::DoubleClick()
2215 maDoubleClickHdl.Call( this );
2218 void Ruler::ExtraDown()
2222 void Ruler::Activate()
2224 mbActive = true;
2226 // update positionlines - draw is delayed
2227 mnUpdateFlags |= RULER_UPDATE_LINES;
2228 Invalidate(InvalidateFlags::NoErase);
2231 void Ruler::Deactivate()
2233 // clear positionlines
2234 Invalidate(InvalidateFlags::NoErase);
2236 mbActive = false;
2239 bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType )
2241 if ( !mbDrag )
2243 Point aMousePos = rMEvt.GetPosPixel();
2244 sal_uInt16 nMouseClicks = rMEvt.GetClicks();
2245 sal_uInt16 nMouseModifier = rMEvt.GetModifier();
2246 RulerSelection aHitTest;
2248 if(eDragType != RulerType::DontKnow)
2249 aHitTest.bExpandTest = true;
2251 // update ruler
2252 if ( mbFormat )
2254 if (!IsReallyVisible())
2256 // set mpData for ImplDocHitTest()
2257 ImplFormat(*GetOutDev());
2260 Invalidate(InvalidateFlags::NoErase);
2263 if ( nMouseClicks == 1 )
2265 if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) )
2267 PointerStyle aPtr = PointerStyle::Arrow;
2269 if ( aHitTest.bSize )
2271 if ( mnWinStyle & WB_HORZ )
2272 aPtr = PointerStyle::ESize;
2273 else
2274 aPtr = PointerStyle::SSize;
2276 else if ( aHitTest.bSizeBar )
2278 if ( mnWinStyle & WB_HORZ )
2279 aPtr = PointerStyle::HSizeBar;
2280 else
2281 aPtr = PointerStyle::VSizeBar;
2283 SetPointer( aPtr );
2284 return ImplStartDrag( &aHitTest, nMouseModifier );
2287 else if ( nMouseClicks == 2 )
2289 if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) )
2291 mnDragPos = aHitTest.nPos;
2292 mnDragAryPos = aHitTest.nAryPos;
2295 DoubleClick();
2297 mnDragPos = 0;
2298 mnDragAryPos = 0;
2300 return true;
2304 return false;
2307 void Ruler::CancelDrag()
2309 if ( mbDrag )
2311 ImplDrag( Point( -1, -1 ) );
2312 ImplEndDrag();
2316 RulerType Ruler::GetRulerType( const Point& rPos, sal_uInt16* pAryPos )
2318 RulerSelection aHitTest;
2320 // update ruler
2321 if ( IsReallyVisible() && mbFormat )
2323 Invalidate(InvalidateFlags::NoErase);
2326 (void)ImplDoHitTest(rPos, &aHitTest);
2328 // return values
2329 if ( pAryPos )
2330 *pAryPos = aHitTest.nAryPos;
2331 return aHitTest.eType;
2334 void Ruler::SetWinPos( tools::Long nNewOff, tools::Long nNewWidth )
2336 // should widths be automatically calculated
2337 if ( !nNewWidth )
2338 mbAutoWinWidth = true;
2339 else
2340 mbAutoWinWidth = false;
2342 mnWinOff = nNewOff;
2343 mnWinWidth = nNewWidth;
2344 ImplUpdate( true );
2347 void Ruler::SetPagePos( tools::Long nNewOff, tools::Long nNewWidth )
2349 // should we do anything?
2350 if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) )
2351 return;
2353 // should widths be automatically calculated
2354 if ( !nNewWidth )
2355 mpData->bAutoPageWidth = true;
2356 else
2357 mpData->bAutoPageWidth = false;
2359 mpData->nPageOff = nNewOff;
2360 mpData->nPageWidth = nNewWidth;
2361 ImplUpdate( true );
2364 void Ruler::SetBorderPos( tools::Long nOff )
2366 if ( mnWinStyle & WB_BORDER )
2368 if ( mnBorderOff != nOff )
2370 mnBorderOff = nOff;
2372 if ( IsReallyVisible() && IsUpdateMode() )
2373 Invalidate(InvalidateFlags::NoErase);
2378 void Ruler::SetUnit( FieldUnit eNewUnit )
2380 if ( meUnit == eNewUnit )
2381 return;
2383 meUnit = eNewUnit;
2384 switch ( meUnit )
2386 case FieldUnit::MM:
2387 mnUnitIndex = RULER_UNIT_MM;
2388 break;
2389 case FieldUnit::CM:
2390 mnUnitIndex = RULER_UNIT_CM;
2391 break;
2392 case FieldUnit::M:
2393 mnUnitIndex = RULER_UNIT_M;
2394 break;
2395 case FieldUnit::KM:
2396 mnUnitIndex = RULER_UNIT_KM;
2397 break;
2398 case FieldUnit::INCH:
2399 mnUnitIndex = RULER_UNIT_INCH;
2400 break;
2401 case FieldUnit::FOOT:
2402 mnUnitIndex = RULER_UNIT_FOOT;
2403 break;
2404 case FieldUnit::MILE:
2405 mnUnitIndex = RULER_UNIT_MILE;
2406 break;
2407 case FieldUnit::POINT:
2408 mnUnitIndex = RULER_UNIT_POINT;
2409 break;
2410 case FieldUnit::PICA:
2411 mnUnitIndex = RULER_UNIT_PICA;
2412 break;
2413 case FieldUnit::CHAR:
2414 mnUnitIndex = RULER_UNIT_CHAR;
2415 break;
2416 case FieldUnit::LINE:
2417 mnUnitIndex = RULER_UNIT_LINE;
2418 break;
2419 default:
2420 SAL_WARN( "svtools.control", "Ruler::SetUnit() - Wrong Unit" );
2421 break;
2424 maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit );
2425 ImplUpdate();
2428 void Ruler::SetZoom( const Fraction& rNewZoom )
2430 DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" );
2432 if ( maZoom != rNewZoom )
2434 maZoom = rNewZoom;
2435 maMapMode.SetScaleX( maZoom );
2436 maMapMode.SetScaleY( maZoom );
2437 ImplUpdate();
2441 void Ruler::SetExtraType( RulerExtra eNewExtraType, sal_uInt16 nStyle )
2443 if ( mnWinStyle & WB_EXTRAFIELD )
2445 meExtraType = eNewExtraType;
2446 mnExtraStyle = nStyle;
2447 if (IsReallyVisible() && IsUpdateMode())
2448 Invalidate();
2452 void Ruler::SetNullOffset( tools::Long nPos )
2454 if ( mpData->nNullOff != nPos )
2456 mpData->nNullVirOff += nPos - mpData->nNullOff;
2457 mpData->nNullOff = nPos;
2458 ImplUpdate();
2462 void Ruler::SetLeftFrameMargin( tools::Long nPos )
2464 if ( mpData->nLeftFrameMargin != nPos )
2466 mpData->nLeftFrameMargin = nPos;
2467 ImplUpdate();
2471 void Ruler::SetRightFrameMargin( tools::Long nPos )
2473 if ( mpData->nRightFrameMargin != nPos )
2475 mpData->nRightFrameMargin = nPos;
2476 ImplUpdate();
2480 void Ruler::SetMargin1( tools::Long nPos, RulerMarginStyle nMarginStyle )
2482 if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) )
2484 mpData->nMargin1 = nPos;
2485 mpData->nMargin1Style = nMarginStyle;
2486 ImplUpdate();
2490 void Ruler::SetMargin2( tools::Long nPos, RulerMarginStyle nMarginStyle )
2492 DBG_ASSERT( (nPos >= mpData->nMargin1) ||
2493 (mpData->nMargin1Style & RulerMarginStyle::Invisible) ||
2494 (mpData->nMargin2Style & RulerMarginStyle::Invisible),
2495 "Ruler::SetMargin2() - Margin2 < Margin1" );
2497 if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) )
2499 mpData->nMargin2 = nPos;
2500 mpData->nMargin2Style = nMarginStyle;
2501 ImplUpdate();
2505 void Ruler::SetLines( sal_uInt32 aLineArraySize, const RulerLine* pLineArray )
2507 // To determine if what has changed
2508 if ( mpData->pLines.size() == aLineArraySize )
2510 sal_uInt32 i = aLineArraySize;
2511 std::vector<RulerLine>::const_iterator aItr1 = mpData->pLines.begin();
2512 const RulerLine* pAry2 = pLineArray;
2513 while ( i )
2515 if ( aItr1->nPos != pAry2->nPos )
2516 break;
2517 ++aItr1;
2518 ++pAry2;
2519 i--;
2521 if ( !i )
2522 return;
2525 // New values and new share issue
2526 bool bMustUpdate;
2527 bMustUpdate = IsReallyVisible() && IsUpdateMode();
2529 // Delete old lines
2530 if ( bMustUpdate )
2531 Invalidate(InvalidateFlags::NoErase);
2533 // New data set
2534 if ( !aLineArraySize || !pLineArray )
2536 if ( mpData->pLines.empty() )
2537 return;
2538 mpData->pLines.clear();
2540 else
2542 if ( mpData->pLines.size() != aLineArraySize )
2544 mpData->pLines.resize(aLineArraySize);
2547 std::copy( pLineArray,
2548 pLineArray + aLineArraySize,
2549 mpData->pLines.begin() );
2551 if ( bMustUpdate )
2552 Invalidate(InvalidateFlags::NoErase);
2556 void Ruler::SetBorders( sal_uInt32 aBorderArraySize, const RulerBorder* pBorderArray )
2558 if ( !aBorderArraySize || !pBorderArray )
2560 if ( mpData->pBorders.empty() )
2561 return;
2562 mpData->pBorders.clear();
2564 else
2566 if ( mpData->pBorders.size() != aBorderArraySize )
2568 mpData->pBorders.resize(aBorderArraySize);
2570 else
2572 sal_uInt32 i = aBorderArraySize;
2573 const RulerBorder* pAry1 = mpData->pBorders.data();
2574 const RulerBorder* pAry2 = pBorderArray;
2575 while ( i )
2577 if ( (pAry1->nPos != pAry2->nPos) ||
2578 (pAry1->nWidth != pAry2->nWidth) ||
2579 (pAry1->nStyle != pAry2->nStyle) )
2580 break;
2581 pAry1++;
2582 pAry2++;
2583 i--;
2585 if ( !i )
2586 return;
2588 std::copy( pBorderArray,
2589 pBorderArray + aBorderArraySize,
2590 mpData->pBorders.begin() );
2593 ImplUpdate();
2596 void Ruler::SetIndents( sal_uInt32 aIndentArraySize, const RulerIndent* pIndentArray )
2599 if ( !aIndentArraySize || !pIndentArray )
2601 if ( mpData->pIndents.empty() )
2602 return;
2603 mpData->pIndents.clear();
2605 else
2607 if ( mpData->pIndents.size() != aIndentArraySize )
2609 mpData->pIndents.resize(aIndentArraySize);
2611 else
2613 sal_uInt32 i = aIndentArraySize;
2614 const RulerIndent* pAry1 = mpData->pIndents.data();
2615 const RulerIndent* pAry2 = pIndentArray;
2616 while ( i )
2618 if ( (pAry1->nPos != pAry2->nPos) ||
2619 (pAry1->nStyle != pAry2->nStyle) )
2620 break;
2621 pAry1++;
2622 pAry2++;
2623 i--;
2625 if ( !i )
2626 return;
2629 std::copy( pIndentArray,
2630 pIndentArray + aIndentArraySize,
2631 mpData->pIndents.begin() );
2634 ImplUpdate();
2637 void Ruler::SetTabs( sal_uInt32 aTabArraySize, const RulerTab* pTabArray )
2639 if ( aTabArraySize == 0 || pTabArray == nullptr )
2641 if ( mpData->pTabs.empty() )
2642 return;
2643 mpData->pTabs.clear();
2645 else
2647 if ( mpData->pTabs.size() != aTabArraySize )
2649 mpData->pTabs.resize(aTabArraySize);
2651 else
2653 sal_uInt32 i = aTabArraySize;
2654 std::vector<RulerTab>::iterator aTabIterator = mpData->pTabs.begin();
2655 const RulerTab* pInputArray = pTabArray;
2656 while ( i )
2658 RulerTab& aCurrent = *aTabIterator;
2659 if ( aCurrent.nPos != pInputArray->nPos ||
2660 aCurrent.nStyle != pInputArray->nStyle )
2662 break;
2664 ++aTabIterator;
2665 pInputArray++;
2666 i--;
2668 if ( !i )
2669 return;
2671 std::copy(pTabArray, pTabArray + aTabArraySize, mpData->pTabs.begin());
2674 ImplUpdate();
2677 const std::vector<RulerTab>& Ruler::GetTabs() const
2679 return mpData->pTabs;
2682 void Ruler::SetStyle( WinBits nStyle )
2684 if ( mnWinStyle != nStyle )
2686 mnWinStyle = nStyle;
2687 ImplInitExtraField( true );
2691 void Ruler::DrawTab(vcl::RenderContext& rRenderContext, const Color &rFillColor, const Point& rPos, sal_uInt16 nStyle)
2693 Point aPos(rPos);
2694 sal_uInt16 nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL);
2696 rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
2697 rRenderContext.SetLineColor();
2698 rRenderContext.SetFillColor(rFillColor);
2699 ImplCenterTabPos(aPos, nTabStyle);
2700 ImplDrawRulerTab(rRenderContext, aPos, nTabStyle, nStyle);
2701 rRenderContext.Pop();
2704 void Ruler::SetTextRTL(bool bRTL)
2706 if(mpData->bTextRTL != bRTL)
2708 mpData->bTextRTL = bRTL;
2709 if ( IsReallyVisible() && IsUpdateMode() )
2710 ImplInitExtraField( true );
2715 tools::Long Ruler::GetPageOffset() const
2717 return mpData->nPageOff;
2720 tools::Long Ruler::GetNullOffset() const
2722 return mpData->nNullOff;
2725 tools::Long Ruler::GetMargin1() const
2727 return mpData->nMargin1;
2730 tools::Long Ruler::GetMargin2() const
2732 return mpData->nMargin2;
2736 bool Ruler::GetTextRTL() const
2738 return mpData->bTextRTL;
2741 const RulerUnitData& Ruler::GetCurrentRulerUnit() const
2743 return aImplRulerUnitTab[mnUnitIndex];
2746 void Ruler::DrawTicks()
2748 mbFormat = true;
2749 Invalidate(InvalidateFlags::NoErase);
2752 uno::Reference< XAccessible > Ruler::CreateAccessible()
2754 vcl::Window* pParent = GetAccessibleParentWindow();
2755 OSL_ENSURE( pParent, "-SvxRuler::CreateAccessible(): No Parent!" );
2756 uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
2757 if( xAccParent.is() )
2759 // MT: Fixed compiler issue because the address from a temporary object was used.
2760 // BUT: Should it really be a Pointer, instead of const&???
2761 OUString aStr;
2762 if ( mnWinStyle & WB_HORZ )
2764 aStr = SvtResId(STR_SVT_ACC_RULER_HORZ_NAME);
2766 else
2768 aStr = SvtResId(STR_SVT_ACC_RULER_VERT_NAME);
2770 mxAccContext = new SvtRulerAccessible( xAccParent, *this, aStr );
2771 SetAccessible(mxAccContext);
2772 return mxAccContext;
2774 else
2775 return uno::Reference< XAccessible >();
2778 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */