1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <cstring>
21 #include <climits>
22 
23 #include <vcl/commandevent.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/fieldvalues.hxx>
26 #include <vcl/image.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/weldutils.hxx>
31 #include <svl/eitem.hxx>
32 #include <svl/rectitem.hxx>
33 #include <svl/hint.hxx>
34 #include <sfx2/dispatch.hxx>
35 #include <svx/strings.hrc>
36 #include <svx/svxids.hrc>
37 #include <svx/dialmgr.hxx>
38 #include <svx/ruler.hxx>
39 #include <svx/rulritem.hxx>
40 #include <editeng/editids.hrc>
41 #include <editeng/tstpitem.hxx>
42 #include <editeng/lrspitem.hxx>
43 #include <editeng/protitem.hxx>
44 #include <osl/diagnose.h>
45 #include <rtl/math.hxx>
46 
47 #include "rlrcitem.hxx"
48 #include <memory>
49 
50 #define CTRL_ITEM_COUNT 14
51 #define GAP 10
52 #define OBJECT_BORDER_COUNT 4
53 #define TAB_GAP 1
54 #define INDENT_GAP 2
55 #define INDENT_FIRST_LINE   2
56 #define INDENT_LEFT_MARGIN  3
57 #define INDENT_RIGHT_MARGIN 4
58 #define INDENT_COUNT        3 //without the first two old values
59 
60 struct SvxRuler_Impl {
61     std::unique_ptr<sal_uInt16[]> pPercBuf;
62     std::unique_ptr<sal_uInt16[]> pBlockBuf;
63     sal_uInt16 nPercSize;
64     tools::Long   nTotalDist;
65     tools::Long   lOldWinPos;
66     tools::Long   lMaxLeftLogic;
67     tools::Long   lMaxRightLogic;
68     tools::Long   lLastLMargin;
69     tools::Long   lLastRMargin;
70     std::unique_ptr<SvxProtectItem> aProtectItem;
71     std::unique_ptr<SfxBoolItem> pTextRTLItem;
72     sal_uInt16 nControllerItems;
73     sal_uInt16 nIdx;
74     sal_uInt16 nColLeftPix;
75     sal_uInt16 nColRightPix;    // Pixel values for left / right edge
76                                 // For columns; buffered to prevent
77                                 // recalculation errors
78                                 // May be has to be widen for future values
79     bool bIsTableRows : 1;  // mxColumnItem contains table rows instead of columns
80     //#i24363# tab stops relative to indent
81     bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent?
82                                       // false means relative to SvxRuler::GetLeftFrameMargin()
83 
SvxRuler_ImplSvxRuler_Impl84     SvxRuler_Impl() :
85         nPercSize(0), nTotalDist(0),
86         lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0),
87         lLastLMargin(0), lLastRMargin(0),
88         aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)),
89         nControllerItems(0), nIdx(0),
90         nColLeftPix(0), nColRightPix(0),
91         bIsTableRows(false),
92         bIsTabsRelativeToIndent(true)
93     {
94     }
95 
96     void SetPercSize(sal_uInt16 nSize);
97 
98 };
99 
100 static RulerTabData ruler_tab_svx =
101 {
102     0, // DPIScaleFactor to be set
103     7, // ruler_tab_width
104     6, // ruler_tab_height
105     0, // ruler_tab_height2
106     0, // ruler_tab_width2
107     0, // ruler_tab_cwidth
108     0, // ruler_tab_cwidth2
109     0, // ruler_tab_cwidth3
110     0, // ruler_tab_cwidth4
111     0, // ruler_tab_dheight
112     0, // ruler_tab_dheight2
113     0, // ruler_tab_dwidth
114     0, // ruler_tab_dwidth2
115     0, // ruler_tab_dwidth3
116     0, // ruler_tab_dwidth4
117     0  // ruler_tab_textoff
118 };
119 
SetPercSize(sal_uInt16 nSize)120 void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize)
121 {
122     if(nSize > nPercSize)
123     {
124         nPercSize = nSize;
125         pPercBuf.reset( new sal_uInt16[nPercSize] );
126         pBlockBuf.reset( new sal_uInt16[nPercSize] );
127     }
128     size_t nSize2 = sizeof(sal_uInt16) * nPercSize;
129     memset(pPercBuf.get(), 0, nSize2);
130     memset(pBlockBuf.get(), 0, nSize2);
131 }
132 
133 // Constructor of the ruler
134 
135 // SID_ATTR_ULSPACE, SID_ATTR_LRSPACE
136 // expects as parameter SvxULSpaceItem for page edge
137 // (either left/right or top/bottom)
138 // Ruler: SetMargin1, SetMargin2
139 
140 // SID_RULER_PAGE_POS
141 // expects as parameter the initial value of the page and page width
142 // Ruler: SetPagePos
143 
144 // SID_ATTR_TABSTOP
145 // expects: SvxTabStopItem
146 // Ruler: SetTabs
147 
148 // SID_ATTR_PARA_LRSPACE
149 // left, right paragraph edge in H-ruler
150 // Ruler: SetIndents
151 
152 // SID_RULER_BORDERS
153 // Table borders, columns
154 // expects: something like SwTabCols
155 // Ruler: SetBorders
156 
157 constexpr tools::Long glMinFrame = 5;   // minimal frame width in pixels
158 
SvxRuler(vcl::Window * pParent,vcl::Window * pWin,SvxRulerSupportFlags flags,SfxBindings & rBindings,WinBits nWinStyle)159 SvxRuler::SvxRuler(
160             vcl::Window* pParent,        // StarView Parent
161             vcl::Window* pWin,           // Output window: is used for conversion
162                                          // logical units <-> pixels
163             SvxRulerSupportFlags flags,  // Display flags, see ruler.hxx
164             SfxBindings &rBindings,      // associated Bindings
165             WinBits nWinStyle) :         // StarView WinBits
166     Ruler(pParent, nWinStyle),
167     pCtrlItems(CTRL_ITEM_COUNT),
168     pEditWin(pWin),
169     mxRulerImpl(new SvxRuler_Impl),
170     bAppSetNullOffset(false),  // Is the 0-offset of the ruler set by the application?
171     lLogicNullOffset(0),
172     lAppNullOffset(LONG_MAX),
173     lInitialDragPos(0),
174     nFlags(flags),
175     nDragType(SvxRulerDragFlags::NONE),
176     nDefTabType(RULER_TAB_LEFT),
177     nTabCount(0),
178     nTabBufSize(0),
179     lDefTabDist(50),
180     lTabPos(-1),
181     mpBorders(1), // due to one column tables
182     pBindings(&rBindings),
183     nDragOffset(0),
184     nMaxLeft(0),
185     nMaxRight(0),
186     bValid(false),
187     bListening(false),
188     bActive(true),
189     mbCoarseSnapping(false),
190     mbSnapping(true)
191 
192 {
193     /* Constructor; Initialize data buffer; controller items are created */
194 
195     rBindings.EnterRegistrations();
196 
197     // Create Supported Items
198     sal_uInt16 i = 0;
199 
200     // Page edges
201     pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings));
202     if((nWinStyle & WB_VSCROLL) == WB_VSCROLL)
203     {
204         bHorz = false;
205         pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings));
206     }
207     else
208     {
209         bHorz = true;
210         pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings));
211     }
212 
213     // Page Position
214     pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings));
215 
216     if(nFlags & SvxRulerSupportFlags::TABS)
217     {
218         sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
219         pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings));
220         SetExtraType(RulerExtra::Tab, nDefTabType);
221     }
222 
223     if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
224     {
225         if(bHorz)
226             pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings));
227         else
228             pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings));
229 
230         mpIndents.resize(5 + INDENT_GAP);
231 
232         for(RulerIndent & rIndent : mpIndents)
233         {
234             rIndent.nPos = 0;
235             rIndent.nStyle = RulerIndentStyle::Top;
236         }
237 
238         mpIndents[0].nStyle = RulerIndentStyle::Top;
239         mpIndents[1].nStyle = RulerIndentStyle::Top;
240         mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top;
241         mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom;
242         mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom;
243     }
244 
245     if( (nFlags & SvxRulerSupportFlags::BORDERS) ==  SvxRulerSupportFlags::BORDERS )
246     {
247         pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings));
248         pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings));
249     }
250 
251     pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings));
252 
253     if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT )
254     {
255         pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings));
256         mpObjectBorders.resize(OBJECT_BORDER_COUNT);
257         for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder)
258         {
259             mpObjectBorders[nBorder].nPos   = 0;
260             mpObjectBorders[nBorder].nWidth = 0;
261             mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable;
262         }
263     }
264 
265     pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings));
266     pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings));
267     mxRulerImpl->nControllerItems=i;
268 
269     if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET )
270         SetExtraType(RulerExtra::NullOffset);
271 
272     rBindings.LeaveRegistrations();
273 
274     ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor();
275     ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor;
276     ruler_tab_svx.width  *= ruler_tab_svx.DPIScaleFactor;
277 
278 }
279 
~SvxRuler()280 SvxRuler::~SvxRuler()
281 {
282     disposeOnce();
283 }
284 
dispose()285 void SvxRuler::dispose()
286 {
287     /* Destructor ruler; release internal buffer */
288     if(bListening)
289         EndListening(*pBindings);
290 
291     pBindings->EnterRegistrations();
292 
293     pCtrlItems.clear();
294 
295     pBindings->LeaveRegistrations();
296 
297     pEditWin.clear();
298     Ruler::dispose();
299 }
300 
MakePositionSticky(tools::Long aPosition,tools::Long aPointOfReference,bool aSnapToFrameMargin) const301 tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const
302 {
303     tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference);
304     tools::Long aLeftFramePosition     = ConvertHPosPixel(GetLeftFrameMargin());
305     tools::Long aRightFramePosition    = ConvertHPosPixel(GetRightFrameMargin());
306 
307     double aTick = GetCurrentRulerUnit().nTick1;
308 
309     if (mbCoarseSnapping)
310         aTick = GetCurrentRulerUnit().nTick2;
311 
312     tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width();
313 
314     double aHalfTick = aTick / 2.0;
315     double aHalfTickPixel = aTickPixel / 2.0;
316 
317     if (aSnapToFrameMargin)
318     {
319         if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel)
320             return aLeftFramePosition;
321 
322         if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel)
323             return aRightFramePosition;
324     }
325 
326     if (!mbSnapping)
327         return aPosition;
328 
329     // Move "coordinate system" to frame position so ticks are calculated correctly
330     tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel;
331     // Convert position to current selected map mode
332     tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width();
333     // Normalize -- snap to nearest tick
334     aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick;
335     // Convert back to pixels
336     aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width();
337     // Move "coordinate system" back to original position
338     return aPosition + aPointOfReferencePixel;
339 }
340 
ConvertHPosPixel(tools::Long nVal) const341 tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const
342 {
343     return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
344 }
345 
ConvertVPosPixel(tools::Long nVal) const346 tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const
347 {
348     return pEditWin->LogicToPixel(Size(0, nVal)).Height();
349 }
350 
ConvertHSizePixel(tools::Long nVal) const351 tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const
352 {
353     return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
354 }
355 
ConvertVSizePixel(tools::Long nVal) const356 tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const
357 {
358     return pEditWin->LogicToPixel(Size(0, nVal)).Height();
359 }
360 
ConvertPosPixel(tools::Long nVal) const361 tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const
362 {
363     return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal);
364 }
365 
ConvertSizePixel(tools::Long nVal) const366 tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const
367 {
368     return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal);
369 }
370 
ConvertHPosLogic(tools::Long nVal) const371 inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const
372 {
373     return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
374 }
375 
ConvertVPosLogic(tools::Long nVal) const376 inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const
377 {
378     return pEditWin->PixelToLogic(Size(0, nVal)).Height();
379 }
380 
ConvertHSizeLogic(tools::Long nVal) const381 inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const
382 {
383     return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
384 }
385 
ConvertVSizeLogic(tools::Long nVal) const386 inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const
387 {
388     return pEditWin->PixelToLogic(Size(0, nVal)).Height();
389 }
390 
ConvertPosLogic(tools::Long nVal) const391 inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const
392 {
393     return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal);
394 }
395 
ConvertSizeLogic(tools::Long nVal) const396 inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const
397 {
398     return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal);
399 }
400 
PixelHAdjust(tools::Long nVal,tools::Long nValOld) const401 tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const
402 {
403     if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld))
404         return  nVal;
405     else
406         return  nValOld;
407 }
408 
PixelVAdjust(tools::Long nVal,tools::Long nValOld) const409 tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const
410 {
411     if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld))
412         return  nVal;
413     else
414         return  nValOld;
415 }
416 
PixelAdjust(tools::Long nVal,tools::Long nValOld) const417 tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const
418 {
419     if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld))
420         return  nVal;
421     else
422         return  nValOld;
423 }
424 
GetObjectBordersOff(sal_uInt16 nIdx) const425 inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const
426 {
427     return bHorz ? nIdx : nIdx + 2;
428 }
429 
430 /*
431     Update Upper Left edge.
432     Items are translated into the representation of the ruler.
433 */
UpdateFrame()434 void SvxRuler::UpdateFrame()
435 {
436     const RulerMarginStyle nMarginStyle =
437         ( mxRulerImpl->aProtectItem->IsSizeProtected() ||
438           mxRulerImpl->aProtectItem->IsPosProtected() ) ?
439         RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
440 
441     if(mxLRSpaceItem && mxPagePosItem)
442     {
443         // if no initialization by default app behavior
444         const tools::Long nOld = lLogicNullOffset;
445         lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft();
446 
447         if(bAppSetNullOffset)
448         {
449             lAppNullOffset += lLogicNullOffset - nOld;
450         }
451 
452         if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
453         {
454             Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset));
455             SetMargin1(0, nMarginStyle);
456             lAppNullOffset = 0;
457         }
458         else
459         {
460             SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle);
461         }
462 
463         tools::Long lRight = 0;
464 
465         // evaluate the table right edge of the table
466         if(mxColumnItem && mxColumnItem->IsTable())
467             lRight = mxColumnItem->GetRight();
468         else
469             lRight = mxLRSpaceItem->GetRight();
470 
471         tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset;
472         tools::Long aWidthPixel = ConvertHPosPixel(aWidth);
473 
474         SetMargin2(aWidthPixel, nMarginStyle);
475     }
476     else if(mxULSpaceItem && mxPagePosItem)
477     {
478         // relative the upper edge of the surrounding frame
479         const tools::Long nOld = lLogicNullOffset;
480         lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper();
481 
482         if(bAppSetNullOffset)
483         {
484             lAppNullOffset += lLogicNullOffset - nOld;
485         }
486 
487         if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
488         {
489             Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset));
490             lAppNullOffset = 0;
491             SetMargin1(0, nMarginStyle);
492         }
493         else
494         {
495             SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle);
496         }
497 
498         tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower();
499         tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset;
500         tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2);
501 
502         SetMargin2(nMargin2Pixel, nMarginStyle);
503     }
504     else
505     {
506         // turns off the view
507         SetMargin1();
508         SetMargin2();
509     }
510 
511     if (mxColumnItem)
512     {
513         mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft()));
514         mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight()));
515     }
516 }
517 
MouseMove(const MouseEvent & rMEvt)518 void SvxRuler::MouseMove( const MouseEvent& rMEvt )
519 {
520     if( bActive )
521     {
522         pBindings->Update( SID_RULER_LR_MIN_MAX );
523         pBindings->Update( SID_ATTR_LONG_ULSPACE );
524         pBindings->Update( SID_ATTR_LONG_LRSPACE );
525         pBindings->Update( SID_RULER_PAGE_POS );
526         pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
527         pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
528         pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
529         pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
530         pBindings->Update( SID_RULER_OBJECT );
531         pBindings->Update( SID_RULER_PROTECT );
532     }
533 
534     Ruler::MouseMove( rMEvt );
535 
536     RulerSelection aSelection = GetHoverSelection();
537 
538     if (aSelection.eType == RulerType::DontKnow)
539     {
540         SetQuickHelpText("");
541         return;
542     }
543 
544     RulerUnitData aUnitData = GetCurrentRulerUnit();
545     double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
546     sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor));
547     OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr);
548 
549     switch (aSelection.eType)
550     {
551         case RulerType::Indent:
552         {
553             if (!mxParaItem)
554                 break;
555 
556             tools::Long nIndex = aSelection.nAryPos + INDENT_GAP;
557 
558             tools::Long nIndentValue = 0.0;
559             if (nIndex == INDENT_LEFT_MARGIN)
560                 nIndentValue = mxParaItem->GetTextLeft();
561             else if (nIndex == INDENT_FIRST_LINE)
562                 nIndentValue = mxParaItem->GetTextFirstLineOffset();
563             else if (nIndex == INDENT_RIGHT_MARGIN)
564                 nIndentValue = mxParaItem->GetRight();
565 
566             double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
567             fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
568 
569             SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
570             break;
571         }
572         case RulerType::Border:
573         {
574             if (mxColumnItem == nullptr)
575                 break;
576 
577             SvxColumnItem& aColumnItem = *mxColumnItem;
578 
579             if (aSelection.nAryPos + 1 >= aColumnItem.Count())
580                 break;
581 
582             double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd,       0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
583             fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces);
584             double fEnd   = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
585             fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces);
586 
587             SetQuickHelpText(
588                 OUString::number(fStart) + " " + sUnit + " - " +
589                 OUString::number(fEnd)   + " " + sUnit );
590             break;
591         }
592         case RulerType::Margin1:
593         {
594             tools::Long nLeft = 0.0;
595             if (mxLRSpaceItem)
596                 nLeft = mxLRSpaceItem->GetLeft();
597             else if (mxULSpaceItem)
598                 nLeft = mxULSpaceItem->GetUpper();
599             else
600                 break;
601 
602             double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
603             fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
604             SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
605 
606             break;
607         }
608         case RulerType::Margin2:
609         {
610             tools::Long nRight = 0.0;
611             if (mxLRSpaceItem)
612                 nRight = mxLRSpaceItem->GetRight();
613             else if (mxULSpaceItem)
614                 nRight = mxULSpaceItem->GetLower();
615             else
616                 break;
617 
618             double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
619             fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
620             SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
621 
622             break;
623         }
624         default:
625         {
626             SetQuickHelpText("");
627             break;
628         }
629     }
630 }
631 
StartListening_Impl()632 void SvxRuler::StartListening_Impl()
633 {
634     if(!bListening)
635     {
636         bValid = false;
637         StartListening(*pBindings);
638         bListening = true;
639     }
640 }
641 
UpdateFrame(const SvxLongLRSpaceItem * pItem)642 void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace
643 {
644     /* Store new value LRSpace; delete old ones if possible */
645     if(bActive)
646     {
647         if(pItem)
648             mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem));
649         else
650             mxLRSpaceItem.reset();
651         StartListening_Impl();
652     }
653 }
654 
UpdateFrameMinMax(const SfxRectangleItem * pItem)655 void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax
656 {
657     /* Set new value for MinMax; delete old ones if possible */
658     if(bActive)
659     {
660         if(pItem)
661             mxMinMaxItem.reset(new SfxRectangleItem(*pItem));
662         else
663             mxMinMaxItem.reset();
664     }
665 }
666 
667 
UpdateFrame(const SvxLongULSpaceItem * pItem)668 void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value
669 {
670     /* Update Right/bottom margin */
671     if(bActive && !bHorz)
672     {
673         if(pItem)
674             mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem));
675         else
676             mxULSpaceItem.reset();
677         StartListening_Impl();
678     }
679 }
680 
Update(const SvxProtectItem * pItem)681 void SvxRuler::Update( const SvxProtectItem* pItem )
682 {
683     if( pItem )
684         mxRulerImpl->aProtectItem.reset(pItem->Clone());
685 }
686 
UpdateTextRTL(const SfxBoolItem * pItem)687 void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem)
688 {
689     if(bActive && bHorz)
690     {
691         mxRulerImpl->pTextRTLItem.reset();
692         if(pItem)
693             mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem));
694         SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue());
695         StartListening_Impl();
696     }
697 }
698 
Update(const SvxColumnItem * pItem,sal_uInt16 nSID)699 void SvxRuler::Update(
700                 const SvxColumnItem *pItem,  // new value
701                 sal_uInt16 nSID) //Slot Id to identify NULL items
702 {
703     /* Set new value for column view */
704     if(!bActive)
705         return;
706 
707     if(pItem)
708     {
709         mxColumnItem.reset(new SvxColumnItem(*pItem));
710         mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL);
711         if(!bHorz && !mxRulerImpl->bIsTableRows)
712             mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL);
713     }
714     else if(mxColumnItem && mxColumnItem->Which() == nSID)
715     //there are two groups of column items table/frame columns and table rows
716     //both can occur in vertical or horizontal mode
717     //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL
718     //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS
719     //if mxColumnItem is already set with one of the ids then a NULL pItem argument
720     //must not delete it
721     {
722         mxColumnItem.reset();
723         mxRulerImpl->bIsTableRows = false;
724     }
725     StartListening_Impl();
726 }
727 
728 
UpdateColumns()729 void SvxRuler::UpdateColumns()
730 {
731     /* Update column view */
732     if(mxColumnItem && mxColumnItem->Count() > 1)
733     {
734         mpBorders.resize(mxColumnItem->Count());
735 
736         RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable;
737 
738         bool bProtectColumns =
739                     mxRulerImpl->aProtectItem->IsSizeProtected() ||
740                     mxRulerImpl->aProtectItem->IsPosProtected();
741 
742         if( !bProtectColumns )
743         {
744             nStyleFlags |= RulerBorderStyle::Moveable;
745             if( !mxColumnItem->IsTable() )
746               nStyleFlags |= RulerBorderStyle::Sizeable;
747         }
748 
749         sal_uInt16 nBorders = mxColumnItem->Count();
750 
751         if(!mxRulerImpl->bIsTableRows)
752             --nBorders;
753 
754         for(sal_uInt16 i = 0; i < nBorders; ++i)
755         {
756             mpBorders[i].nStyle = nStyleFlags;
757             if(!mxColumnItem->At(i).bVisible)
758                 mpBorders[i].nStyle |= RulerBorderStyle::Invisible;
759 
760             mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset);
761 
762             if(mxColumnItem->Count() == i + 1)
763             {
764                 //with table rows the end of the table is contained in the
765                 //column item but it has no width!
766                 mpBorders[i].nWidth = 0;
767             }
768             else
769             {
770                 mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd);
771             }
772             mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset);
773             mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset);
774         }
775         SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
776     }
777     else
778     {
779         SetBorders();
780     }
781 }
782 
UpdateObject()783 void SvxRuler::UpdateObject()
784 {
785     /* Update view of object representation */
786     if (mxObjectItem)
787     {
788         DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer");
789         // !! to the page margin
790         tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
791         mpObjectBorders[0].nPos =
792             ConvertPosPixel(mxObjectItem->GetStartX() -
793                             nMargin + lAppNullOffset);
794         mpObjectBorders[1].nPos =
795             ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset);
796         nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
797         mpObjectBorders[2].nPos =
798             ConvertPosPixel(mxObjectItem->GetStartY() -
799                             nMargin + lAppNullOffset);
800         mpObjectBorders[3].nPos =
801             ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset);
802 
803         const sal_uInt16 nOffset = GetObjectBordersOff(0);
804         SetBorders(2, mpObjectBorders.data() + nOffset);
805     }
806     else
807     {
808         SetBorders();
809     }
810 }
811 
UpdatePara()812 void SvxRuler::UpdatePara()
813 {
814 
815     /*  Update the view for paragraph indents:
816         Left margin, first line indent, right margin paragraph update
817         mpIndents[0] = Buffer for old intent
818         mpIndents[1] = Buffer for old intent
819         mpIndents[INDENT_FIRST_LINE]   = first line indent
820         mpIndents[INDENT_LEFT_MARGIN]  = left margin
821         mpIndents[INDENT_RIGHT_MARGIN] = right margin
822     */
823 
824     // Dependence on PagePosItem
825     if (mxParaItem && mxPagePosItem && !mxObjectItem)
826     {
827         bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
828         // First-line indent is negative to the left paragraph margin
829         tools::Long nLeftFrameMargin = GetLeftFrameMargin();
830         tools::Long nRightFrameMargin = GetRightFrameMargin();
831         SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin));
832         SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin));
833 
834         tools::Long leftMargin;
835         tools::Long leftFirstLine;
836         tools::Long rightMargin;
837 
838         if(bRTLText)
839         {
840             leftMargin    = nRightFrameMargin - mxParaItem->GetTextLeft() + lAppNullOffset;
841             leftFirstLine = leftMargin - mxParaItem->GetTextFirstLineOffset();
842             rightMargin   = nLeftFrameMargin + mxParaItem->GetRight() + lAppNullOffset;
843         }
844         else
845         {
846             leftMargin    = nLeftFrameMargin + mxParaItem->GetTextLeft() + lAppNullOffset;
847             leftFirstLine = leftMargin + mxParaItem->GetTextFirstLineOffset();
848             rightMargin   = nRightFrameMargin - mxParaItem->GetRight() + lAppNullOffset;
849         }
850 
851         mpIndents[INDENT_LEFT_MARGIN].nPos  = ConvertHPosPixel(leftMargin);
852         mpIndents[INDENT_FIRST_LINE].nPos   = ConvertHPosPixel(leftFirstLine);
853         mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin);
854 
855         mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst();
856 
857         SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
858     }
859     else
860     {
861         if(!mpIndents.empty())
862         {
863             mpIndents[INDENT_FIRST_LINE].nPos = 0;
864             mpIndents[INDENT_LEFT_MARGIN].nPos = 0;
865             mpIndents[INDENT_RIGHT_MARGIN].nPos = 0;
866         }
867         SetIndents(); // turn off
868     }
869 }
870 
UpdatePara(const SvxLRSpaceItem * pItem)871 void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents
872 {
873     /* Store new value of paragraph indents */
874     if(bActive)
875     {
876         if(pItem)
877             mxParaItem.reset(new SvxLRSpaceItem(*pItem));
878         else
879             mxParaItem.reset();
880         StartListening_Impl();
881     }
882 }
883 
UpdateParaBorder()884 void SvxRuler::UpdateParaBorder()
885 {
886     /* Border distance */
887     if(bActive)
888     {
889         StartListening_Impl();
890     }
891 }
892 
UpdatePage()893 void SvxRuler::UpdatePage()
894 {
895     /* Update view of position and width of page */
896     if (mxPagePosItem)
897     {
898         // all objects are automatically adjusted
899         if(bHorz)
900         {
901             SetPagePos(
902                 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(),
903                 pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)).
904                 Width());
905         }
906         else
907         {
908             SetPagePos(
909                 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(),
910                 pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())).
911                 Height());
912         }
913         if(bAppSetNullOffset)
914             SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset));
915     }
916     else
917     {
918         SetPagePos();
919     }
920 
921     tools::Long lPos = 0;
922     Point aOwnPos = GetPosPixel();
923     Point aEdtWinPos = pEditWin->GetPosPixel();
924     if( AllSettings::GetLayoutRTL() && bHorz )
925     {
926         //#i73321# in RTL the window and the ruler is not mirrored but the
927         // influence of the vertical ruler is inverted
928         Size aOwnSize = GetSizePixel();
929         Size aEdtWinSize = pEditWin->GetSizePixel();
930         lPos = aOwnSize.Width() - aEdtWinSize.Width();
931         lPos -= (aEdtWinPos - aOwnPos).X();
932     }
933     else
934     {
935         Point aPos(aEdtWinPos - aOwnPos);
936         lPos = bHorz ? aPos.X() : aPos.Y();
937     }
938 
939     // Unfortunately, we get the offset of the edit window to the ruler never
940     // through a status message. So we set it ourselves if necessary.
941     if(lPos != mxRulerImpl->lOldWinPos)
942     {
943         mxRulerImpl->lOldWinPos=lPos;
944         SetWinPos(lPos);
945     }
946 }
947 
Update(const SvxPagePosSizeItem * pItem)948 void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes
949 {
950     /* Store new value of page attributes */
951     if(bActive)
952     {
953         if(pItem)
954             mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem));
955         else
956             mxPagePosItem.reset();
957         StartListening_Impl();
958     }
959 }
960 
SetDefTabDist(tools::Long inDefTabDist)961 void SvxRuler::SetDefTabDist(tools::Long inDefTabDist)  // New distance for DefaultTabs in App-Metrics
962 {
963     if (lAppNullOffset == LONG_MAX)
964         UpdateFrame(); // hack: try to get lAppNullOffset initialized
965     /* New distance is set for DefaultTabs */
966     lDefTabDist = inDefTabDist;
967     UpdateTabs();
968 }
969 
ToSvTab_Impl(SvxTabAdjust eAdj)970 static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj)
971 {
972     /* Internal conversion routine between SV-Tab.-Enum and Svx */
973     switch(eAdj) {
974         case SvxTabAdjust::Left:    return RULER_TAB_LEFT;
975         case SvxTabAdjust::Right:   return RULER_TAB_RIGHT;
976         case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL;
977         case SvxTabAdjust::Center:  return RULER_TAB_CENTER;
978         case SvxTabAdjust::Default: return RULER_TAB_DEFAULT;
979         default: ; //prevent warning
980     }
981     return 0;
982 }
983 
ToAttrTab_Impl(sal_uInt16 eAdj)984 static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj)
985 {
986     switch(eAdj) {
987         case RULER_TAB_LEFT:    return SvxTabAdjust::Left    ;
988         case RULER_TAB_RIGHT:   return SvxTabAdjust::Right   ;
989         case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ;
990         case RULER_TAB_CENTER:  return SvxTabAdjust::Center  ;
991         case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ;
992     }
993     return SvxTabAdjust::Left;
994 }
995 
UpdateTabs()996 void SvxRuler::UpdateTabs()
997 {
998     if(IsDrag())
999         return;
1000 
1001     if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem)
1002     {
1003         // buffer for DefaultTabStop
1004         // Distance last Tab <-> Right paragraph margin / DefaultTabDist
1005         bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1006 
1007         const tools::Long nLeftFrameMargin = GetLeftFrameMargin();
1008         const tools::Long nRightFrameMargin = GetRightFrameMargin();
1009 
1010         //#i24363# tab stops relative to indent
1011         const tools::Long nParaItemTxtLeft = mxParaItem->GetTextLeft();
1012 
1013         const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft;
1014         const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft;
1015 
1016         const tools::Long lLastTab = mxTabStopItem->Count()
1017                                 ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos())
1018                                 : 0;
1019         const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab;
1020         const tools::Long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight());
1021 
1022         tools::Long nDefTabDist = ConvertHPosPixel(lDefTabDist);
1023 
1024         if( !nDefTabDist )
1025             nDefTabDist = 1;
1026 
1027         const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent
1028                     ? 0
1029                     : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist );
1030 
1031         if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize)
1032         {
1033             // 10 (GAP) in stock
1034             nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP;
1035             mpTabs.resize(nTabBufSize);
1036         }
1037 
1038         nTabCount = 0;
1039         sal_uInt16 j;
1040 
1041         const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent);
1042 
1043         tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin)
1044             + lAppNullOffset;
1045         if (bRTL)
1046         {
1047             lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic;
1048         }
1049         tools::Long lLastTabOffsetLogic = 0;
1050         for(j = 0; j < mxTabStopItem->Count(); ++j)
1051         {
1052             const SvxTabStop* pTab = &mxTabStopItem->At(j);
1053             lLastTabOffsetLogic = pTab->GetTabPos();
1054             tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic);
1055             mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos);
1056             mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment());
1057             ++nTabCount;
1058         }
1059 
1060         // Adjust to previous-to-first default tab stop
1061         lLastTabOffsetLogic -= lLastTabOffsetLogic % lDefTabDist;
1062 
1063         // fill the rest with default Tabs
1064         for (j = 0; j < nDefTabBuf; ++j)
1065         {
1066             //simply add the default distance to the last position
1067             lLastTabOffsetLogic += lDefTabDist;
1068             if (bRTL)
1069             {
1070                 mpTabs[nTabCount + TAB_GAP].nPos =
1071                     ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic);
1072                 if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix)
1073                     break;
1074             }
1075             else
1076             {
1077                 mpTabs[nTabCount + TAB_GAP].nPos =
1078                     ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic);
1079                 if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent)
1080                     break;
1081             }
1082 
1083             mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT;
1084             ++nTabCount;
1085         }
1086         SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1087         DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small");
1088     }
1089     else
1090     {
1091         SetTabs();
1092     }
1093 }
1094 
Update(const SvxTabStopItem * pItem)1095 void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs
1096 {
1097     /* Store new value for tabs; delete old ones if possible */
1098     if(!bActive)
1099         return;
1100 
1101     if(pItem)
1102     {
1103         mxTabStopItem.reset(new SvxTabStopItem(*pItem));
1104         if(!bHorz)
1105             mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL);
1106     }
1107     else
1108     {
1109         mxTabStopItem.reset();
1110     }
1111     StartListening_Impl();
1112 }
1113 
Update(const SvxObjectItem * pItem)1114 void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects
1115 {
1116     /* Store new value for objects */
1117     if(bActive)
1118     {
1119         if(pItem)
1120             mxObjectItem.reset(new SvxObjectItem(*pItem));
1121         else
1122             mxObjectItem.reset();
1123         StartListening_Impl();
1124     }
1125 }
1126 
SetNullOffsetLogic(tools::Long lVal)1127 void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets
1128 {
1129     lAppNullOffset = lLogicNullOffset - lVal;
1130     bAppSetNullOffset = true;
1131     Ruler::SetNullOffset(ConvertSizePixel(lVal));
1132     Update();
1133 }
1134 
Update()1135 void SvxRuler::Update()
1136 {
1137     /* Perform update of view */
1138     if(IsDrag())
1139         return;
1140 
1141     UpdatePage();
1142     UpdateFrame();
1143     if(nFlags & SvxRulerSupportFlags::OBJECT)
1144         UpdateObject();
1145     else
1146         UpdateColumns();
1147 
1148     if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
1149       UpdatePara();
1150 
1151     if(nFlags & SvxRulerSupportFlags::TABS)
1152       UpdateTabs();
1153 }
1154 
GetPageWidth() const1155 tools::Long SvxRuler::GetPageWidth() const
1156 {
1157     if (!mxPagePosItem)
1158         return 0;
1159     return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
1160 }
1161 
GetFrameLeft() const1162 inline tools::Long SvxRuler::GetFrameLeft() const
1163 {
1164     /* Get Left margin in Pixels */
1165     return  bAppSetNullOffset ?
1166             GetMargin1() + ConvertSizePixel(lLogicNullOffset) :
1167             Ruler::GetNullOffset();
1168 }
1169 
GetFirstLineIndent() const1170 tools::Long SvxRuler::GetFirstLineIndent() const
1171 {
1172     /* Get First-line indent in pixels */
1173     return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1();
1174 }
1175 
GetLeftIndent() const1176 tools::Long SvxRuler::GetLeftIndent() const
1177 {
1178     /* Get Left paragraph margin in Pixels */
1179     return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1();
1180 }
1181 
GetRightIndent() const1182 tools::Long SvxRuler::GetRightIndent() const
1183 {
1184     /* Get Right paragraph margin in Pixels */
1185     return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2();
1186 }
1187 
GetLogicRightIndent() const1188 tools::Long SvxRuler::GetLogicRightIndent() const
1189 {
1190     /* Get Right paragraph margin in Logic */
1191     return mxParaItem ? GetRightFrameMargin() - mxParaItem->GetRight() : GetRightFrameMargin();
1192 }
1193 
1194 // Left margin in App values, is either the margin (= 0)  or the left edge of
1195 // the column that is set in the column attribute as current column.
GetLeftFrameMargin() const1196 tools::Long SvxRuler::GetLeftFrameMargin() const
1197 {
1198     // #126721# for some unknown reason the current column is set to 0xffff
1199     DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(),
1200                "issue #126721# - invalid current column!");
1201     tools::Long nLeft = 0;
1202     if (mxColumnItem &&
1203         mxColumnItem->Count() &&
1204         mxColumnItem->IsConsistent())
1205     {
1206         nLeft = mxColumnItem->GetActiveColumnDescription().nStart;
1207     }
1208 
1209     return nLeft;
1210 }
1211 
GetLeftMin() const1212 inline tools::Long SvxRuler::GetLeftMin() const
1213 {
1214     DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1215     if (mxMinMaxItem)
1216     {
1217         if (bHorz)
1218             return mxMinMaxItem->GetValue().Left();
1219         else
1220             return mxMinMaxItem->GetValue().Top();
1221     }
1222     return 0;
1223 }
1224 
GetRightMax() const1225 inline tools::Long SvxRuler::GetRightMax() const
1226 {
1227     DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1228     if (mxMinMaxItem)
1229     {
1230         if (bHorz)
1231             return mxMinMaxItem->GetValue().Right();
1232         else
1233             return mxMinMaxItem->GetValue().Bottom();
1234     }
1235     return 0;
1236 }
1237 
1238 
GetRightFrameMargin() const1239 tools::Long SvxRuler::GetRightFrameMargin() const
1240 {
1241     /* Get right frame margin (in logical units) */
1242     if (mxColumnItem)
1243     {
1244         if (!IsActLastColumn(true))
1245         {
1246             return mxColumnItem->At(GetActRightColumn(true)).nEnd;
1247         }
1248     }
1249 
1250     tools::Long lResult = lLogicNullOffset;
1251 
1252     // If possible deduct right table entry
1253     if(mxColumnItem && mxColumnItem->IsTable())
1254         lResult += mxColumnItem->GetRight();
1255     else if(bHorz && mxLRSpaceItem)
1256         lResult += mxLRSpaceItem->GetRight();
1257     else if(!bHorz && mxULSpaceItem)
1258         lResult += mxULSpaceItem->GetLower();
1259 
1260     if(bHorz)
1261         lResult = mxPagePosItem->GetWidth() - lResult;
1262     else
1263         lResult = mxPagePosItem->GetHeight() - lResult;
1264 
1265     return lResult;
1266 }
1267 
1268 #define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \
1269                    SvxRulerSupportFlags::NEGATIVE_MARGINS )
1270 #define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() )
1271 
GetCorrectedDragPos(bool bLeft,bool bRight)1272 tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight )
1273 {
1274     /*
1275         Corrects the position within the calculated limits. The limit values are in
1276         pixels relative to the page edge.
1277     */
1278 
1279     const tools::Long lNullPix = Ruler::GetNullOffset();
1280     tools::Long lDragPos = GetDragPos() + lNullPix;
1281     bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows;
1282     if((bLeft || bHoriRows) && lDragPos < nMaxLeft)
1283         lDragPos = nMaxLeft;
1284     else if((bRight||bHoriRows) && lDragPos > nMaxRight)
1285         lDragPos = nMaxRight;
1286     return lDragPos - lNullPix;
1287 }
1288 
ModifyTabs_Impl(sal_uInt16 nCount,RulerTab * pTabs,tools::Long lDiff)1289 static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs
1290                       RulerTab* pTabs,   // Tab buffer
1291                       tools::Long lDiff)        // difference to be added
1292 {
1293     /* Helper function, move all the tabs by a fixed value */
1294     if( pTabs )
1295     {
1296         for(sal_uInt16 i = 0; i < nCount; ++i)
1297         {
1298             pTabs[i].nPos += lDiff;
1299         }
1300     }
1301 }
1302 
DragMargin1()1303 void SvxRuler::DragMargin1()
1304 {
1305     /* Dragging the left edge of frame */
1306     tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG );
1307 
1308     aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false);
1309 
1310     // Check if position changed
1311     if (aDragPosition == 0)
1312         return;
1313 
1314     DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz);
1315     if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1316         DragBorders();
1317     AdjustMargin1(aDragPosition);
1318 }
1319 
AdjustMargin1(tools::Long lInputDiff)1320 void SvxRuler::AdjustMargin1(tools::Long lInputDiff)
1321 {
1322     const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset();
1323     const tools::Long lDragPos = lInputDiff;
1324 
1325     bool bProtectColumns =
1326         mxRulerImpl->aProtectItem->IsSizeProtected() ||
1327         mxRulerImpl->aProtectItem->IsPosProtected();
1328 
1329     const RulerMarginStyle nMarginStyle =
1330         bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1331 
1332     if(!bAppSetNullOffset)
1333     {
1334         tools::Long lDiff = lDragPos;
1335         SetNullOffset(nOld + lDiff);
1336         if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
1337         {
1338             SetMargin2( GetMargin2() - lDiff, nMarginStyle );
1339 
1340             if (!mxColumnItem && !mxObjectItem && mxParaItem)
1341             {
1342                 // Right indent of the old position
1343                 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1344                 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1345             }
1346             if (mxObjectItem)
1347             {
1348                 mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff;
1349                 mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff;
1350                 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1351             }
1352             if (mxColumnItem)
1353             {
1354                 for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i)
1355                     mpBorders[i].nPos -= lDiff;
1356                 SetBorders(mxColumnItem->Count()-1, mpBorders.data());
1357                 if(mxColumnItem->IsFirstAct())
1358                 {
1359                     // Right indent of the old position
1360                     if (mxParaItem)
1361                     {
1362                         mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1363                         SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1364                     }
1365                 }
1366                 else
1367                 {
1368                     if (mxParaItem)
1369                     {
1370                         mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1371                         mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff;
1372                         mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1373                         SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1374                     }
1375                 }
1376                 if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1377                    &&!IsActFirstColumn())
1378                 {
1379                     ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff);
1380                     SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1381                 }
1382             }
1383         }
1384     }
1385     else
1386     {
1387         tools::Long lDiff = lDragPos - nOld;
1388         SetMargin1(nOld + lDiff, nMarginStyle);
1389 
1390         if (!mxColumnItem
1391             || !(nDragType
1392                  & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR
1393                     | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
1394         {
1395             if (!mxColumnItem && !mxObjectItem && mxParaItem)
1396             {
1397                 // Left indent of the old position
1398                 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1399                 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1400                 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1401             }
1402 
1403             if (mxColumnItem)
1404             {
1405                 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
1406                     mpBorders[i].nPos += lDiff;
1407                 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1408                 if (mxColumnItem->IsFirstAct())
1409                 {
1410                     // Left indent of the old position
1411                     if (mxParaItem)
1412                     {
1413                         mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1414                         mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1415                         SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1416                     }
1417                 }
1418                 else
1419                 {
1420                     if (mxParaItem)
1421                     {
1422                         mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1423                         mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1424                         mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff;
1425                         SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1426                     }
1427                 }
1428             }
1429             if (mxTabStopItem)
1430             {
1431                 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff);
1432                 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1433             }
1434         }
1435     }
1436 }
1437 
DragMargin2()1438 void SvxRuler::DragMargin2()
1439 {
1440     /* Dragging the right edge of frame */
1441     tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG);
1442     aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false);
1443     tools::Long lDiff = aDragPosition - GetMargin2();
1444 
1445     // Check if position changed
1446     if (lDiff == 0)
1447         return;
1448 
1449     if( mxRulerImpl->bIsTableRows &&
1450         !bHorz &&
1451         mxColumnItem &&
1452         (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1453     {
1454         DragBorders();
1455     }
1456 
1457     bool bProtectColumns =
1458         mxRulerImpl->aProtectItem->IsSizeProtected() ||
1459         mxRulerImpl->aProtectItem->IsPosProtected();
1460 
1461     const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1462 
1463     SetMargin2( aDragPosition, nMarginStyle );
1464 
1465     // Right indent of the old position
1466     if ((!mxColumnItem || IsActLastColumn()) && mxParaItem)
1467     {
1468         mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1469         SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1470     }
1471 
1472     DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz);
1473 }
1474 
DragIndents()1475 void SvxRuler::DragIndents()
1476 {
1477     /* Dragging the paragraph indents */
1478     tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos();
1479     const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP;
1480 
1481     bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1482 
1483     if(nIndex == INDENT_RIGHT_MARGIN)
1484         aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin());
1485     else
1486         aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
1487 
1488     const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition;
1489 
1490     // Check if position changed
1491     if (lDiff == 0)
1492         return;
1493 
1494     if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN )  &&
1495         !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
1496     {
1497         mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1498     }
1499 
1500     mpIndents[nIndex].nPos = aDragPosition;
1501 
1502     SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1503     DrawLine_Impl(lTabPos, 1, bHorz);
1504 }
1505 
DrawLine_Impl(tools::Long & lTabPosition,int nNew,bool bHorizontal)1506 void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal)
1507 {
1508     /*
1509        Output routine for the ledger line when moving tabs, tables and other
1510        columns
1511     */
1512     if(bHorizontal)
1513     {
1514         const tools::Long nHeight = pEditWin->GetOutDev()->GetOutputSize().Height();
1515         Point aZero = pEditWin->GetMapMode().GetOrigin();
1516         if(lTabPosition != -1)
1517         {
1518             pEditWin->InvertTracking(
1519                 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1520                            Point(lTabPosition, -aZero.Y() + nHeight)),
1521                 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1522         }
1523         if( nNew & 1 )
1524         {
1525             tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 );
1526             nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1527             lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() );
1528             if (mxPagePosItem)
1529                 lTabPosition += mxPagePosItem->GetPos().X();
1530             pEditWin->InvertTracking(
1531                 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1532                            Point(lTabPosition, -aZero.Y() + nHeight) ),
1533                 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1534         }
1535     }
1536     else
1537     {
1538         const tools::Long nWidth = pEditWin->GetOutDev()->GetOutputSize().Width();
1539         Point aZero = pEditWin->GetMapMode().GetOrigin();
1540         if(lTabPosition != -1)
1541         {
1542             pEditWin->InvertTracking(
1543                 tools::Rectangle( Point(-aZero.X(),          lTabPosition),
1544                            Point(-aZero.X() + nWidth, lTabPosition)),
1545                 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1546         }
1547 
1548         if(nNew & 1)
1549         {
1550             tools::Long nDrapPosition = GetCorrectedDragPos();
1551             nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1552             lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset());
1553             if (mxPagePosItem)
1554                 lTabPosition += mxPagePosItem->GetPos().Y();
1555             pEditWin->InvertTracking(
1556                 tools::Rectangle( Point(-aZero.X(),        lTabPosition),
1557                            Point(-aZero.X()+nWidth, lTabPosition)),
1558                 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1559         }
1560     }
1561 }
1562 
DragTabs()1563 void SvxRuler::DragTabs()
1564 {
1565     /* Dragging of Tabs */
1566     tools::Long aDragPosition = GetCorrectedDragPos(true, false);
1567     aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin());
1568 
1569     sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP;
1570     tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos;
1571     if (nDiff == 0)
1572         return;
1573 
1574     DrawLine_Impl(lTabPos, 7, bHorz);
1575 
1576     if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1577     {
1578 
1579         for(sal_uInt16 i = nIdx; i < nTabCount; ++i)
1580         {
1581             mpTabs[i].nPos += nDiff;
1582             // limit on maximum
1583             if(mpTabs[i].nPos > GetMargin2())
1584                 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1585             else
1586                 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1587         }
1588     }
1589     else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1590     {
1591         mxRulerImpl->nTotalDist -= nDiff;
1592         mpTabs[nIdx].nPos = aDragPosition;
1593         for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
1594         {
1595             if(mpTabs[i].nStyle & RULER_TAB_DEFAULT)
1596                 // can be canceled at the DefaultTabs
1597                 break;
1598             tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i];
1599             nDelta /= 1000;
1600             mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta;
1601             if(mpTabs[i].nPos + GetNullOffset() > nMaxRight)
1602                 mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE;
1603             else
1604                 mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE;
1605         }
1606     }
1607     else
1608     {
1609         mpTabs[nIdx].nPos = aDragPosition;
1610     }
1611 
1612     if(IsDragDelete())
1613         mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1614     else
1615         mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1616     SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1617 }
1618 
SetActive(bool bOn)1619 void SvxRuler::SetActive(bool bOn)
1620 {
1621     if(bOn)
1622     {
1623         Activate();
1624     }
1625     else
1626         Deactivate();
1627     if(bActive!=bOn)
1628     {
1629         pBindings->EnterRegistrations();
1630         if(bOn)
1631             for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++)
1632                 pCtrlItems[i]->ReBind();
1633         else
1634             for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++)
1635                 pCtrlItems[j]->UnBind();
1636         pBindings->LeaveRegistrations();
1637     }
1638     bActive = bOn;
1639 }
1640 
UpdateParaContents_Impl(tools::Long lDifference,UpdateType eType)1641 void SvxRuler::UpdateParaContents_Impl(
1642                             tools::Long lDifference,
1643                             UpdateType eType)  // Art (all, left or right)
1644 {
1645     /* Helper function; carry Tabs and Paragraph Margins */
1646     switch(eType)
1647     {
1648         case UpdateType::MoveRight:
1649             mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference;
1650             break;
1651         case UpdateType::MoveLeft:
1652         {
1653             mpIndents[INDENT_FIRST_LINE].nPos += lDifference;
1654             mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference;
1655             if (!mpTabs.empty())
1656             {
1657                 for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i)
1658                 {
1659                     mpTabs[i].nPos += lDifference;
1660                 }
1661                 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1662             }
1663             break;
1664         }
1665     }
1666     SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1667 }
1668 
DragBorders()1669 void SvxRuler::DragBorders()
1670 {
1671     /* Dragging of Borders (Tables and other columns) */
1672     bool bLeftIndentsCorrected  = false;
1673     bool bRightIndentsCorrected = false;
1674     int nIndex;
1675 
1676     if(GetDragType() == RulerType::Border)
1677     {
1678         DrawLine_Impl(lTabPos, 7, bHorz);
1679         nIndex = GetDragAryPos();
1680     }
1681     else
1682     {
1683         nIndex = 0;
1684     }
1685 
1686     RulerDragSize nDragSize = GetDragSize();
1687     tools::Long lDiff = 0;
1688 
1689     // the drag position has to be corrected to be able to prevent borders from passing each other
1690     tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1691 
1692     switch(nDragSize)
1693     {
1694         case RulerDragSize::Move:
1695         {
1696             if(GetDragType() == RulerType::Border)
1697                 lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos;
1698             else
1699                 lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin;
1700 
1701             if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1702             {
1703                 tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters
1704                 for(int i = mpBorders.size() - 2; i >= nIndex; --i)
1705                 {
1706                     tools::Long l = mpBorders[i].nPos;
1707                     mpBorders[i].nPos += lDiff;
1708                     mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth);
1709                     nRight = mpBorders[i].nPos - glMinFrame;
1710                     // RR update the column
1711                     if(i == GetActRightColumn())
1712                     {
1713                         UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1714                         bRightIndentsCorrected = true;
1715                     }
1716                     // LAR, EZE update the column
1717                     else if(i == GetActLeftColumn())
1718                     {
1719                         UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1720                         bLeftIndentsCorrected = true;
1721                     }
1722                 }
1723             }
1724             else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1725             {
1726                 int nLimit;
1727                 tools::Long lLeft;
1728                 int nStartLimit = mpBorders.size() - 2;
1729                 switch(GetDragType())
1730                 {
1731                 default: ;//prevent warning
1732                     OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" );
1733                     [[fallthrough]];
1734                 case RulerType::Border:
1735                     if(mxRulerImpl->bIsTableRows)
1736                     {
1737                         mpBorders[nIndex].nPos += lDiff;
1738                         if(bHorz)
1739                         {
1740                             lLeft = mpBorders[nIndex].nPos;
1741                             mxRulerImpl->nTotalDist -= lDiff;
1742                             nLimit = nIndex + 1;
1743                         }
1744                         else
1745                         {
1746                             lLeft = 0;
1747                             nStartLimit = nIndex - 1;
1748                             mxRulerImpl->nTotalDist += lDiff;
1749                             nLimit = 0;
1750                         }
1751                     }
1752                     else
1753                     {
1754                         nLimit = nIndex + 1;
1755                         mpBorders[nIndex].nPos += lDiff;
1756                         lLeft = mpBorders[nIndex].nPos;
1757                         mxRulerImpl->nTotalDist -= lDiff;
1758                     }
1759                 break;
1760                 case RulerType::Margin1:
1761                     nLimit = 0;
1762                     lLeft = mxRulerImpl->lLastLMargin + lDiff;
1763                     mxRulerImpl->nTotalDist -= lDiff;
1764                 break;
1765                 case RulerType::Margin2:
1766                     nLimit = 0;
1767                     lLeft= 0;
1768                     nStartLimit = mpBorders.size() - 2;
1769                     mxRulerImpl->nTotalDist += lDiff;
1770                 break;
1771                 }
1772 
1773                 for(int i  = nStartLimit; i >= nLimit; --i)
1774                 {
1775 
1776                     tools::Long l = mpBorders[i].nPos;
1777                     mpBorders[i].nPos =
1778                         lLeft +
1779                         (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 +
1780                         mxRulerImpl->pBlockBuf[i];
1781 
1782                     // RR update the column
1783                     if(!mxRulerImpl->bIsTableRows)
1784                     {
1785                         if(i == GetActRightColumn())
1786                         {
1787                             UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1788                             bRightIndentsCorrected = true;
1789                         }
1790                         // LAR, EZE update the column
1791                         else if(i == GetActLeftColumn())
1792                         {
1793                             UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1794                             bLeftIndentsCorrected = true;
1795                         }
1796                     }
1797                 }
1798                 if(mxRulerImpl->bIsTableRows)
1799                 {
1800                     //in vertical tables the left borders have to be moved
1801                     if(bHorz)
1802                     {
1803                         for(int i  = 0; i < nIndex; ++i)
1804                             mpBorders[i].nPos += lDiff;
1805                         AdjustMargin1(lDiff);
1806                     }
1807                     else
1808                     {
1809                         //otherwise the right borders are moved
1810                         for(int i  = mxColumnItem->Count() - 1; i > nIndex; --i)
1811                             mpBorders[i].nPos += lDiff;
1812                         SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1813                     }
1814                 }
1815             }
1816             else if(mxRulerImpl->bIsTableRows)
1817             {
1818                 //moving rows: if a row is resized all following rows
1819                 //have to be moved by the same amount.
1820                 //This includes the left border when the table is not limited
1821                 //to a lower frame border.
1822                 int nLimit;
1823                 if(GetDragType()==RulerType::Border)
1824                 {
1825                     nLimit = nIndex + 1;
1826                     mpBorders[nIndex].nPos += lDiff;
1827                 }
1828                 else
1829                 {
1830                     nLimit=0;
1831                 }
1832                 //in vertical tables the left borders have to be moved
1833                 if(bHorz)
1834                 {
1835                     for(int i  = 0; i < nIndex; ++i)
1836                     {
1837                         mpBorders[i].nPos += lDiff;
1838                     }
1839                     AdjustMargin1(lDiff);
1840                 }
1841                 else
1842                 {
1843                     //otherwise the right borders are moved
1844                     for(int i  = mpBorders.size() - 2; i >= nLimit; --i)
1845                     {
1846                         mpBorders[i].nPos += lDiff;
1847                     }
1848                     SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1849                 }
1850             }
1851             else
1852                 mpBorders[nIndex].nPos += lDiff;
1853             break;
1854         }
1855       case RulerDragSize::N1:
1856         {
1857             lDiff = lPos - mpBorders[nIndex].nPos;
1858             mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos;
1859             mpBorders[nIndex].nPos = lPos;
1860             break;
1861         }
1862       case RulerDragSize::N2:
1863         {
1864             const tools::Long nOld = mpBorders[nIndex].nWidth;
1865             mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos;
1866             lDiff = mpBorders[nIndex].nWidth - nOld;
1867             break;
1868         }
1869     }
1870     if(!bRightIndentsCorrected &&
1871        GetActRightColumn() == nIndex &&
1872        nDragSize != RulerDragSize::N2 &&
1873        !mpIndents.empty() &&
1874        !mxRulerImpl->bIsTableRows)
1875     {
1876         UpdateParaContents_Impl(lDiff, UpdateType::MoveRight);
1877     }
1878     else if(!bLeftIndentsCorrected &&
1879             GetActLeftColumn() == nIndex &&
1880             nDragSize != RulerDragSize::N1 &&
1881             !mpIndents.empty())
1882     {
1883         UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft);
1884     }
1885     SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1886 }
1887 
DragObjectBorder()1888 void SvxRuler::DragObjectBorder()
1889 {
1890     /* Dragging of object edges */
1891     if(RulerDragSize::Move == GetDragSize())
1892     {
1893         const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1894 
1895         const sal_uInt16 nIdx = GetDragAryPos();
1896         mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition;
1897         SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1898         DrawLine_Impl(lTabPos, 7, bHorz);
1899 
1900     }
1901 }
1902 
ApplyMargins()1903 void SvxRuler::ApplyMargins()
1904 {
1905     /* Applying margins; changed by dragging. */
1906     const SfxPoolItem* pItem = nullptr;
1907     sal_uInt16 nId = SID_ATTR_LONG_LRSPACE;
1908 
1909     if(bHorz)
1910     {
1911         const tools::Long lOldNull = lLogicNullOffset;
1912         if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset())
1913         {
1914             lLogicNullOffset = mxRulerImpl->lMaxLeftLogic;
1915             mxLRSpaceItem->SetLeft(lLogicNullOffset);
1916         }
1917         else
1918         {
1919             lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset;
1920             mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft()));
1921         }
1922 
1923         if(bAppSetNullOffset)
1924         {
1925             lAppNullOffset += lLogicNullOffset - lOldNull;
1926         }
1927 
1928         tools::Long nRight;
1929         if(mxRulerImpl->lMaxRightLogic != -1
1930            && nMaxRight == GetMargin2() + Ruler::GetNullOffset())
1931         {
1932             nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic;
1933         }
1934         else
1935         {
1936             nRight = std::max(tools::Long(0),
1937                             mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() -
1938                                 (ConvertHPosLogic(GetMargin2()) - lAppNullOffset));
1939 
1940             nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight());
1941         }
1942         mxLRSpaceItem->SetRight(nRight);
1943 
1944         pItem = mxLRSpaceItem.get();
1945 
1946 #ifdef DEBUGLIN
1947         Debug_Impl(pEditWin, *mxLRSpaceItem);
1948 #endif // DEBUGLIN
1949 
1950     }
1951     else
1952     {
1953         const tools::Long lOldNull = lLogicNullOffset;
1954         lLogicNullOffset =
1955                 ConvertVPosLogic(GetFrameLeft()) -
1956                 lAppNullOffset;
1957         mxULSpaceItem->SetUpper(
1958             PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper()));
1959         if(bAppSetNullOffset)
1960         {
1961             lAppNullOffset += lLogicNullOffset - lOldNull;
1962         }
1963         mxULSpaceItem->SetLower(
1964             PixelVAdjust(
1965                 std::max(tools::Long(0), mxPagePosItem->GetHeight() -
1966                     mxULSpaceItem->GetUpper() -
1967                     (ConvertVPosLogic(GetMargin2()) -
1968                      lAppNullOffset)), mxULSpaceItem->GetLower()));
1969         pItem = mxULSpaceItem.get();
1970         nId = SID_ATTR_LONG_ULSPACE;
1971 
1972 #ifdef DEBUGLIN
1973         Debug_Impl(pEditWin,*mxULSpaceItem);
1974 #endif // DEBUGLIN
1975 
1976     }
1977     pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem });
1978     if (mxTabStopItem)
1979         UpdateTabs();
1980 }
1981 
RoundToCurrentMapMode(tools::Long lValue) const1982 tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const
1983 {
1984     RulerUnitData aUnitData = GetCurrentRulerUnit();
1985     double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
1986 
1987     tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
1988     lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit;
1989     return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width();
1990 }
1991 
ApplyIndents()1992 void SvxRuler::ApplyIndents()
1993 {
1994     /* Applying paragraph settings; changed by dragging. */
1995 
1996     tools::Long nLeftFrameMargin  = GetLeftFrameMargin();
1997 
1998     bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1999 
2000     tools::Long nNewTxtLeft;
2001     tools::Long nNewFirstLineOffset;
2002     tools::Long nNewRight;
2003 
2004     tools::Long nFirstLine    = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos);
2005     tools::Long nLeftMargin   = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos);
2006     tools::Long nRightMargin  = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos);
2007 
2008     if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true))))
2009     {
2010         if(bRTL)
2011         {
2012             tools::Long nRightColumn  = GetActRightColumn(true);
2013             tools::Long nRightBorder  = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2014             nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2015         }
2016         else
2017         {
2018             tools::Long nLeftColumn = GetActLeftColumn(true);
2019             tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2020             nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset;
2021         }
2022     }
2023     else
2024     {
2025         if(bRTL)
2026         {
2027             tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2028             nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2029         }
2030         else
2031         {
2032             tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2033             nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset;
2034         }
2035     }
2036 
2037     if(bRTL)
2038         nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset;
2039     else
2040         nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset;
2041 
2042     if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true))))
2043     {
2044         if(bRTL)
2045         {
2046             tools::Long nLeftColumn = GetActLeftColumn(true);
2047             tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2048             nNewRight = nRightMargin - nLeftBorder - lAppNullOffset;
2049         }
2050         else
2051         {
2052             tools::Long nRightColumn  = GetActRightColumn(true);
2053             tools::Long nRightBorder  = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2054             nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2055         }
2056     }
2057     else
2058     {
2059         if(bRTL)
2060         {
2061             tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2062             nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset;
2063         }
2064         else
2065         {
2066             tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2067             nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2068         }
2069     }
2070 
2071     if (mbSnapping)
2072     {
2073         nNewTxtLeft         = RoundToCurrentMapMode(nNewTxtLeft);
2074         nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset);
2075         nNewRight           = RoundToCurrentMapMode(nNewRight);
2076     }
2077 
2078     mxParaItem->SetTextFirstLineOffset(sal::static_int_cast<short>(nNewFirstLineOffset));
2079     mxParaItem->SetTextLeft(nNewTxtLeft);
2080     mxParaItem->SetRight(nNewRight);
2081 
2082     sal_uInt16 nParagraphId  = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL;
2083     pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD,
2084             { mxParaItem.get() });
2085     UpdateTabs();
2086 }
2087 
ApplyTabs()2088 void SvxRuler::ApplyTabs()
2089 {
2090     /* Apply tab settings, changed by dragging. */
2091     bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2092     const sal_uInt16 nCoreIdx = GetDragAryPos();
2093     if(IsDragDelete())
2094     {
2095         mxTabStopItem->Remove(nCoreIdx);
2096     }
2097     else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType ||
2098             SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType)
2099     {
2100         SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which());
2101         //remove default tab stops
2102         for ( sal_uInt16 i = 0; i < pItem->Count(); )
2103         {
2104             if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() )
2105             {
2106                 pItem->Remove(i);
2107                 continue;
2108             }
2109             ++i;
2110         }
2111 
2112         sal_uInt16 j;
2113         for(j = 0; j < nCoreIdx; ++j)
2114         {
2115             pItem->Insert(mxTabStopItem->At(j));
2116         }
2117         for(; j < mxTabStopItem->Count(); ++j)
2118         {
2119             SvxTabStop aTabStop = mxTabStopItem->At(j);
2120             aTabStop.GetTabPos() = PixelHAdjust(
2121                 ConvertHPosLogic(
2122                     mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset,
2123                 aTabStop.GetTabPos());
2124             pItem->Insert(aTabStop);
2125         }
2126         mxTabStopItem.reset(pItem);
2127     }
2128     else if( mxTabStopItem->Count() == 0 )
2129         return;
2130     else
2131     {
2132         SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx);
2133         if( mxRulerImpl->lMaxRightLogic != -1 &&
2134             mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight )
2135         {
2136             // Set tab pos exactly at the right indent
2137             tools::Long nTmpLeftIndentLogic
2138                 = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
2139             if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem)
2140             {
2141                 nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetLeft();
2142             }
2143             aTabStop.GetTabPos()
2144                 = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic;
2145         }
2146         else
2147         {
2148             if(bRTL)
2149             {
2150                 //#i24363# tab stops relative to indent
2151                 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2152                                             GetLeftIndent() :
2153                                             ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset );
2154 
2155                 tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos);
2156                 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2157             }
2158             else
2159             {
2160                 //#i24363# tab stops relative to indent
2161                 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2162                                             GetLeftIndent() :
2163                                             ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset );
2164 
2165                 tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent);
2166                 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2167             }
2168         }
2169         mxTabStopItem->Remove(nCoreIdx);
2170         mxTabStopItem->Insert(aTabStop);
2171     }
2172     sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
2173     pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD,
2174             { mxTabStopItem.get() });
2175     UpdateTabs();
2176 }
2177 
ApplyBorders()2178 void SvxRuler::ApplyBorders()
2179 {
2180     /* Applying (table) column settings; changed by dragging. */
2181     if(mxColumnItem->IsTable())
2182     {
2183         tools::Long lValue = GetFrameLeft();
2184         if(lValue != mxRulerImpl->nColLeftPix)
2185         {
2186             tools::Long nLeft = PixelHAdjust(
2187                             ConvertHPosLogic(lValue) -
2188                                 lAppNullOffset,
2189                             mxColumnItem->GetLeft());
2190             mxColumnItem->SetLeft(nLeft);
2191         }
2192 
2193         lValue = GetMargin2();
2194 
2195         if(lValue != mxRulerImpl->nColRightPix)
2196         {
2197             tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
2198             tools::Long nRight = PixelHAdjust(
2199                             nWidthOrHeight -
2200                                 mxColumnItem->GetLeft() -
2201                                 ConvertHPosLogic(lValue) -
2202                                 lAppNullOffset,
2203                             mxColumnItem->GetRight() );
2204             mxColumnItem->SetRight(nRight);
2205         }
2206     }
2207 
2208     for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
2209     {
2210         tools::Long& nEnd = mxColumnItem->At(i).nEnd;
2211         nEnd = PixelHAdjust(
2212                 ConvertPosLogic(mpBorders[i].nPos),
2213                 mxColumnItem->At(i).nEnd);
2214         tools::Long& nStart = mxColumnItem->At(i + 1).nStart;
2215         nStart = PixelHAdjust(
2216                     ConvertSizeLogic(mpBorders[i].nPos +
2217                         mpBorders[i].nWidth) -
2218                         lAppNullOffset,
2219                     mxColumnItem->At(i + 1).nStart);
2220         // It may be that, due to the PixelHAdjust readjustment to old values,
2221         // the width becomes  < 0. This we readjust.
2222         if( nEnd > nStart )
2223             nStart = nEnd;
2224     }
2225 
2226 #ifdef DEBUGLIN
2227         Debug_Impl(pEditWin,*mxColumnItem);
2228 #endif // DEBUGLIN
2229 
2230     SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY,
2231                       bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY));
2232 
2233     sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) :
2234                             (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2235 
2236     pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD,
2237             { mxColumnItem.get(), &aFlag });
2238 }
2239 
ApplyObject()2240 void SvxRuler::ApplyObject()
2241 {
2242     /* Applying object settings, changed by dragging. */
2243 
2244     // to the page margin
2245     tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
2246     tools::Long nStartX = PixelAdjust(
2247                     ConvertPosLogic(mpObjectBorders[0].nPos) +
2248                         nMargin -
2249                         lAppNullOffset,
2250                     mxObjectItem->GetStartX());
2251     mxObjectItem->SetStartX(nStartX);
2252 
2253     tools::Long nEndX = PixelAdjust(
2254                     ConvertPosLogic(mpObjectBorders[1].nPos) +
2255                         nMargin -
2256                         lAppNullOffset,
2257                     mxObjectItem->GetEndX());
2258     mxObjectItem->SetEndX(nEndX);
2259 
2260     nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
2261     tools::Long nStartY = PixelAdjust(
2262                     ConvertPosLogic(mpObjectBorders[2].nPos) +
2263                         nMargin -
2264                         lAppNullOffset,
2265                     mxObjectItem->GetStartY());
2266     mxObjectItem->SetStartY(nStartY);
2267 
2268     tools::Long nEndY = PixelAdjust(
2269                     ConvertPosLogic(mpObjectBorders[3].nPos) +
2270                         nMargin -
2271                         lAppNullOffset,
2272                     mxObjectItem->GetEndY());
2273     mxObjectItem->SetEndY(nEndY);
2274 
2275     pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT,
2276             SfxCallMode::RECORD, { mxObjectItem.get() });
2277 }
2278 
PrepareProportional_Impl(RulerType eType)2279 void SvxRuler::PrepareProportional_Impl(RulerType eType)
2280 {
2281     /*
2282        Preparation proportional dragging, and it is calculated based on the
2283        proportional share of the total width in parts per thousand.
2284     */
2285     mxRulerImpl->nTotalDist = GetMargin2();
2286     switch(eType)
2287     {
2288       case RulerType::Margin2:
2289       case RulerType::Margin1:
2290       case RulerType::Border:
2291         {
2292             DBG_ASSERT(mxColumnItem, "no ColumnItem");
2293 
2294             mxRulerImpl->SetPercSize(mxColumnItem->Count());
2295 
2296             tools::Long lPos;
2297             tools::Long lWidth=0;
2298             sal_uInt16 nStart;
2299             sal_uInt16 nIdx=GetDragAryPos();
2300             tools::Long lActWidth=0;
2301             tools::Long lActBorderSum;
2302             tools::Long lOrigLPos;
2303 
2304             if(eType != RulerType::Border)
2305             {
2306                 lOrigLPos = GetMargin1();
2307                 nStart = 0;
2308                 lActBorderSum = 0;
2309             }
2310             else
2311             {
2312                 if(mxRulerImpl->bIsTableRows &&!bHorz)
2313                 {
2314                     lOrigLPos = GetMargin1();
2315                     nStart = 0;
2316                 }
2317                 else
2318                 {
2319                     lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth;
2320                     nStart = 1;
2321                 }
2322                 lActBorderSum = mpBorders[nIdx].nWidth;
2323             }
2324 
2325             //in horizontal mode the percentage value has to be
2326             //calculated on a "current change" position base
2327             //because the height of the table changes while dragging
2328             if(mxRulerImpl->bIsTableRows && RulerType::Border == eType)
2329             {
2330                 sal_uInt16 nStartBorder;
2331                 sal_uInt16 nEndBorder;
2332                 if(bHorz)
2333                 {
2334                     nStartBorder = nIdx + 1;
2335                     nEndBorder = mxColumnItem->Count() - 1;
2336                 }
2337                 else
2338                 {
2339                     nStartBorder = 0;
2340                     nEndBorder = nIdx;
2341                 }
2342 
2343                 lWidth = mpBorders[nIdx].nPos;
2344                 if(bHorz)
2345                     lWidth = GetMargin2() - lWidth;
2346                 mxRulerImpl->nTotalDist = lWidth;
2347                 lPos = mpBorders[nIdx].nPos;
2348 
2349                 for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i)
2350                 {
2351                     if(bHorz)
2352                     {
2353                         lActWidth += mpBorders[i].nPos - lPos;
2354                         lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2355                     }
2356                     else
2357                         lActWidth = mpBorders[i].nPos;
2358                     mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2359                                                     / mxRulerImpl->nTotalDist);
2360                     mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2361                     lActBorderSum += mpBorders[i].nWidth;
2362                 }
2363             }
2364             else
2365             {
2366                 lPos = lOrigLPos;
2367                 for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii)
2368                 {
2369                     lWidth += mpBorders[ii].nPos - lPos;
2370                     lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth;
2371                 }
2372 
2373                 lWidth += GetMargin2() - lPos;
2374                 mxRulerImpl->nTotalDist = lWidth;
2375                 lPos = lOrigLPos;
2376 
2377                 for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i)
2378                 {
2379                     lActWidth += mpBorders[i].nPos - lPos;
2380                     lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2381                     mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2382                                                     / mxRulerImpl->nTotalDist);
2383                     mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2384                     lActBorderSum += mpBorders[i].nWidth;
2385                 }
2386             }
2387         }
2388         break;
2389         case RulerType::Tab:
2390         {
2391             const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP;
2392             mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos;
2393             mxRulerImpl->SetPercSize(nTabCount);
2394             for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ;
2395             for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
2396             {
2397                 const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos;
2398                 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist);
2399             }
2400             break;
2401         }
2402         default: break;
2403     }
2404 }
2405 
EvalModifier()2406 void SvxRuler::EvalModifier()
2407 {
2408     /*
2409     Eval Drag Modifier
2410     Shift: move linear
2411     Control: move proportional
2412     Shift + Control: Table: only current line
2413     Alt: disable snapping
2414     Alt + Shift: coarse snapping
2415     */
2416 
2417     sal_uInt16 nModifier = GetDragModifier();
2418     if(mxRulerImpl->bIsTableRows)
2419     {
2420         //rows can only be moved in one way, additionally current column is possible
2421         if(nModifier == KEY_SHIFT)
2422             nModifier = 0;
2423     }
2424 
2425     switch(nModifier)
2426     {
2427         case KEY_SHIFT:
2428             nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR;
2429         break;
2430         case KEY_MOD2 | KEY_SHIFT:
2431             mbCoarseSnapping = true;
2432         break;
2433         case KEY_MOD2:
2434             mbSnapping = false;
2435         break;
2436         case KEY_MOD1:
2437         {
2438             const RulerType eType = GetDragType();
2439             nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL;
2440             if( RulerType::Tab == eType ||
2441                 ( ( RulerType::Border == eType  ||
2442                     RulerType::Margin1 == eType ||
2443                     RulerType::Margin2 == eType ) &&
2444                 mxColumnItem ) )
2445             {
2446                 PrepareProportional_Impl(eType);
2447             }
2448         }
2449         break;
2450         case KEY_MOD1 | KEY_SHIFT:
2451             if( GetDragType() != RulerType::Margin1 &&
2452                 GetDragType() != RulerType::Margin2 )
2453             {
2454                 nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY;
2455             }
2456         break;
2457     }
2458 }
2459 
Click()2460 void SvxRuler::Click()
2461 {
2462     /* Override handler SV; sets Tab per dispatcher call */
2463     Ruler::Click();
2464     if( bActive )
2465     {
2466         pBindings->Update( SID_RULER_LR_MIN_MAX );
2467         pBindings->Update( SID_ATTR_LONG_ULSPACE );
2468         pBindings->Update( SID_ATTR_LONG_LRSPACE );
2469         pBindings->Update( SID_RULER_PAGE_POS );
2470         pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
2471         pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
2472         pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2473         pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
2474         pBindings->Update( SID_RULER_OBJECT );
2475         pBindings->Update( SID_RULER_PROTECT );
2476         pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL );
2477     }
2478     bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2479     if(!(mxTabStopItem &&
2480        (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS))
2481         return;
2482 
2483     bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
2484     if( bContentProtected ) return;
2485     const tools::Long lPos = GetClickPos();
2486     if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) ||
2487         (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())))
2488         return;
2489 
2490     //convert position in left-to-right text
2491     tools::Long nTabPos;
2492 //#i24363# tab stops relative to indent
2493     if(bRTL)
2494         nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ?
2495                     GetLeftIndent() :
2496                     ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) -
2497                   lPos;
2498     else
2499         nTabPos = lPos -
2500                   ( mxRulerImpl->bIsTabsRelativeToIndent ?
2501                     GetLeftIndent() :
2502                     ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ));
2503 
2504     SvxTabStop aTabStop(ConvertHPosLogic(nTabPos),
2505                         ToAttrTab_Impl(nDefTabType));
2506     mxTabStopItem->Insert(aTabStop);
2507     UpdateTabs();
2508 }
2509 
CalcMinMax()2510 void SvxRuler::CalcMinMax()
2511 {
2512     /*
2513        Calculates the limits for dragging; which are in pixels relative to the
2514        page edge
2515     */
2516     bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2517     const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset);
2518     mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1;
2519     switch(GetDragType())
2520     {
2521         case RulerType::Margin1:
2522         {        // left edge of the surrounding Frame
2523             // DragPos - NOf between left - right
2524             mxRulerImpl->lMaxLeftLogic = GetLeftMin();
2525             nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic);
2526 
2527             if (!mxColumnItem || mxColumnItem->Count() == 1)
2528             {
2529                 if(bRTL)
2530                 {
2531                     nMaxRight = lNullPix - GetRightIndent() +
2532                         std::max(GetFirstLineIndent(), GetLeftIndent()) -
2533                         glMinFrame;
2534                 }
2535                 else
2536                 {
2537                     nMaxRight = lNullPix + GetRightIndent() -
2538                         std::max(GetFirstLineIndent(), GetLeftIndent()) -
2539                         glMinFrame;
2540                 }
2541             }
2542             else if(mxRulerImpl->bIsTableRows)
2543             {
2544                 //top border is not moveable when table rows are displayed
2545                 // protection of content means the margin is not moveable
2546                 if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected())
2547                 {
2548                     nMaxLeft = mpBorders[0].nMinPos + lNullPix;
2549                     if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2550                         nMaxRight = GetRightIndent() + lNullPix -
2551                                 (mxColumnItem->Count() - 1 ) * glMinFrame;
2552                     else
2553                         nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix;
2554                 }
2555                 else
2556                     nMaxLeft = nMaxRight = lNullPix;
2557             }
2558             else
2559             {
2560                 if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2561                 {
2562                     nMaxRight=lNullPix+CalcPropMaxRight();
2563                 }
2564                 else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
2565                 {
2566                     nMaxRight = ConvertPosPixel(
2567                         GetPageWidth() - (
2568                             (mxColumnItem->IsTable() && mxLRSpaceItem)
2569                             ? mxLRSpaceItem->GetRight() : 0))
2570                             - GetMargin2() + GetMargin1();
2571                 }
2572                 else
2573                 {
2574                     nMaxRight = lNullPix - glMinFrame;
2575                     if (mxColumnItem->IsFirstAct())
2576                     {
2577                         if(bRTL)
2578                         {
2579                             nMaxRight += std::min(
2580                                 mpBorders[0].nPos,
2581                                 std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent());
2582                         }
2583                         else
2584                         {
2585                             nMaxRight += std::min(
2586                                 mpBorders[0].nPos, GetRightIndent() -
2587                                 std::max(GetFirstLineIndent(), GetLeftIndent()));
2588                         }
2589                     }
2590                     else if ( mxColumnItem->Count() > 1 )
2591                     {
2592                         nMaxRight += mpBorders[0].nPos;
2593                     }
2594                     else
2595                     {
2596                         nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent());
2597                     }
2598                     // Do not drag the left table edge over the edge of the page
2599                     if(mxLRSpaceItem && mxColumnItem->IsTable())
2600                     {
2601                         tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft());
2602                         if(nTmp>nMaxLeft)
2603                             nMaxLeft=nTmp;
2604                     }
2605                 }
2606             }
2607             break;
2608         }
2609         case RulerType::Margin2:
2610         {        // right edge of the surrounding Frame
2611             mxRulerImpl->lMaxRightLogic
2612                 = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth();
2613             nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
2614 
2615             if (!mxColumnItem)
2616             {
2617                 if(bRTL)
2618                 {
2619                     nMaxLeft =  GetMargin2() + GetRightIndent() -
2620                         std::max(GetFirstLineIndent(),GetLeftIndent())  - GetMargin1()+
2621                             glMinFrame + lNullPix;
2622                 }
2623                 else
2624                 {
2625                     nMaxLeft =  GetMargin2() - GetRightIndent() +
2626                         std::max(GetFirstLineIndent(),GetLeftIndent())  - GetMargin1()+
2627                             glMinFrame + lNullPix;
2628                 }
2629             }
2630             else if(mxRulerImpl->bIsTableRows)
2631             {
2632                 // get the bottom move range from the last border position - only available for rows!
2633                 // protection of content means the margin is not moveable
2634                 if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected())
2635                 {
2636                     nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix;
2637                 }
2638                 else
2639                 {
2640                     if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2641                     {
2642                         nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix;
2643                     }
2644                     else
2645                     {
2646                         if(mxColumnItem->Count() > 1)
2647                             nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix;
2648                         else
2649                             nMaxLeft = glMinFrame + lNullPix;
2650                     }
2651                     if(mxColumnItem->Count() > 1)
2652                         nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix;
2653                     else
2654                         nMaxRight -= GetRightIndent() - lNullPix;
2655                 }
2656             }
2657             else
2658             {
2659                 nMaxLeft = glMinFrame + lNullPix;
2660                 if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column
2661                 {
2662                     if(bRTL)
2663                     {
2664                         nMaxLeft = glMinFrame + lNullPix + GetMargin2() +
2665                             GetRightIndent() - std::max(GetFirstLineIndent(),
2666                                                    GetLeftIndent());
2667                     }
2668                     else
2669                     {
2670                         nMaxLeft = glMinFrame + lNullPix + GetMargin2() -
2671                             GetRightIndent() + std::max(GetFirstLineIndent(),
2672                                                    GetLeftIndent());
2673                     }
2674                 }
2675                 if( mxColumnItem->Count() >= 2 )
2676                 {
2677                     tools::Long nNewMaxLeft =
2678                         glMinFrame + lNullPix +
2679                         mpBorders[mxColumnItem->Count() - 2].nPos +
2680                         mpBorders[mxColumnItem->Count() - 2].nWidth;
2681                     nMaxLeft = std::max(nMaxLeft, nNewMaxLeft);
2682                 }
2683 
2684             }
2685             break;
2686         }
2687         case RulerType::Border:
2688         {                // Table, column (Modifier)
2689         const sal_uInt16 nIdx = GetDragAryPos();
2690         switch(GetDragSize())
2691         {
2692           case RulerDragSize::N1 :
2693             {
2694                 nMaxRight = mpBorders[nIdx].nPos +
2695                     mpBorders[nIdx].nWidth + lNullPix;
2696 
2697                 if(0 == nIdx)
2698                     nMaxLeft = lNullPix;
2699                 else
2700                     nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix;
2701                 if(nIdx == mxColumnItem->GetActColumn())
2702                 {
2703                     if(bRTL)
2704                     {
2705                         nMaxLeft += mpBorders[nIdx].nPos +
2706                             GetRightIndent() - std::max(GetFirstLineIndent(),
2707                                                    GetLeftIndent());
2708                     }
2709                     else
2710                     {
2711                         nMaxLeft += mpBorders[nIdx].nPos -
2712                             GetRightIndent() + std::max(GetFirstLineIndent(),
2713                                                    GetLeftIndent());
2714                     }
2715                     if(0 != nIdx)
2716                         nMaxLeft -= mpBorders[nIdx-1].nPos +
2717                             mpBorders[nIdx-1].nWidth;
2718                 }
2719                 nMaxLeft += glMinFrame;
2720                 nMaxLeft += nDragOffset;
2721                 break;
2722             }
2723           case RulerDragSize::Move:
2724             {
2725                 if (mxColumnItem)
2726                 {
2727                     //nIdx contains the position of the currently moved item
2728                     //next visible separator on the left
2729                     sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx);
2730                     //next visible separator on the right
2731                     sal_uInt16 nRightCol=GetActRightColumn(false, nIdx);
2732                     //next separator on the left - regardless if visible or not
2733                     sal_uInt16 nActLeftCol=GetActLeftColumn();
2734                     //next separator on the right - regardless if visible or not
2735                     sal_uInt16 nActRightCol=GetActRightColumn();
2736                     if(mxColumnItem->IsTable())
2737                     {
2738                         if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)
2739                         {
2740                             //the current row/column should be modified only
2741                             //then the next/previous visible border position
2742                             //marks the min/max positions
2743                             nMaxLeft = nLeftCol == USHRT_MAX ?
2744                                 0 :
2745                                 mpBorders[nLeftCol].nPos;
2746                             //rows can always be increased without a limit
2747                             if(mxRulerImpl->bIsTableRows)
2748                                 nMaxRight = mpBorders[nIdx].nMaxPos;
2749                             else
2750                                 nMaxRight = nRightCol == USHRT_MAX ?
2751                                     GetMargin2():
2752                                     mpBorders[nRightCol].nPos;
2753                             nMaxLeft += lNullPix;
2754                             nMaxRight += lNullPix;
2755                         }
2756                         else
2757                         {
2758                             if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows)
2759                                 nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix;
2760                             else
2761                                 nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix;
2762                             if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2763                                (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2764                             {
2765                                 if(mxRulerImpl->bIsTableRows)
2766                                 {
2767                                     if(bHorz)
2768                                         nMaxRight = GetRightIndent() + lNullPix -
2769                                                 (mxColumnItem->Count() - nIdx - 1) * glMinFrame;
2770                                     else
2771                                         nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2772                                 }
2773                                 else
2774                                     nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2775                             }
2776                             else
2777                                 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2778                         }
2779                         nMaxLeft += glMinFrame;
2780                         nMaxRight -= glMinFrame;
2781 
2782                     }
2783                     else
2784                     {
2785                         if(nLeftCol==USHRT_MAX)
2786                             nMaxLeft=lNullPix;
2787                         else
2788                             nMaxLeft = mpBorders[nLeftCol].nPos +
2789                                 mpBorders[nLeftCol].nWidth + lNullPix;
2790 
2791                         if(nActRightCol == nIdx)
2792                         {
2793                             if(bRTL)
2794                             {
2795                                 nMaxLeft += mpBorders[nIdx].nPos +
2796                                     GetRightIndent() - std::max(GetFirstLineIndent(),
2797                                                            GetLeftIndent());
2798                                 if(nActLeftCol!=USHRT_MAX)
2799                                     nMaxLeft -= mpBorders[nActLeftCol].nPos +
2800                                         mpBorders[nActLeftCol].nWidth;
2801                             }
2802                             else
2803                             {
2804                                 nMaxLeft += mpBorders[nIdx].nPos -
2805                                     GetRightIndent() + std::max(GetFirstLineIndent(),
2806                                                            GetLeftIndent());
2807                                 if(nActLeftCol!=USHRT_MAX)
2808                                     nMaxLeft -= mpBorders[nActLeftCol].nPos +
2809                                         mpBorders[nActLeftCol].nWidth;
2810                             }
2811                         }
2812                         nMaxLeft += glMinFrame;
2813                         nMaxLeft += nDragOffset;
2814 
2815                         // nMaxRight
2816                         // linear / proportional move
2817                         if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2818                            (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2819                         {
2820                             nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2821                         }
2822                         else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType)
2823                         {
2824                             nMaxRight = lNullPix + GetMargin2() - GetMargin1() +
2825                                 (mpBorders.size() - nIdx - 1) * glMinFrame;
2826                         }
2827                         else
2828                         {
2829                             if(nRightCol==USHRT_MAX)
2830                             { // last column
2831                                 nMaxRight = GetMargin2() + lNullPix;
2832                                 if(IsActLastColumn())
2833                                 {
2834                                     if(bRTL)
2835                                     {
2836                                         nMaxRight -=
2837                                             GetMargin2() + GetRightIndent() -
2838                                                 std::max(GetFirstLineIndent(),
2839                                                     GetLeftIndent());
2840                                     }
2841                                     else
2842                                     {
2843                                         nMaxRight -=
2844                                             GetMargin2() - GetRightIndent() +
2845                                                 std::max(GetFirstLineIndent(),
2846                                                     GetLeftIndent());
2847                                     }
2848                                     nMaxRight += mpBorders[nIdx].nPos +
2849                                         mpBorders[nIdx].nWidth;
2850                                 }
2851                             }
2852                             else
2853                             {
2854                                 nMaxRight = lNullPix + mpBorders[nRightCol].nPos;
2855                                 sal_uInt16 nNotHiddenRightCol =
2856                                     GetActRightColumn(true, nIdx);
2857 
2858                                 if( nActLeftCol == nIdx )
2859                                 {
2860                                     tools::Long nBorder = nNotHiddenRightCol ==
2861                                         USHRT_MAX ?
2862                                         GetMargin2() :
2863                                         mpBorders[nNotHiddenRightCol].nPos;
2864                                     if(bRTL)
2865                                     {
2866                                         nMaxRight -= nBorder + GetRightIndent() -
2867                                             std::max(GetFirstLineIndent(),
2868                                                 GetLeftIndent());
2869                                     }
2870                                     else
2871                                     {
2872                                         nMaxRight -= nBorder - GetRightIndent() +
2873                                             std::max(GetFirstLineIndent(),
2874                                                 GetLeftIndent());
2875                                     }
2876                                     nMaxRight += mpBorders[nIdx].nPos +
2877                                         mpBorders[nIdx].nWidth;
2878                                 }
2879                             }
2880                             nMaxRight -= glMinFrame;
2881                             nMaxRight -= mpBorders[nIdx].nWidth;
2882                         }
2883                     }
2884                 }
2885                 // ObjectItem
2886                 else
2887                 {
2888                     nMaxLeft = LONG_MIN;
2889                     nMaxRight = LONG_MAX;
2890                 }
2891                 break;
2892             }
2893           case RulerDragSize::N2:
2894             {
2895                 nMaxLeft = lNullPix + mpBorders[nIdx].nPos;
2896                 if(nIdx == mxColumnItem->Count()-2) { // last column
2897                     nMaxRight = GetMargin2() + lNullPix;
2898                     if(mxColumnItem->IsLastAct()) {
2899                         nMaxRight -=
2900                             GetMargin2() - GetRightIndent() +
2901                                 std::max(GetFirstLineIndent(),
2902                                     GetLeftIndent());
2903                         nMaxRight += mpBorders[nIdx].nPos +
2904                             mpBorders[nIdx].nWidth;
2905                     }
2906                 }
2907                 else {
2908                     nMaxRight = lNullPix + mpBorders[nIdx+1].nPos;
2909                     if(mxColumnItem->GetActColumn()-1 == nIdx) {
2910                         nMaxRight -= mpBorders[nIdx+1].nPos  - GetRightIndent() +
2911                             std::max(GetFirstLineIndent(),
2912                                 GetLeftIndent());
2913                         nMaxRight += mpBorders[nIdx].nPos +
2914                             mpBorders[nIdx].nWidth;
2915                     }
2916             }
2917                 nMaxRight -= glMinFrame;
2918                 nMaxRight -= mpBorders[nIdx].nWidth;
2919                 break;
2920             }
2921         }
2922         nMaxRight += nDragOffset;
2923         break;
2924     }
2925       case RulerType::Indent:
2926         {
2927         const sal_uInt16 nIdx = GetDragAryPos();
2928         switch(nIdx) {
2929         case INDENT_FIRST_LINE - INDENT_GAP:
2930         case INDENT_LEFT_MARGIN - INDENT_GAP:
2931             {
2932                 if(bRTL)
2933                 {
2934                     nMaxLeft = lNullPix + GetRightIndent();
2935 
2936                     if(mxColumnItem && !mxColumnItem->IsFirstAct())
2937                         nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
2938                             mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
2939                     nMaxRight = lNullPix + GetMargin2();
2940 
2941                     // Dragging along
2942                     if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
2943                        !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
2944                     {
2945                         if(GetLeftIndent() > GetFirstLineIndent())
2946                             nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
2947                         else
2948                             nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
2949                     }
2950                 }
2951                 else
2952                 {
2953                     nMaxLeft = lNullPix;
2954 
2955                     if(mxColumnItem && !mxColumnItem->IsFirstAct())
2956                         nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
2957                             mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
2958                     nMaxRight = lNullPix + GetRightIndent() - glMinFrame;
2959 
2960                     // Dragging along
2961                     if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
2962                        !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
2963                     {
2964                         if(GetLeftIndent() > GetFirstLineIndent())
2965                             nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
2966                         else
2967                             nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
2968                     }
2969                 }
2970             }
2971           break;
2972           case INDENT_RIGHT_MARGIN - INDENT_GAP:
2973             {
2974                 if(bRTL)
2975                 {
2976                     nMaxLeft = lNullPix;
2977                     nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame;
2978                     if (mxColumnItem)
2979                     {
2980                         sal_uInt16 nRightCol=GetActRightColumn( true );
2981                         if(!IsActLastColumn( true ))
2982                             nMaxRight += mpBorders[nRightCol].nPos;
2983                         else
2984                             nMaxRight += GetMargin2();
2985                     }
2986                     else
2987                     {
2988                         nMaxLeft += GetMargin1();
2989                     }
2990                     nMaxLeft += glMinFrame;
2991                 }
2992                 else
2993                 {
2994                     nMaxLeft = lNullPix +
2995                         std::max(GetFirstLineIndent(), GetLeftIndent());
2996                     nMaxRight = lNullPix;
2997                     if (mxColumnItem)
2998                     {
2999                         sal_uInt16 nRightCol=GetActRightColumn( true );
3000                         if(!IsActLastColumn( true ))
3001                             nMaxRight += mpBorders[nRightCol].nPos;
3002                         else
3003                             nMaxRight += GetMargin2();
3004                     }
3005                     else
3006                         nMaxRight += GetMargin2();
3007                     nMaxLeft += glMinFrame;
3008                 }
3009             }
3010             break;
3011         }
3012         break;
3013     }
3014     case RulerType::Tab:                // Tabs (Modifier)
3015         /* left = NOf + Max(LAR, EZ)
3016            right = NOf + RAR */
3017 
3018         if (bRTL)
3019             nMaxLeft = lNullPix + GetRightIndent();
3020         else
3021             nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent());
3022 
3023         mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset;
3024         nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
3025         break;
3026     default: ; //prevent warning
3027     }
3028 }
3029 
StartDrag()3030 bool SvxRuler::StartDrag()
3031 {
3032     /*
3033        Beginning of a drag operation (SV-handler) evaluates modifier and
3034        calculated values
3035 
3036        [Cross-reference]
3037 
3038        <SvxRuler::EvalModifier()>
3039        <SvxRuler::CalcMinMax()>
3040        <SvxRuler::EndDrag()>
3041     */
3042     bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
3043 
3044     if(!bValid)
3045         return false;
3046 
3047     mxRulerImpl->lLastLMargin = GetMargin1();
3048     mxRulerImpl->lLastRMargin = GetMargin2();
3049 
3050     bool bOk = true;
3051 
3052     lInitialDragPos = GetDragPos();
3053     switch(GetDragType())
3054     {
3055         case RulerType::Margin1:        // left edge of the surrounding Frame
3056         case RulerType::Margin2:        // right edge of the surrounding Frame
3057             if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem))
3058             {
3059                 if (!mxColumnItem)
3060                     EvalModifier();
3061                 else
3062                     nDragType = SvxRulerDragFlags::OBJECT;
3063             }
3064             else
3065             {
3066                 bOk = false;
3067             }
3068             break;
3069         case RulerType::Border: // Table, column (Modifier)
3070             if (mxColumnItem)
3071             {
3072                 nDragOffset = 0;
3073                 if (!mxColumnItem->IsTable())
3074                     nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos;
3075                 EvalModifier();
3076             }
3077             else
3078                 nDragOffset = 0;
3079             break;
3080         case RulerType::Indent: // Paragraph indents (Modifier)
3081         {
3082             if( bContentProtected )
3083                 return false;
3084             if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) {  // Left paragraph indent
3085                 mpIndents[0] = mpIndents[INDENT_FIRST_LINE];
3086                 EvalModifier();
3087             }
3088             else
3089             {
3090                 nDragType = SvxRulerDragFlags::OBJECT;
3091             }
3092             mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP];
3093             break;
3094         }
3095         case RulerType::Tab: // Tabs (Modifier)
3096             if( bContentProtected )
3097                 return false;
3098             EvalModifier();
3099             mpTabs[0] = mpTabs[GetDragAryPos() + 1];
3100             mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW;
3101             break;
3102         default:
3103             nDragType = SvxRulerDragFlags::NONE;
3104     }
3105 
3106     if(bOk)
3107         CalcMinMax();
3108 
3109     return bOk;
3110 }
3111 
Drag()3112 void  SvxRuler::Drag()
3113 {
3114     /* SV-Draghandler */
3115     if(IsDragCanceled())
3116     {
3117         Ruler::Drag();
3118         return;
3119     }
3120     switch(GetDragType()) {
3121         case RulerType::Margin1: // left edge of the surrounding Frame
3122             DragMargin1();
3123             mxRulerImpl->lLastLMargin = GetMargin1();
3124             break;
3125         case RulerType::Margin2: // right edge of the surrounding Frame
3126             DragMargin2();
3127             mxRulerImpl->lLastRMargin = GetMargin2();
3128             break;
3129         case RulerType::Indent: // Paragraph indents
3130             DragIndents();
3131             break;
3132         case RulerType::Border: // Table, columns
3133             if (mxColumnItem)
3134                 DragBorders();
3135             else if (mxObjectItem)
3136                 DragObjectBorder();
3137             break;
3138         case RulerType::Tab: // Tabs
3139             DragTabs();
3140             break;
3141         default:
3142             break; //prevent warning
3143     }
3144     Ruler::Drag();
3145 }
3146 
EndDrag()3147 void SvxRuler::EndDrag()
3148 {
3149     /*
3150        SV-handler; is called when ending the dragging. Triggers the updating of data
3151        on the application, by calling the respective Apply...() methods to send the
3152        data to the application.
3153     */
3154     const bool bUndo = IsDragCanceled();
3155     const tools::Long lPos = GetDragPos();
3156     DrawLine_Impl(lTabPos, 6, bHorz);
3157     lTabPos = -1;
3158 
3159     if(!bUndo)
3160     {
3161         switch(GetDragType())
3162         {
3163             case RulerType::Margin1: // upper left edge of the surrounding Frame
3164             case RulerType::Margin2: // lower right edge of the surrounding Frame
3165                 {
3166                     if (!mxColumnItem || !mxColumnItem->IsTable())
3167                         ApplyMargins();
3168 
3169                     if(mxColumnItem &&
3170                        (mxColumnItem->IsTable() ||
3171                         (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
3172                         ApplyBorders();
3173 
3174                 }
3175                 break;
3176             case RulerType::Border: // Table, columns
3177                 if(lInitialDragPos != lPos ||
3178                     (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here
3179                 {
3180                     if (mxColumnItem)
3181                     {
3182                         ApplyBorders();
3183                         if(bHorz)
3184                             UpdateTabs();
3185                     }
3186                     else if (mxObjectItem)
3187                         ApplyObject();
3188                 }
3189                 break;
3190             case RulerType::Indent: // Paragraph indents
3191                 if(lInitialDragPos != lPos)
3192                     ApplyIndents();
3193                 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
3194                 break;
3195             case RulerType::Tab: // Tabs
3196                 {
3197                     ApplyTabs();
3198                     mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE;
3199                     SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
3200                 }
3201                 break;
3202             default:
3203                 break; //prevent warning
3204         }
3205     }
3206     nDragType = SvxRulerDragFlags::NONE;
3207 
3208     mbCoarseSnapping = false;
3209     mbSnapping = true;
3210 
3211     Ruler::EndDrag();
3212     if(bUndo)
3213     {
3214         for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++)
3215         {
3216             pCtrlItems[i]->ClearCache();
3217             pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId());
3218         }
3219     }
3220 }
3221 
ExtraDown()3222 void SvxRuler::ExtraDown()
3223 {
3224     /* Override SV method, sets the new type for the Default tab. */
3225 
3226     // Switch Tab Type
3227     if(mxTabStopItem &&
3228         (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)
3229     {
3230         ++nDefTabType;
3231         if(RULER_TAB_DEFAULT == nDefTabType)
3232             nDefTabType = RULER_TAB_LEFT;
3233         SetExtraType(RulerExtra::Tab, nDefTabType);
3234     }
3235     Ruler::ExtraDown();
3236 }
3237 
Notify(SfxBroadcaster &,const SfxHint & rHint)3238 void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint)
3239 {
3240     /*
3241        Report through the bindings that the status update is completed. The ruler
3242        updates its appearance and gets registered again in the bindings.
3243     */
3244 
3245     // start update
3246     if (bActive && rHint.GetId() == SfxHintId::UpdateDone)
3247     {
3248         Update();
3249         EndListening(*pBindings);
3250         bValid = true;
3251         bListening = false;
3252     }
3253 }
3254 
MenuSelect(std::string_view ident)3255 void SvxRuler::MenuSelect(std::string_view ident)
3256 {
3257     if (ident.empty())
3258         return;
3259     /* Handler of the context menus for switching the unit of measurement */
3260     SetUnit(vcl::EnglishStringToMetric(OUString::fromUtf8(ident)));
3261 }
3262 
TabMenuSelect(const OString & rIdent)3263 void SvxRuler::TabMenuSelect(const OString& rIdent)
3264 {
3265     if (rIdent.isEmpty())
3266         return;
3267     sal_Int32 nId = rIdent.toInt32();
3268     /* Handler of the tab menu for setting the type */
3269     if (mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx)
3270     {
3271         SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx);
3272         aTabStop.GetAdjustment() = ToAttrTab_Impl(nId - 1);
3273         mxTabStopItem->Remove(mxRulerImpl->nIdx);
3274         mxTabStopItem->Insert(aTabStop);
3275         sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
3276         pBindings->GetDispatcher()->ExecuteList(nTabStopId,
3277                 SfxCallMode::RECORD, { mxTabStopItem.get() });
3278         UpdateTabs();
3279         mxRulerImpl->nIdx = 0;
3280     }
3281 }
3282 
3283 static const char* RID_SVXSTR_RULER_TAB[] =
3284 {
3285     RID_SVXSTR_RULER_TAB_LEFT,
3286     RID_SVXSTR_RULER_TAB_RIGHT,
3287     RID_SVXSTR_RULER_TAB_CENTER,
3288     RID_SVXSTR_RULER_TAB_DECIMAL
3289 };
3290 
Command(const CommandEvent & rCommandEvent)3291 void SvxRuler::Command( const CommandEvent& rCommandEvent )
3292 {
3293     /* Mouse context menu for switching the unit of measurement */
3294     if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() )
3295     {
3296         CancelDrag();
3297 
3298         tools::Rectangle aRect(rCommandEvent.GetMousePosPixel(), Size(1, 1));
3299         weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
3300         std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/rulermenu.ui"));
3301         std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
3302 
3303         bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
3304         if ( !mpTabs.empty() &&
3305              RulerType::Tab ==
3306              GetRulerType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) &&
3307              mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT )
3308         {
3309             xMenu->clear();
3310 
3311             const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2);
3312             const Point aPt(aSz.Width() / 2, aSz.Height() / 2);
3313 
3314             for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i )
3315             {
3316                 ScopedVclPtr<VirtualDevice> xDev(pPopupParent->create_virtual_device());
3317                 xDev->SetOutputSize(aSz);
3318 
3319                 sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i;
3320                 nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT);
3321 
3322                 Color aFillColor(xDev->GetSettings().GetStyleSettings().GetShadowColor());
3323                 DrawTab(*xDev, aFillColor, aPt, nStyle);
3324 
3325                 OString sId(OString::number(i + 1));
3326                 xMenu->insert(-1, OUString::fromUtf8(sId), SvxResId(RID_SVXSTR_RULER_TAB[i]),
3327                               nullptr, xDev.get(), nullptr, TRISTATE_TRUE);
3328                 xMenu->set_active(sId, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle);
3329             }
3330             TabMenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
3331         }
3332         else
3333         {
3334             FieldUnit eUnit = GetUnit();
3335             const int nCount = xMenu->n_children();
3336 
3337             bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC);
3338             for ( sal_uInt16 i = nCount; i; --i )
3339             {
3340                 OString sIdent = xMenu->get_id(i - 1);
3341                 FieldUnit eMenuUnit = vcl::EnglishStringToMetric(OUString::fromUtf8(sIdent));
3342                 xMenu->set_active(sIdent, eMenuUnit == eUnit);
3343                 if( bReduceMetric )
3344                 {
3345                     if (eMenuUnit == FieldUnit::M    ||
3346                         eMenuUnit == FieldUnit::KM   ||
3347                         eMenuUnit == FieldUnit::FOOT ||
3348                         eMenuUnit == FieldUnit::MILE)
3349                     {
3350                         xMenu->remove(sIdent);
3351                     }
3352                     else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz )
3353                     {
3354                         xMenu->remove(sIdent);
3355                     }
3356                     else if (( eMenuUnit == FieldUnit::LINE ) && bHorz )
3357                     {
3358                         xMenu->remove(sIdent);
3359                     }
3360                 }
3361             }
3362             MenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
3363         }
3364     }
3365     else
3366     {
3367         Ruler::Command( rCommandEvent );
3368     }
3369 }
3370 
GetActRightColumn(bool bForceDontConsiderHidden,sal_uInt16 nAct) const3371 sal_uInt16 SvxRuler::GetActRightColumn(
3372                         bool bForceDontConsiderHidden,
3373                         sal_uInt16 nAct ) const
3374 {
3375     if( nAct == USHRT_MAX )
3376         nAct = mxColumnItem->GetActColumn();
3377     else
3378         nAct++; //To be able to pass on the ActDrag
3379 
3380     bool bConsiderHidden = !bForceDontConsiderHidden &&
3381                                !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3382 
3383     while( nAct < mxColumnItem->Count() - 1 )
3384     {
3385         if (mxColumnItem->At(nAct).bVisible || bConsiderHidden)
3386             return nAct;
3387         else
3388             nAct++;
3389     }
3390     return USHRT_MAX;
3391 }
3392 
GetActLeftColumn(bool bForceDontConsiderHidden,sal_uInt16 nAct) const3393 sal_uInt16 SvxRuler::GetActLeftColumn(
3394                         bool bForceDontConsiderHidden,
3395                         sal_uInt16 nAct ) const
3396 {
3397     if(nAct == USHRT_MAX)
3398         nAct = mxColumnItem->GetActColumn();
3399 
3400     sal_uInt16 nLeftOffset = 1;
3401 
3402     bool bConsiderHidden = !bForceDontConsiderHidden &&
3403                                !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3404 
3405     while(nAct >= nLeftOffset)
3406     {
3407         if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden)
3408             return nAct - nLeftOffset;
3409         else
3410             nLeftOffset++;
3411     }
3412     return USHRT_MAX;
3413 }
3414 
IsActLastColumn(bool bForceDontConsiderHidden,sal_uInt16 nAct) const3415 bool SvxRuler::IsActLastColumn(
3416                         bool bForceDontConsiderHidden,
3417                         sal_uInt16 nAct) const
3418 {
3419     return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3420 }
3421 
IsActFirstColumn(bool bForceDontConsiderHidden,sal_uInt16 nAct) const3422 bool SvxRuler::IsActFirstColumn(
3423                         bool bForceDontConsiderHidden,
3424                         sal_uInt16 nAct) const
3425 {
3426     return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3427 }
3428 
CalcPropMaxRight(sal_uInt16 nCol) const3429 tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const
3430 {
3431 
3432     if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
3433     {
3434         // Remove the minimum width for all affected columns
3435         // starting from the right edge
3436         tools::Long _nMaxRight = GetMargin2() - GetMargin1();
3437 
3438         tools::Long lFences = 0;
3439         tools::Long lMinSpace = USHRT_MAX;
3440         tools::Long lOldPos;
3441         tools::Long lColumns = 0;
3442 
3443         sal_uInt16 nStart;
3444         if(!mxColumnItem->IsTable())
3445         {
3446             if(nCol == USHRT_MAX)
3447             {
3448                 lOldPos = GetMargin1();
3449                 nStart = 0;
3450             }
3451             else
3452             {
3453                 lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth;
3454                 nStart = nCol + 1;
3455                 lFences = mpBorders[nCol].nWidth;
3456             }
3457 
3458             for(size_t i = nStart; i < mpBorders.size() - 1; ++i)
3459             {
3460                 tools::Long lWidth = mpBorders[i].nPos - lOldPos;
3461                 lColumns += lWidth;
3462                 if(lWidth < lMinSpace)
3463                     lMinSpace = lWidth;
3464                 lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth;
3465                 lFences += mpBorders[i].nWidth;
3466             }
3467             tools::Long lWidth = GetMargin2() - lOldPos;
3468             lColumns += lWidth;
3469             if(lWidth < lMinSpace)
3470                 lMinSpace = lWidth;
3471         }
3472         else
3473         {
3474             sal_uInt16 nActCol;
3475             if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin
3476             {
3477                 lOldPos = GetMargin1();
3478             }
3479             else
3480             {
3481                 lOldPos = mpBorders[nCol].nPos;
3482             }
3483             lColumns = GetMargin2()-lOldPos;
3484             nActCol = nCol;
3485             lFences = 0;
3486             while(nActCol < mpBorders.size() || nActCol == USHRT_MAX)
3487             {
3488                 sal_uInt16 nRight;
3489                 if(nActCol == USHRT_MAX)
3490                 {
3491                     nRight = 0;
3492                     while (!(*mxColumnItem)[nRight].bVisible)
3493                     {
3494                         nRight++;
3495                     }
3496                 }
3497                 else
3498                 {
3499                     nRight = GetActRightColumn(false, nActCol);
3500                 }
3501 
3502                 tools::Long lWidth;
3503                 if(nRight != USHRT_MAX)
3504                 {
3505                     lWidth = mpBorders[nRight].nPos - lOldPos;
3506                     lOldPos = mpBorders[nRight].nPos;
3507                 }
3508                 else
3509                 {
3510                     lWidth=GetMargin2() - lOldPos;
3511                 }
3512                 nActCol = nRight;
3513                 if(lWidth < lMinSpace)
3514                     lMinSpace = lWidth;
3515                 if(nActCol == USHRT_MAX)
3516                     break;
3517             }
3518         }
3519 
3520         _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns);
3521         return _nMaxRight;
3522     }
3523     else
3524     {
3525         if(mxColumnItem->IsTable())
3526         {
3527             sal_uInt16 nVisCols = 0;
3528             for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();)
3529             {
3530                 if ((*mxColumnItem)[i].bVisible)
3531                     nVisCols++;
3532                 i = GetActRightColumn(false, i);
3533             }
3534             return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame;
3535         }
3536         else
3537         {
3538             tools::Long lWidth = 0;
3539             for(size_t i = nCol; i < mpBorders.size() - 1; i++)
3540             {
3541                 lWidth += glMinFrame + mpBorders[i].nWidth;
3542             }
3543             return GetMargin2() - GetMargin1() - lWidth;
3544         }
3545     }
3546 }
3547 
3548 // Tab stops relative to indent (#i24363#)
SetTabsRelativeToIndent(bool bRel)3549 void SvxRuler::SetTabsRelativeToIndent( bool bRel )
3550 {
3551     mxRulerImpl->bIsTabsRelativeToIndent = bRel;
3552 }
3553 
SetValues(RulerChangeType type,tools::Long diffValue)3554 void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue)
3555 {
3556     if (diffValue == 0)
3557         return;
3558 
3559     if (type == RulerChangeType::MARGIN1)
3560         AdjustMargin1(diffValue);
3561     else if (type == RulerChangeType::MARGIN2)
3562         SetMargin2( GetMargin2() - diffValue);
3563     ApplyMargins();
3564 }
3565 
3566 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
3567