cid#1636690 Dereference after null check
[LibreOffice.git] / svx / source / dialog / svxruler.cxx
blob7c60ac13faf6d26c4865845a9434a8be8afbfb4a
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.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cstring>
21 #include <climits>
23 #include <vcl/commandevent.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/fieldvalues.hxx>
26 #include <vcl/settings.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/weldutils.hxx>
30 #include <svl/eitem.hxx>
31 #include <svl/rectitem.hxx>
32 #include <svl/hint.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include <svx/strings.hrc>
35 #include <svx/svxids.hrc>
36 #include <svx/dialmgr.hxx>
37 #include <svx/ruler.hxx>
38 #include <svx/rulritem.hxx>
39 #include <sfx2/viewsh.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 #include <o3tl/string_view.hxx>
47 #include <svl/itemset.hxx>
48 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
49 #include <tools/json_writer.hxx>
50 #include <tools/UnitConversion.hxx>
51 #include <comphelper/lok.hxx>
52 #include "rlrcitem.hxx"
53 #include <com/sun/star/frame/XFrame.hpp>
54 #include <com/sun/star/lang/XServiceInfo.hpp>
55 #include <sfx2/viewfrm.hxx>
56 #include <memory>
58 using namespace css;
60 #define CTRL_ITEM_COUNT 14
61 #define GAP 10
62 #define OBJECT_BORDER_COUNT 4
63 #define TAB_GAP 1
64 #define INDENT_GAP 2
65 #define INDENT_FIRST_LINE 2
66 #define INDENT_LEFT_MARGIN 3
67 #define INDENT_RIGHT_MARGIN 4
68 #define INDENT_COUNT 3 //without the first two old values
70 struct SvxRuler_Impl {
71 std::unique_ptr<sal_uInt16[]> pPercBuf;
72 std::unique_ptr<sal_uInt16[]> pBlockBuf;
73 sal_uInt16 nPercSize;
74 tools::Long nTotalDist;
75 tools::Long lOldWinPos;
76 tools::Long lMaxLeftLogic;
77 tools::Long lMaxRightLogic;
78 tools::Long lLastLMargin;
79 tools::Long lLastRMargin;
80 std::unique_ptr<SvxProtectItem> aProtectItem;
81 std::unique_ptr<SfxBoolItem> pTextRTLItem;
82 sal_uInt16 nControllerItems;
83 sal_uInt16 nIdx;
84 sal_uInt16 nColLeftPix;
85 sal_uInt16 nColRightPix; // Pixel values for left / right edge
86 // For columns; buffered to prevent
87 // recalculation errors
88 // May be has to be widen for future values
89 bool bIsTableRows : 1; // mxColumnItem contains table rows instead of columns
90 //#i24363# tab stops relative to indent
91 bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent?
92 // false means relative to SvxRuler::GetLeftFrameMargin()
94 SvxRuler_Impl() :
95 nPercSize(0), nTotalDist(0),
96 lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0),
97 lLastLMargin(0), lLastRMargin(0),
98 aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)),
99 nControllerItems(0), nIdx(0),
100 nColLeftPix(0), nColRightPix(0),
101 bIsTableRows(false),
102 bIsTabsRelativeToIndent(true)
106 void SetPercSize(sal_uInt16 nSize);
110 static RulerTabData ruler_tab_svx =
112 0, // DPIScaleFactor to be set
113 7, // ruler_tab_width
114 6, // ruler_tab_height
115 0, // ruler_tab_height2
116 0, // ruler_tab_width2
117 0, // ruler_tab_cwidth
118 0, // ruler_tab_cwidth2
119 0, // ruler_tab_cwidth3
120 0, // ruler_tab_cwidth4
121 0, // ruler_tab_dheight
122 0, // ruler_tab_dheight2
123 0, // ruler_tab_dwidth
124 0, // ruler_tab_dwidth2
125 0, // ruler_tab_dwidth3
126 0, // ruler_tab_dwidth4
127 0 // ruler_tab_textoff
130 void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize)
132 if(nSize > nPercSize)
134 nPercSize = nSize;
135 pPercBuf.reset( new sal_uInt16[nPercSize] );
136 pBlockBuf.reset( new sal_uInt16[nPercSize] );
138 size_t nSize2 = sizeof(sal_uInt16) * nPercSize;
139 memset(pPercBuf.get(), 0, nSize2);
140 memset(pBlockBuf.get(), 0, nSize2);
143 // Constructor of the ruler
145 // SID_ATTR_ULSPACE, SID_ATTR_LRSPACE
146 // expects as parameter SvxULSpaceItem for page edge
147 // (either left/right or top/bottom)
148 // Ruler: SetMargin1, SetMargin2
150 // SID_RULER_PAGE_POS
151 // expects as parameter the initial value of the page and page width
152 // Ruler: SetPagePos
154 // SID_ATTR_TABSTOP
155 // expects: SvxTabStopItem
156 // Ruler: SetTabs
158 // SID_ATTR_PARA_LRSPACE
159 // left, right paragraph edge in H-ruler
160 // Ruler: SetIndents
162 // SID_RULER_BORDERS
163 // Table borders, columns
164 // expects: something like SwTabCols
165 // Ruler: SetBorders
167 constexpr tools::Long glMinFrame = 5; // minimal frame width in pixels
169 SvxRuler::SvxRuler(
170 vcl::Window* pParent, // StarView Parent
171 vcl::Window* pWin, // Output window: is used for conversion
172 // logical units <-> pixels
173 SvxRulerSupportFlags flags, // Display flags, see ruler.hxx
174 SfxBindings &rBindings, // associated Bindings
175 WinBits nWinStyle) : // StarView WinBits
176 Ruler(pParent, nWinStyle),
177 pCtrlItems(CTRL_ITEM_COUNT),
178 pEditWin(pWin),
179 mxRulerImpl(new SvxRuler_Impl),
180 bAppSetNullOffset(false), // Is the 0-offset of the ruler set by the application?
181 lLogicNullOffset(0),
182 lAppNullOffset(LONG_MAX),
183 lInitialDragPos(0),
184 nFlags(flags),
185 nDragType(SvxRulerDragFlags::NONE),
186 nDefTabType(RULER_TAB_LEFT),
187 nTabCount(0),
188 nTabBufSize(0),
189 lDefTabDist(50),
190 lTabPos(-1),
191 mpBorders(1), // due to one column tables
192 pBindings(&rBindings),
193 nDragOffset(0),
194 nMaxLeft(0),
195 nMaxRight(0),
196 bValid(false),
197 bListening(false),
198 bActive(true),
199 mbCoarseSnapping(false),
200 mbSnapping(true)
202 /* Constructor; Initialize data buffer; controller items are created */
204 rBindings.EnterRegistrations();
206 // Create Supported Items
207 sal_uInt16 i = 0;
209 // Page edges
210 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings));
211 if((nWinStyle & WB_VSCROLL) == WB_VSCROLL)
213 bHorz = false;
214 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings));
216 else
218 bHorz = true;
219 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings));
222 // Page Position
223 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings));
225 if(nFlags & SvxRulerSupportFlags::TABS)
227 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
228 pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings));
229 SetExtraType(RulerExtra::Tab, nDefTabType);
232 if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
234 if(bHorz)
235 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings));
236 else
237 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings));
239 mpIndents.resize(5 + INDENT_GAP);
241 for(RulerIndent & rIndent : mpIndents)
243 rIndent.nPos = 0;
244 rIndent.nStyle = RulerIndentStyle::Top;
247 mpIndents[0].nStyle = RulerIndentStyle::Top;
248 mpIndents[1].nStyle = RulerIndentStyle::Top;
249 mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top;
250 mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom;
251 mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom;
254 if( (nFlags & SvxRulerSupportFlags::BORDERS) == SvxRulerSupportFlags::BORDERS )
256 pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings));
257 pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings));
260 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings));
262 if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT )
264 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings));
265 mpObjectBorders.resize(OBJECT_BORDER_COUNT);
266 for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder)
268 mpObjectBorders[nBorder].nPos = 0;
269 mpObjectBorders[nBorder].nWidth = 0;
270 mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable;
274 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings));
275 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings));
276 mxRulerImpl->nControllerItems=i;
278 if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET )
279 SetExtraType(RulerExtra::NullOffset);
281 rBindings.LeaveRegistrations();
283 ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor();
284 ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor;
285 ruler_tab_svx.width *= ruler_tab_svx.DPIScaleFactor;
288 SvxRuler::~SvxRuler()
290 disposeOnce();
293 void SvxRuler::dispose()
295 /* Destructor ruler; release internal buffer */
296 if(bListening)
297 EndListening(*pBindings);
299 pBindings->EnterRegistrations();
301 pCtrlItems.clear();
303 pBindings->LeaveRegistrations();
305 pEditWin.clear();
306 Ruler::dispose();
309 tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const
311 tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference);
312 tools::Long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin());
313 tools::Long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin());
315 double aTick = GetCurrentRulerUnit().nTick1;
317 if (mbCoarseSnapping)
318 aTick = GetCurrentRulerUnit().nTick2;
320 tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width();
322 double aHalfTick = aTick / 2.0;
323 double aHalfTickPixel = aTickPixel / 2.0;
325 if (aSnapToFrameMargin)
327 if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel)
328 return aLeftFramePosition;
330 if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel)
331 return aRightFramePosition;
334 if (!mbSnapping)
335 return aPosition;
337 // Move "coordinate system" to frame position so ticks are calculated correctly
338 tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel;
339 // Convert position to current selected map mode
340 tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width();
341 // Normalize -- snap to nearest tick
342 aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick;
343 // Convert back to pixels
344 aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width();
345 // Move "coordinate system" back to original position
346 return aPosition + aPointOfReferencePixel;
349 tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const
351 return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
354 tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const
356 return pEditWin->LogicToPixel(Size(0, nVal)).Height();
359 tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const
361 return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
364 tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const
366 return pEditWin->LogicToPixel(Size(0, nVal)).Height();
369 tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const
371 return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal);
374 tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const
376 return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal);
379 inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const
381 return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
384 inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const
386 return pEditWin->PixelToLogic(Size(0, nVal)).Height();
389 inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const
391 return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
394 inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const
396 return pEditWin->PixelToLogic(Size(0, nVal)).Height();
399 inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const
401 return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal);
404 inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const
406 return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal);
409 tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const
411 if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld))
412 return nVal;
413 else
414 return nValOld;
417 tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const
419 if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld))
420 return nVal;
421 else
422 return nValOld;
425 tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const
427 if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld))
428 return nVal;
429 else
430 return nValOld;
433 inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const
435 return bHorz ? nIdx : nIdx + 2;
439 Update Upper Left edge.
440 Items are translated into the representation of the ruler.
442 void SvxRuler::UpdateFrame()
444 const RulerMarginStyle nMarginStyle =
445 ( mxRulerImpl->aProtectItem->IsSizeProtected() ||
446 mxRulerImpl->aProtectItem->IsPosProtected() ) ?
447 RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
449 if(mxLRSpaceItem && mxPagePosItem)
451 // if no initialization by default app behavior
452 const tools::Long nOld = lLogicNullOffset;
453 lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft();
455 if(bAppSetNullOffset)
457 lAppNullOffset += lLogicNullOffset - nOld;
460 if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
462 Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset));
463 SetMargin1(0, nMarginStyle);
464 lAppNullOffset = 0;
466 else
468 SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle);
471 tools::Long lRight = 0;
473 // evaluate the table right edge of the table
474 if(mxColumnItem && mxColumnItem->IsTable())
475 lRight = mxColumnItem->GetRight();
476 else
477 lRight = mxLRSpaceItem->GetRight();
479 tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset;
480 tools::Long aWidthPixel = ConvertHPosPixel(aWidth);
482 SetMargin2(aWidthPixel, nMarginStyle);
484 else if(mxULSpaceItem && mxPagePosItem)
486 // relative the upper edge of the surrounding frame
487 const tools::Long nOld = lLogicNullOffset;
488 lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper();
490 if(bAppSetNullOffset)
492 lAppNullOffset += lLogicNullOffset - nOld;
495 if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
497 Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset));
498 lAppNullOffset = 0;
499 SetMargin1(0, nMarginStyle);
501 else
503 SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle);
506 tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower();
507 tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset;
508 tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2);
510 SetMargin2(nMargin2Pixel, nMarginStyle);
512 else
514 // turns off the view
515 SetMargin1();
516 SetMargin2();
519 if (mxColumnItem)
521 mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft()));
522 mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight()));
526 void SvxRuler::MouseMove( const MouseEvent& rMEvt )
528 if( bActive )
530 pBindings->Update( SID_RULER_LR_MIN_MAX );
531 pBindings->Update( SID_ATTR_LONG_ULSPACE );
532 pBindings->Update( SID_ATTR_LONG_LRSPACE );
533 pBindings->Update( SID_RULER_PAGE_POS );
534 pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
535 pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
536 pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
537 pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
538 pBindings->Update( SID_RULER_OBJECT );
539 pBindings->Update( SID_RULER_PROTECT );
542 Ruler::MouseMove( rMEvt );
544 RulerSelection aSelection = GetHoverSelection();
546 if (aSelection.eType == RulerType::DontKnow)
548 SetQuickHelpText(u""_ustr);
549 return;
552 RulerUnitData aUnitData = GetCurrentRulerUnit();
553 double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
554 sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor));
555 OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr);
557 switch (aSelection.eType)
559 case RulerType::Indent:
561 if (!mxParaItem)
562 break;
564 tools::Long nIndex = aSelection.nAryPos + INDENT_GAP;
566 tools::Long nIndentValue = 0.0;
567 if (nIndex == INDENT_LEFT_MARGIN)
568 nIndentValue = mxParaItem->ResolveTextLeft({});
569 else if (nIndex == INDENT_FIRST_LINE)
570 nIndentValue = mxParaItem->ResolveTextFirstLineOffset({});
571 else if (nIndex == INDENT_RIGHT_MARGIN)
572 nIndentValue = mxParaItem->ResolveRight({});
574 double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
575 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
577 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
578 break;
580 case RulerType::Border:
582 if (mxColumnItem == nullptr)
583 break;
585 SvxColumnItem& aColumnItem = *mxColumnItem;
587 if (aSelection.nAryPos + 1 >= aColumnItem.Count())
588 break;
590 double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
591 fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces);
592 double fEnd = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
593 fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces);
595 SetQuickHelpText(
596 OUString::number(fStart) + " " + sUnit + " - " +
597 OUString::number(fEnd) + " " + sUnit );
598 break;
600 case RulerType::Margin1:
602 tools::Long nLeft = 0.0;
603 if (mxLRSpaceItem)
604 nLeft = mxLRSpaceItem->GetLeft();
605 else if (mxULSpaceItem)
606 nLeft = mxULSpaceItem->GetUpper();
607 else
608 break;
610 double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
611 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
612 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
614 break;
616 case RulerType::Margin2:
618 tools::Long nRight = 0.0;
619 if (mxLRSpaceItem)
620 nRight = mxLRSpaceItem->GetRight();
621 else if (mxULSpaceItem)
622 nRight = mxULSpaceItem->GetLower();
623 else
624 break;
626 double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
627 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
628 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
630 break;
632 default:
634 SetQuickHelpText(u""_ustr);
635 break;
640 void SvxRuler::StartListening_Impl()
642 if(!bListening)
644 bValid = false;
645 StartListening(*pBindings);
646 bListening = true;
650 void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace
652 /* Store new value LRSpace; delete old ones if possible */
653 if(bActive)
655 if(pItem)
656 mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem));
657 else
658 mxLRSpaceItem.reset();
659 StartListening_Impl();
663 void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax
665 /* Set new value for MinMax; delete old ones if possible */
666 if(bActive)
668 if(pItem)
669 mxMinMaxItem.reset(new SfxRectangleItem(*pItem));
670 else
671 mxMinMaxItem.reset();
676 void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value
678 /* Update Right/bottom margin */
679 if(bActive && !bHorz)
681 if(pItem)
682 mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem));
683 else
684 mxULSpaceItem.reset();
685 StartListening_Impl();
689 void SvxRuler::Update( const SvxProtectItem* pItem )
691 if( pItem )
692 mxRulerImpl->aProtectItem.reset(pItem->Clone());
695 void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem)
697 if(bActive && bHorz)
699 mxRulerImpl->pTextRTLItem.reset();
700 if(pItem)
701 mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem));
702 SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue());
703 StartListening_Impl();
707 void SvxRuler::Update(
708 const SvxColumnItem *pItem, // new value
709 sal_uInt16 nSID) //Slot Id to identify NULL items
711 /* Set new value for column view */
712 if(!bActive)
713 return;
715 if(pItem)
717 mxColumnItem.reset(new SvxColumnItem(*pItem));
718 mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL);
719 if(!bHorz && !mxRulerImpl->bIsTableRows)
720 mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL);
722 else if(mxColumnItem && mxColumnItem->Which() == nSID)
723 //there are two groups of column items table/frame columns and table rows
724 //both can occur in vertical or horizontal mode
725 //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL
726 //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS
727 //if mxColumnItem is already set with one of the ids then a NULL pItem argument
728 //must not delete it
730 mxColumnItem.reset();
731 mxRulerImpl->bIsTableRows = false;
733 StartListening_Impl();
737 void SvxRuler::UpdateColumns()
739 /* Update column view */
740 if(mxColumnItem && mxColumnItem->Count() > 1)
742 mpBorders.resize(mxColumnItem->Count());
744 RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable;
746 bool bProtectColumns =
747 mxRulerImpl->aProtectItem->IsSizeProtected() ||
748 mxRulerImpl->aProtectItem->IsPosProtected();
750 if( !bProtectColumns )
752 nStyleFlags |= RulerBorderStyle::Moveable;
753 if( !mxColumnItem->IsTable() )
754 nStyleFlags |= RulerBorderStyle::Sizeable;
757 sal_uInt16 nBorders = mxColumnItem->Count();
759 if(!mxRulerImpl->bIsTableRows)
760 --nBorders;
762 for(sal_uInt16 i = 0; i < nBorders; ++i)
764 mpBorders[i].nStyle = nStyleFlags;
765 if(!mxColumnItem->At(i).bVisible)
766 mpBorders[i].nStyle |= RulerBorderStyle::Invisible;
768 mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset);
770 if(mxColumnItem->Count() == i + 1)
772 //with table rows the end of the table is contained in the
773 //column item but it has no width!
774 mpBorders[i].nWidth = 0;
776 else
778 mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd);
780 mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset);
781 mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset);
783 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
785 else
787 SetBorders();
791 void SvxRuler::UpdateObject()
793 /* Update view of object representation */
794 if (mxObjectItem)
796 DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer");
797 // !! to the page margin
798 tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
799 mpObjectBorders[0].nPos =
800 ConvertPosPixel(mxObjectItem->GetStartX() -
801 nMargin + lAppNullOffset);
802 mpObjectBorders[1].nPos =
803 ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset);
804 nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
805 mpObjectBorders[2].nPos =
806 ConvertPosPixel(mxObjectItem->GetStartY() -
807 nMargin + lAppNullOffset);
808 mpObjectBorders[3].nPos =
809 ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset);
811 const sal_uInt16 nOffset = GetObjectBordersOff(0);
812 SetBorders(2, mpObjectBorders.data() + nOffset);
814 else
816 SetBorders();
820 void SvxRuler::UpdatePara()
823 /* Update the view for paragraph indents:
824 Left margin, first line indent, right margin paragraph update
825 mpIndents[0] = Buffer for old intent
826 mpIndents[1] = Buffer for old intent
827 mpIndents[INDENT_FIRST_LINE] = first line indent
828 mpIndents[INDENT_LEFT_MARGIN] = left margin
829 mpIndents[INDENT_RIGHT_MARGIN] = right margin
832 // Dependence on PagePosItem
833 if (mxParaItem && mxPagePosItem && !mxObjectItem)
835 bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
836 // First-line indent is negative to the left paragraph margin
837 tools::Long nLeftFrameMargin = GetLeftFrameMargin();
838 tools::Long nRightFrameMargin = GetRightFrameMargin();
839 SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin));
840 SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin));
842 tools::Long leftMargin;
843 tools::Long leftFirstLine;
844 tools::Long rightMargin;
846 if(bRTLText)
848 leftMargin = nRightFrameMargin - mxParaItem->ResolveTextLeft({}) + lAppNullOffset;
849 leftFirstLine = leftMargin - mxParaItem->ResolveTextFirstLineOffset({});
850 rightMargin = nLeftFrameMargin + mxParaItem->ResolveRight({}) + lAppNullOffset;
852 else
854 leftMargin = nLeftFrameMargin + mxParaItem->ResolveTextLeft({}) + lAppNullOffset;
855 leftFirstLine = leftMargin + mxParaItem->ResolveTextFirstLineOffset({});
856 rightMargin = nRightFrameMargin - mxParaItem->ResolveRight({}) + lAppNullOffset;
859 mpIndents[INDENT_LEFT_MARGIN].nPos = ConvertHPosPixel(leftMargin);
860 mpIndents[INDENT_FIRST_LINE].nPos = ConvertHPosPixel(leftFirstLine);
861 mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin);
863 mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst();
865 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
867 else
869 if(!mpIndents.empty())
871 mpIndents[INDENT_FIRST_LINE].nPos = 0;
872 mpIndents[INDENT_LEFT_MARGIN].nPos = 0;
873 mpIndents[INDENT_RIGHT_MARGIN].nPos = 0;
875 SetIndents(); // turn off
879 void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents
881 /* Store new value of paragraph indents */
882 if(bActive)
884 if(pItem)
885 mxParaItem.reset(new SvxLRSpaceItem(*pItem));
886 else
887 mxParaItem.reset();
888 StartListening_Impl();
892 void SvxRuler::UpdateBorder(const SvxLRSpaceItem * pItem)
894 /* Border distance */
895 if(bActive)
897 if (pItem)
898 mxBorderItem.reset(new SvxLRSpaceItem(*pItem));
899 else
900 mxBorderItem.reset();
902 StartListening_Impl();
906 void SvxRuler::UpdatePage()
908 /* Update view of position and width of page */
909 if (mxPagePosItem)
911 // all objects are automatically adjusted
912 if(bHorz)
914 SetPagePos(
915 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(),
916 pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)).
917 Width());
919 else
921 SetPagePos(
922 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(),
923 pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())).
924 Height());
926 if(bAppSetNullOffset)
927 SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset));
929 else
931 SetPagePos();
934 tools::Long lPos = 0;
935 Point aOwnPos = GetPosPixel();
936 Point aEdtWinPos = pEditWin->GetPosPixel();
937 if( AllSettings::GetLayoutRTL() && bHorz )
939 //#i73321# in RTL the window and the ruler is not mirrored but the
940 // influence of the vertical ruler is inverted
941 Size aOwnSize = GetSizePixel();
942 Size aEdtWinSize = pEditWin->GetSizePixel();
943 lPos = aOwnSize.Width() - aEdtWinSize.Width();
944 lPos -= (aEdtWinPos - aOwnPos).X();
946 else
948 Point aPos(aEdtWinPos - aOwnPos);
949 lPos = bHorz ? aPos.X() : aPos.Y();
952 // Unfortunately, we get the offset of the edit window to the ruler never
953 // through a status message. So we set it ourselves if necessary.
954 if(lPos != mxRulerImpl->lOldWinPos)
956 mxRulerImpl->lOldWinPos=lPos;
957 SetWinPos(lPos);
961 void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes
963 /* Store new value of page attributes */
964 if(bActive)
966 if(pItem)
967 mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem));
968 else
969 mxPagePosItem.reset();
970 StartListening_Impl();
974 void SvxRuler::SetDefTabDist(tools::Long inDefTabDist) // New distance for DefaultTabs in App-Metrics
976 if (lAppNullOffset == LONG_MAX)
977 UpdateFrame(); // hack: try to get lAppNullOffset initialized
978 /* New distance is set for DefaultTabs */
979 lDefTabDist = inDefTabDist;
980 if( !lDefTabDist )
981 lDefTabDist = 1;
983 UpdateTabs();
986 static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj)
988 /* Internal conversion routine between SV-Tab.-Enum and Svx */
989 switch(eAdj) {
990 case SvxTabAdjust::Left: return RULER_TAB_LEFT;
991 case SvxTabAdjust::Right: return RULER_TAB_RIGHT;
992 case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL;
993 case SvxTabAdjust::Center: return RULER_TAB_CENTER;
994 case SvxTabAdjust::Default: return RULER_TAB_DEFAULT;
995 default: ; //prevent warning
997 return 0;
1000 static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj)
1002 switch(eAdj) {
1003 case RULER_TAB_LEFT: return SvxTabAdjust::Left ;
1004 case RULER_TAB_RIGHT: return SvxTabAdjust::Right ;
1005 case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ;
1006 case RULER_TAB_CENTER: return SvxTabAdjust::Center ;
1007 case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ;
1009 return SvxTabAdjust::Left;
1012 void SvxRuler::UpdateTabs()
1014 if(IsDrag())
1015 return;
1017 if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem)
1019 // buffer for DefaultTabStop
1020 // Distance last Tab <-> Right paragraph margin / DefaultTabDist
1021 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1023 const tools::Long nLeftFrameMargin = GetLeftFrameMargin();
1024 const tools::Long nRightFrameMargin = GetRightFrameMargin();
1026 //#i24363# tab stops relative to indent
1027 const tools::Long nParaItemTxtLeft = mxParaItem->ResolveTextLeft({});
1029 const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft;
1030 const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft;
1032 const tools::Long lLastTab = mxTabStopItem->Count()
1033 ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos())
1034 : 0;
1035 const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab;
1036 const tools::Long lRightIndent
1037 = ConvertHPosPixel(nRightFrameMargin - mxParaItem->ResolveRight({}));
1039 tools::Long lCurrentDefTabDist = lDefTabDist;
1040 if(mxTabStopItem->GetDefaultDistance())
1041 lCurrentDefTabDist = mxTabStopItem->GetDefaultDistance();
1042 tools::Long nDefTabDist = ConvertHPosPixel(lCurrentDefTabDist);
1044 const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent || nDefTabDist == 0
1046 : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist );
1048 if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize)
1050 // 10 (GAP) in stock
1051 nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP;
1052 mpTabs.resize(nTabBufSize);
1055 nTabCount = 0;
1056 sal_uInt16 j;
1058 const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent);
1060 tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin)
1061 + lAppNullOffset;
1062 if (bRTL)
1064 lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic;
1066 tools::Long lLastTabOffsetLogic = 0;
1067 for(j = 0; j < mxTabStopItem->Count(); ++j)
1069 const SvxTabStop* pTab = &mxTabStopItem->At(j);
1070 lLastTabOffsetLogic = pTab->GetTabPos();
1071 tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic);
1072 mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos);
1073 mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment());
1074 ++nTabCount;
1077 // Adjust to previous-to-first default tab stop
1078 lLastTabOffsetLogic -= lLastTabOffsetLogic % lCurrentDefTabDist;
1080 // fill the rest with default Tabs
1081 for (j = 0; j < nDefTabBuf; ++j)
1083 //simply add the default distance to the last position
1084 lLastTabOffsetLogic += lCurrentDefTabDist;
1085 if (bRTL)
1087 mpTabs[nTabCount + TAB_GAP].nPos =
1088 ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic);
1089 if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix)
1090 break;
1092 else
1094 mpTabs[nTabCount + TAB_GAP].nPos =
1095 ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic);
1096 if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent)
1097 break;
1100 mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT;
1101 ++nTabCount;
1103 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1104 DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small");
1106 else
1108 SetTabs();
1112 void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs
1114 /* Store new value for tabs; delete old ones if possible */
1115 if(!bActive)
1116 return;
1118 if(pItem)
1120 mxTabStopItem.reset(new SvxTabStopItem(*pItem));
1121 if(!bHorz)
1122 mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL);
1124 else
1126 mxTabStopItem.reset();
1128 StartListening_Impl();
1131 void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects
1133 /* Store new value for objects */
1134 if(bActive)
1136 if(pItem)
1137 mxObjectItem.reset(new SvxObjectItem(*pItem));
1138 else
1139 mxObjectItem.reset();
1140 StartListening_Impl();
1144 void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets
1146 lAppNullOffset = lLogicNullOffset - lVal;
1147 bAppSetNullOffset = true;
1148 Ruler::SetNullOffset(ConvertSizePixel(lVal));
1149 Update();
1152 void SvxRuler::CreateJsonNotification(tools::JsonWriter& rJsonWriter)
1154 tools::Long nMargin1 = 0;
1155 tools::Long nMargin2 = 0;
1156 tools::Long nNullOffset = 0;
1157 tools::Long nPageOffset = 0;
1158 tools::Long nPageWidthHeight = 0;
1160 bool bWriter = false;
1162 // Determine if we are a Ruler for Writer or not
1163 if (SfxViewFrame* pFrame = SfxViewFrame::Current())
1165 uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame().GetFrameInterface();
1166 uno::Reference<frame::XModel> xModel = xFrame->getController()->getModel();
1167 uno::Reference<lang::XServiceInfo> xSI(xModel, uno::UNO_QUERY);
1168 if (xSI.is())
1170 bWriter = xSI->supportsService("com.sun.star.text.TextDocument")
1171 || xSI->supportsService("com.sun.star.text.WebDocument")
1172 || xSI->supportsService("com.sun.star.text.GlobalDocument");
1176 if (bWriter)
1178 // In Writer the ruler values need to be converted first from pixel to twips (default logical unit) and then to 100thmm
1179 nMargin1 = convertTwipToMm100(ConvertPosLogic(GetMargin1()));
1180 nMargin2 = convertTwipToMm100(ConvertPosLogic(GetMargin2()));
1181 nNullOffset = convertTwipToMm100(ConvertPosLogic(GetNullOffset()));
1182 nPageOffset = convertTwipToMm100(ConvertPosLogic(GetPageOffset()));
1183 nPageWidthHeight = convertTwipToMm100(GetPageWidth());
1185 else
1187 // Only convert from pixel to default logical unit, which is 100thmm for Impress
1188 nMargin1 = ConvertPosLogic(GetMargin1());
1189 nMargin2 = ConvertPosLogic(GetMargin2());
1190 nPageOffset = ConvertPosLogic(GetPageOffset());
1192 // In LOKit API we expect the ruler 0,0 coordinate is where the document starts.
1193 // In Impress and Draw the ruler 0,0 is where the canvas starts, not where the document starts.
1194 // The margin to the document is 1 document width (on the left and right) and 0.5 document height
1195 // (on the top and bottom).
1196 // So the canvas width = 3 * document width, canvas height = 2 * document height
1197 if (isHorizontal())
1199 nPageWidthHeight = GetPageWidth() / 3;
1200 nNullOffset = ConvertPosLogic(GetNullOffset()) - nPageWidthHeight;
1202 else
1204 nPageWidthHeight = GetPageWidth() / 2;
1205 nNullOffset = ConvertPosLogic(GetNullOffset()) - (nPageWidthHeight / 2);
1209 rJsonWriter.put("margin1", nMargin1);
1210 rJsonWriter.put("margin2", nMargin2);
1211 rJsonWriter.put("leftOffset", nNullOffset);
1212 rJsonWriter.put("pageOffset", nPageOffset);
1213 rJsonWriter.put("pageWidth", nPageWidthHeight);
1216 auto tabsNode = rJsonWriter.startNode("tabs");
1218 // The RulerTab array elements that GetTabs() returns have their nPos field in twips. So these
1219 // too are actual mm100.
1220 for (auto const& tab : GetTabs())
1222 auto tabNode = rJsonWriter.startNode("");
1223 rJsonWriter.put("position", convertTwipToMm100(tab.nPos));
1224 rJsonWriter.put("style", tab.nStyle);
1228 RulerUnitData aUnitData = GetCurrentRulerUnit();
1229 rJsonWriter.put("unit", aUnitData.aUnitStr);
1232 void SvxRuler::NotifyKit()
1234 if (!comphelper::LibreOfficeKit::isActive())
1235 return;
1236 SfxViewShell* pViewShell = SfxViewShell::Current();
1237 if (!pViewShell)
1238 return;
1240 tools::JsonWriter aJsonWriter;
1241 CreateJsonNotification(aJsonWriter);
1242 OString pJsonData = aJsonWriter.finishAndGetAsOString();
1243 LibreOfficeKitCallbackType eType = isHorizontal() ? LOK_CALLBACK_RULER_UPDATE : LOK_CALLBACK_VERTICAL_RULER_UPDATE;
1244 pViewShell->libreOfficeKitViewCallback(eType, pJsonData);
1247 void SvxRuler::Update()
1249 /* Perform update of view */
1250 if(IsDrag())
1251 return;
1253 UpdatePage();
1254 UpdateFrame();
1255 if(nFlags & SvxRulerSupportFlags::OBJECT)
1256 UpdateObject();
1257 else
1258 UpdateColumns();
1260 if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
1261 UpdatePara();
1263 if(nFlags & SvxRulerSupportFlags::TABS)
1264 UpdateTabs();
1266 NotifyKit();
1269 tools::Long SvxRuler::GetPageWidth() const
1271 if (!mxPagePosItem)
1272 return 0;
1273 return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
1276 inline tools::Long SvxRuler::GetFrameLeft() const
1278 /* Get Left margin in Pixels */
1279 return bAppSetNullOffset ?
1280 GetMargin1() + ConvertSizePixel(lLogicNullOffset) :
1281 Ruler::GetNullOffset();
1284 tools::Long SvxRuler::GetFirstLineIndent() const
1286 /* Get First-line indent in pixels */
1287 return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1();
1290 tools::Long SvxRuler::GetLeftIndent() const
1292 /* Get Left paragraph margin in Pixels */
1293 return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1();
1296 tools::Long SvxRuler::GetRightIndent() const
1298 /* Get Right paragraph margin in Pixels */
1299 return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2();
1302 tools::Long SvxRuler::GetLogicRightIndent() const
1304 /* Get Right paragraph margin in Logic */
1305 return mxParaItem ? GetRightFrameMargin() - mxParaItem->ResolveRight({})
1306 : GetRightFrameMargin();
1309 // Left margin in App values, is either the margin (= 0) or the left edge of
1310 // the column that is set in the column attribute as current column.
1311 tools::Long SvxRuler::GetLeftFrameMargin() const
1313 // #126721# for some unknown reason the current column is set to 0xffff
1314 DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(),
1315 "issue #126721# - invalid current column!");
1316 tools::Long nLeft = 0;
1317 if (mxColumnItem &&
1318 mxColumnItem->Count() &&
1319 mxColumnItem->IsConsistent())
1321 nLeft = mxColumnItem->GetActiveColumnDescription().nStart;
1324 if (mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
1325 nLeft += mxBorderItem->ResolveLeft({});
1327 return nLeft;
1330 inline tools::Long SvxRuler::GetLeftMin() const
1332 DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1333 if (mxMinMaxItem)
1335 if (bHorz)
1336 return mxMinMaxItem->GetValue().Left();
1337 else
1338 return mxMinMaxItem->GetValue().Top();
1340 return 0;
1343 inline tools::Long SvxRuler::GetRightMax() const
1345 DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1346 if (mxMinMaxItem)
1348 if (bHorz)
1349 return mxMinMaxItem->GetValue().Right();
1350 else
1351 return mxMinMaxItem->GetValue().Bottom();
1353 return 0;
1357 tools::Long SvxRuler::GetRightFrameMargin() const
1359 /* Get right frame margin (in logical units) */
1360 if (mxColumnItem)
1362 if (!IsActLastColumn(true))
1364 return mxColumnItem->At(GetActRightColumn(true)).nEnd;
1368 tools::Long lResult = lLogicNullOffset;
1370 // If possible deduct right table entry
1371 if(mxColumnItem && mxColumnItem->IsTable())
1372 lResult += mxColumnItem->GetRight();
1373 else if(bHorz && mxLRSpaceItem)
1374 lResult += mxLRSpaceItem->GetRight();
1375 else if(!bHorz && mxULSpaceItem)
1376 lResult += mxULSpaceItem->GetLower();
1378 if (bHorz && mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
1379 lResult += mxBorderItem->ResolveRight({});
1381 if(bHorz)
1382 lResult = mxPagePosItem->GetWidth() - lResult;
1383 else
1384 lResult = mxPagePosItem->GetHeight() - lResult;
1386 return lResult;
1389 #define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \
1390 SvxRulerSupportFlags::NEGATIVE_MARGINS )
1391 #define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() )
1393 tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight )
1396 Corrects the position within the calculated limits. The limit values are in
1397 pixels relative to the page edge.
1400 const tools::Long lNullPix = Ruler::GetNullOffset();
1401 tools::Long lDragPos = GetDragPos() + lNullPix;
1402 bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows;
1403 if((bLeft || bHoriRows) && lDragPos < nMaxLeft)
1404 lDragPos = nMaxLeft;
1405 else if((bRight||bHoriRows) && lDragPos > nMaxRight)
1406 lDragPos = nMaxRight;
1407 return lDragPos - lNullPix;
1410 static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs
1411 RulerTab* pTabs, // Tab buffer
1412 tools::Long lDiff) // difference to be added
1414 /* Helper function, move all the tabs by a fixed value */
1415 if( pTabs )
1417 for(sal_uInt16 i = 0; i < nCount; ++i)
1419 pTabs[i].nPos += lDiff;
1424 void SvxRuler::DragMargin1()
1426 /* Dragging the left edge of frame */
1427 tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG );
1429 aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false);
1431 // Check if position changed
1432 if (aDragPosition == 0)
1433 return;
1435 DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz);
1436 if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1437 DragBorders();
1438 AdjustMargin1(aDragPosition);
1441 void SvxRuler::AdjustMargin1(tools::Long lInputDiff)
1443 const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset();
1444 const tools::Long lDragPos = lInputDiff;
1446 bool bProtectColumns =
1447 mxRulerImpl->aProtectItem->IsSizeProtected() ||
1448 mxRulerImpl->aProtectItem->IsPosProtected();
1450 const RulerMarginStyle nMarginStyle =
1451 bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1453 if(!bAppSetNullOffset)
1455 tools::Long lDiff = lDragPos;
1456 SetNullOffset(nOld + lDiff);
1457 if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
1459 SetMargin2( GetMargin2() - lDiff, nMarginStyle );
1461 if (!mxColumnItem && !mxObjectItem && mxParaItem)
1463 // Right indent of the old position
1464 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1465 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1467 if (mxObjectItem)
1469 mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff;
1470 mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff;
1471 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1473 if (mxColumnItem)
1475 for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i)
1476 mpBorders[i].nPos -= lDiff;
1477 SetBorders(mxColumnItem->Count()-1, mpBorders.data());
1478 if(mxColumnItem->IsFirstAct())
1480 // Right indent of the old position
1481 if (mxParaItem)
1483 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1484 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1487 else
1489 if (mxParaItem)
1491 mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1492 mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff;
1493 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1494 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1497 if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1498 &&!IsActFirstColumn())
1500 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff);
1501 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1506 else
1508 tools::Long lDiff = lDragPos - nOld;
1509 SetMargin1(nOld + lDiff, nMarginStyle);
1511 if (!mxColumnItem
1512 || !(nDragType
1513 & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR
1514 | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
1516 if (!mxColumnItem && !mxObjectItem && mxParaItem)
1518 // Left indent of the old position
1519 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1520 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1521 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1524 if (mxColumnItem)
1526 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
1527 mpBorders[i].nPos += lDiff;
1528 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1529 if (mxColumnItem->IsFirstAct())
1531 // Left indent of the old position
1532 if (mxParaItem)
1534 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1535 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1536 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1539 else
1541 if (mxParaItem)
1543 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1544 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1545 mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff;
1546 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1550 if (mxTabStopItem)
1552 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff);
1553 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1559 void SvxRuler::DragMargin2()
1561 /* Dragging the right edge of frame */
1562 tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG);
1563 aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false);
1564 tools::Long lDiff = aDragPosition - GetMargin2();
1566 // Check if position changed
1567 if (lDiff == 0)
1568 return;
1570 if( mxRulerImpl->bIsTableRows &&
1571 !bHorz &&
1572 mxColumnItem &&
1573 (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1575 DragBorders();
1578 bool bProtectColumns =
1579 mxRulerImpl->aProtectItem->IsSizeProtected() ||
1580 mxRulerImpl->aProtectItem->IsPosProtected();
1582 const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1584 SetMargin2( aDragPosition, nMarginStyle );
1586 // Right indent of the old position
1587 if ((!mxColumnItem || IsActLastColumn()) && mxParaItem)
1589 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1590 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1593 DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz);
1596 void SvxRuler::DragIndents()
1598 /* Dragging the paragraph indents */
1599 tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos();
1600 const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP;
1602 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1604 if(nIndex == INDENT_RIGHT_MARGIN)
1605 aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin());
1606 else
1607 aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
1609 const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition;
1611 // Check if position changed
1612 if (lDiff == 0)
1613 return;
1615 if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN ) &&
1616 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
1618 mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1621 mpIndents[nIndex].nPos = aDragPosition;
1623 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1624 DrawLine_Impl(lTabPos, 1, bHorz);
1627 void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal)
1630 Output routine for the ledger line when moving tabs, tables and other
1631 columns
1633 if(bHorizontal)
1635 const tools::Long nHeight = pEditWin->GetOutDev()->GetOutputSize().Height();
1636 Point aZero = pEditWin->GetMapMode().GetOrigin();
1637 if(lTabPosition != -1)
1639 pEditWin->InvertTracking(
1640 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1641 Point(lTabPosition, -aZero.Y() + nHeight)),
1642 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1644 if( nNew & 1 )
1646 tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 );
1647 nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1648 lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() );
1649 if (mxPagePosItem)
1650 lTabPosition += mxPagePosItem->GetPos().X();
1651 pEditWin->InvertTracking(
1652 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1653 Point(lTabPosition, -aZero.Y() + nHeight) ),
1654 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1657 else
1659 const tools::Long nWidth = pEditWin->GetOutDev()->GetOutputSize().Width();
1660 Point aZero = pEditWin->GetMapMode().GetOrigin();
1661 if(lTabPosition != -1)
1663 pEditWin->InvertTracking(
1664 tools::Rectangle( Point(-aZero.X(), lTabPosition),
1665 Point(-aZero.X() + nWidth, lTabPosition)),
1666 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1669 if(nNew & 1)
1671 tools::Long nDrapPosition = GetCorrectedDragPos();
1672 nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1673 lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset());
1674 if (mxPagePosItem)
1675 lTabPosition += mxPagePosItem->GetPos().Y();
1676 pEditWin->InvertTracking(
1677 tools::Rectangle( Point(-aZero.X(), lTabPosition),
1678 Point(-aZero.X()+nWidth, lTabPosition)),
1679 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1684 void SvxRuler::DragTabs()
1686 /* Dragging of Tabs */
1687 tools::Long aDragPosition = GetCorrectedDragPos(true, false);
1688 aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin());
1690 sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP;
1691 tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos;
1692 if (nDiff == 0)
1693 return;
1695 DrawLine_Impl(lTabPos, 7, bHorz);
1697 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1700 for(sal_uInt16 i = nIdx; i < nTabCount; ++i)
1702 mpTabs[i].nPos += nDiff;
1703 // limit on maximum
1704 if(mpTabs[i].nPos > GetMargin2())
1705 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1706 else
1707 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1710 else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1712 mxRulerImpl->nTotalDist -= nDiff;
1713 mpTabs[nIdx].nPos = aDragPosition;
1714 for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
1716 if(mpTabs[i].nStyle & RULER_TAB_DEFAULT)
1717 // can be canceled at the DefaultTabs
1718 break;
1719 tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i];
1720 nDelta /= 1000;
1721 mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta;
1722 if(mpTabs[i].nPos + GetNullOffset() > nMaxRight)
1723 mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE;
1724 else
1725 mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE;
1728 else
1730 mpTabs[nIdx].nPos = aDragPosition;
1733 if(IsDragDelete())
1734 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1735 else
1736 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1737 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1740 void SvxRuler::SetActive(bool bOn)
1742 if(bOn)
1744 Activate();
1746 else
1747 Deactivate();
1748 if(bActive!=bOn)
1750 pBindings->EnterRegistrations();
1751 if(bOn)
1752 for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++)
1753 pCtrlItems[i]->ReBind();
1754 else
1755 for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++)
1756 pCtrlItems[j]->UnBind();
1757 pBindings->LeaveRegistrations();
1759 bActive = bOn;
1762 void SvxRuler::UpdateParaContents_Impl(
1763 tools::Long lDifference,
1764 UpdateType eType) // Art (all, left or right)
1766 /* Helper function; carry Tabs and Paragraph Margins */
1767 switch(eType)
1769 case UpdateType::MoveRight:
1770 mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference;
1771 break;
1772 case UpdateType::MoveLeft:
1774 mpIndents[INDENT_FIRST_LINE].nPos += lDifference;
1775 mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference;
1776 if (!mpTabs.empty())
1778 for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i)
1780 mpTabs[i].nPos += lDifference;
1782 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1784 break;
1787 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1790 void SvxRuler::DragBorders()
1792 /* Dragging of Borders (Tables and other columns) */
1793 bool bLeftIndentsCorrected = false;
1794 bool bRightIndentsCorrected = false;
1795 int nIndex;
1797 if(GetDragType() == RulerType::Border)
1799 DrawLine_Impl(lTabPos, 7, bHorz);
1800 nIndex = GetDragAryPos();
1802 else
1804 nIndex = 0;
1807 RulerDragSize nDragSize = GetDragSize();
1808 tools::Long lDiff = 0;
1810 // the drag position has to be corrected to be able to prevent borders from passing each other
1811 tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1813 switch(nDragSize)
1815 case RulerDragSize::Move:
1817 if(GetDragType() == RulerType::Border)
1818 lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos;
1819 else
1820 lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin;
1822 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1824 tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters
1825 for(int i = mpBorders.size() - 2; i >= nIndex; --i)
1827 tools::Long l = mpBorders[i].nPos;
1828 mpBorders[i].nPos += lDiff;
1829 mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth);
1830 nRight = mpBorders[i].nPos - glMinFrame;
1831 // RR update the column
1832 if(i == GetActRightColumn())
1834 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1835 bRightIndentsCorrected = true;
1837 // LAR, EZE update the column
1838 else if(i == GetActLeftColumn())
1840 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1841 bLeftIndentsCorrected = true;
1845 else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1847 int nLimit;
1848 tools::Long lLeft;
1849 int nStartLimit = mpBorders.size() - 2;
1850 switch(GetDragType())
1852 default: ;//prevent warning
1853 OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" );
1854 [[fallthrough]];
1855 case RulerType::Border:
1856 if(mxRulerImpl->bIsTableRows)
1858 mpBorders[nIndex].nPos += lDiff;
1859 if(bHorz)
1861 lLeft = mpBorders[nIndex].nPos;
1862 mxRulerImpl->nTotalDist -= lDiff;
1863 nLimit = nIndex + 1;
1865 else
1867 lLeft = 0;
1868 nStartLimit = nIndex - 1;
1869 mxRulerImpl->nTotalDist += lDiff;
1870 nLimit = 0;
1873 else
1875 nLimit = nIndex + 1;
1876 mpBorders[nIndex].nPos += lDiff;
1877 lLeft = mpBorders[nIndex].nPos;
1878 mxRulerImpl->nTotalDist -= lDiff;
1880 break;
1881 case RulerType::Margin1:
1882 nLimit = 0;
1883 lLeft = mxRulerImpl->lLastLMargin + lDiff;
1884 mxRulerImpl->nTotalDist -= lDiff;
1885 break;
1886 case RulerType::Margin2:
1887 nLimit = 0;
1888 lLeft= 0;
1889 nStartLimit = mpBorders.size() - 2;
1890 mxRulerImpl->nTotalDist += lDiff;
1891 break;
1894 for(int i = nStartLimit; i >= nLimit; --i)
1897 tools::Long l = mpBorders[i].nPos;
1898 mpBorders[i].nPos =
1899 lLeft +
1900 (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 +
1901 mxRulerImpl->pBlockBuf[i];
1903 // RR update the column
1904 if(!mxRulerImpl->bIsTableRows)
1906 if(i == GetActRightColumn())
1908 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1909 bRightIndentsCorrected = true;
1911 // LAR, EZE update the column
1912 else if(i == GetActLeftColumn())
1914 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1915 bLeftIndentsCorrected = true;
1919 if(mxRulerImpl->bIsTableRows)
1921 //in vertical tables the left borders have to be moved
1922 if(bHorz)
1924 for(int i = 0; i < nIndex; ++i)
1925 mpBorders[i].nPos += lDiff;
1926 AdjustMargin1(lDiff);
1928 else
1930 //otherwise the right borders are moved
1931 for(int i = mxColumnItem->Count() - 1; i > nIndex; --i)
1932 mpBorders[i].nPos += lDiff;
1933 SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1937 else if(mxRulerImpl->bIsTableRows)
1939 //moving rows: if a row is resized all following rows
1940 //have to be moved by the same amount.
1941 //This includes the left border when the table is not limited
1942 //to a lower frame border.
1943 int nLimit;
1944 if(GetDragType()==RulerType::Border)
1946 nLimit = nIndex + 1;
1947 mpBorders[nIndex].nPos += lDiff;
1949 else
1951 nLimit=0;
1953 //in vertical tables the left borders have to be moved
1954 if(bHorz)
1956 for(int i = 0; i < nIndex; ++i)
1958 mpBorders[i].nPos += lDiff;
1960 AdjustMargin1(lDiff);
1962 else
1964 //otherwise the right borders are moved
1965 for(int i = mpBorders.size() - 2; i >= nLimit; --i)
1967 mpBorders[i].nPos += lDiff;
1969 SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1972 else
1973 mpBorders[nIndex].nPos += lDiff;
1974 break;
1976 case RulerDragSize::N1:
1978 lDiff = lPos - mpBorders[nIndex].nPos;
1979 mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos;
1980 mpBorders[nIndex].nPos = lPos;
1981 break;
1983 case RulerDragSize::N2:
1985 const tools::Long nOld = mpBorders[nIndex].nWidth;
1986 mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos;
1987 lDiff = mpBorders[nIndex].nWidth - nOld;
1988 break;
1991 if(!bRightIndentsCorrected &&
1992 GetActRightColumn() == nIndex &&
1993 nDragSize != RulerDragSize::N2 &&
1994 !mpIndents.empty() &&
1995 !mxRulerImpl->bIsTableRows)
1997 UpdateParaContents_Impl(lDiff, UpdateType::MoveRight);
1999 else if(!bLeftIndentsCorrected &&
2000 GetActLeftColumn() == nIndex &&
2001 nDragSize != RulerDragSize::N1 &&
2002 !mpIndents.empty())
2004 UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft);
2006 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
2009 void SvxRuler::DragObjectBorder()
2011 /* Dragging of object edges */
2012 if(RulerDragSize::Move == GetDragSize())
2014 const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
2016 const sal_uInt16 nIdx = GetDragAryPos();
2017 mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition;
2018 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
2019 DrawLine_Impl(lTabPos, 7, bHorz);
2024 void SvxRuler::ApplyMargins()
2026 /* Applying margins; changed by dragging. */
2027 const SfxPoolItem* pItem = nullptr;
2028 sal_uInt16 nId = SID_ATTR_LONG_LRSPACE;
2030 if(bHorz)
2032 const tools::Long lOldNull = lLogicNullOffset;
2033 if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset())
2035 lLogicNullOffset = mxRulerImpl->lMaxLeftLogic;
2036 mxLRSpaceItem->SetLeft(lLogicNullOffset);
2038 else
2040 lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset;
2041 mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft()));
2044 if(bAppSetNullOffset)
2046 lAppNullOffset += lLogicNullOffset - lOldNull;
2049 tools::Long nRight;
2050 if(mxRulerImpl->lMaxRightLogic != -1
2051 && nMaxRight == GetMargin2() + Ruler::GetNullOffset())
2053 nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic;
2055 else
2057 nRight = std::max(tools::Long(0),
2058 mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() -
2059 (ConvertHPosLogic(GetMargin2()) - lAppNullOffset));
2061 nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight());
2063 mxLRSpaceItem->SetRight(nRight);
2065 pItem = mxLRSpaceItem.get();
2067 #ifdef DEBUGLIN
2068 Debug_Impl(pEditWin, *mxLRSpaceItem);
2069 #endif // DEBUGLIN
2072 else
2074 const tools::Long lOldNull = lLogicNullOffset;
2075 lLogicNullOffset =
2076 ConvertVPosLogic(GetFrameLeft()) -
2077 lAppNullOffset;
2078 mxULSpaceItem->SetUpper(
2079 PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper()));
2080 if(bAppSetNullOffset)
2082 lAppNullOffset += lLogicNullOffset - lOldNull;
2084 mxULSpaceItem->SetLower(
2085 PixelVAdjust(
2086 std::max(tools::Long(0), mxPagePosItem->GetHeight() -
2087 mxULSpaceItem->GetUpper() -
2088 (ConvertVPosLogic(GetMargin2()) -
2089 lAppNullOffset)), mxULSpaceItem->GetLower()));
2090 pItem = mxULSpaceItem.get();
2091 nId = SID_ATTR_LONG_ULSPACE;
2093 #ifdef DEBUGLIN
2094 Debug_Impl(pEditWin,*mxULSpaceItem);
2095 #endif // DEBUGLIN
2098 pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem });
2099 if (mxTabStopItem)
2100 UpdateTabs();
2103 tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const
2105 RulerUnitData aUnitData = GetCurrentRulerUnit();
2106 double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
2108 tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
2109 lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit;
2110 return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width();
2113 void SvxRuler::ApplyIndents()
2115 /* Applying paragraph settings; changed by dragging. */
2117 tools::Long nLeftFrameMargin = GetLeftFrameMargin();
2119 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2121 tools::Long nNewTxtLeft;
2122 tools::Long nNewFirstLineOffset;
2123 tools::Long nNewRight;
2125 tools::Long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos);
2126 tools::Long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos);
2127 tools::Long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos);
2129 if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true))))
2131 if(bRTL)
2133 tools::Long nRightColumn = GetActRightColumn(true);
2134 tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2135 nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2137 else
2139 tools::Long nLeftColumn = GetActLeftColumn(true);
2140 tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2141 nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset;
2144 else
2146 if(bRTL)
2148 tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2149 nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2151 else
2153 tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2154 nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset;
2158 if(bRTL)
2159 nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset;
2160 else
2161 nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset;
2163 if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true))))
2165 if(bRTL)
2167 tools::Long nLeftColumn = GetActLeftColumn(true);
2168 tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2169 nNewRight = nRightMargin - nLeftBorder - lAppNullOffset;
2171 else
2173 tools::Long nRightColumn = GetActRightColumn(true);
2174 tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2175 nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2178 else
2180 if(bRTL)
2182 tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2183 nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset;
2185 else
2187 tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2188 nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2192 if (mbSnapping)
2194 nNewTxtLeft = RoundToCurrentMapMode(nNewTxtLeft);
2195 nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset);
2196 nNewRight = RoundToCurrentMapMode(nNewRight);
2199 mxParaItem->SetTextFirstLineOffset(SvxIndentValue::twips(nNewFirstLineOffset));
2200 mxParaItem->SetTextLeft(SvxIndentValue::twips(nNewTxtLeft));
2201 mxParaItem->SetRight(SvxIndentValue::twips(nNewRight));
2203 sal_uInt16 nParagraphId = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL;
2204 pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD,
2205 { mxParaItem.get() });
2206 UpdateTabs();
2209 void SvxRuler::ApplyTabs()
2211 /* Apply tab settings, changed by dragging. */
2212 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2213 const sal_uInt16 nCoreIdx = GetDragAryPos();
2214 if(IsDragDelete())
2216 mxTabStopItem->Remove(nCoreIdx);
2218 else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType ||
2219 SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType)
2221 SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which());
2222 //remove default tab stops
2223 for ( sal_uInt16 i = 0; i < pItem->Count(); )
2225 if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() )
2227 pItem->Remove(i);
2228 continue;
2230 ++i;
2233 sal_uInt16 j;
2234 for(j = 0; j < nCoreIdx; ++j)
2236 pItem->Insert(mxTabStopItem->At(j));
2238 for(; j < mxTabStopItem->Count(); ++j)
2240 SvxTabStop aTabStop = mxTabStopItem->At(j);
2241 aTabStop.GetTabPos() = PixelHAdjust(
2242 ConvertHPosLogic(
2243 mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset,
2244 aTabStop.GetTabPos());
2245 pItem->Insert(aTabStop);
2247 mxTabStopItem.reset(pItem);
2249 else if( mxTabStopItem->Count() == 0 )
2250 return;
2251 else
2253 SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx);
2254 if( mxRulerImpl->lMaxRightLogic != -1 &&
2255 mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight )
2257 // Set tab pos exactly at the right indent
2258 tools::Long nTmpLeftIndentLogic
2259 = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
2260 if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem)
2262 nTmpLeftIndentLogic
2263 += bRTL ? mxParaItem->ResolveRight({}) : mxParaItem->ResolveTextLeft({});
2265 aTabStop.GetTabPos()
2266 = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic;
2268 else
2270 if(bRTL)
2272 //#i24363# tab stops relative to indent
2273 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2274 GetLeftIndent() :
2275 ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset );
2277 tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos);
2278 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2280 else
2282 //#i24363# tab stops relative to indent
2283 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2284 GetLeftIndent() :
2285 ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset );
2287 tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent);
2288 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2291 mxTabStopItem->Remove(nCoreIdx);
2292 mxTabStopItem->Insert(aTabStop);
2294 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
2295 pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD,
2296 { mxTabStopItem.get() });
2297 UpdateTabs();
2300 void SvxRuler::ApplyBorders()
2302 /* Applying (table) column settings; changed by dragging. */
2303 if(mxColumnItem->IsTable())
2305 tools::Long lValue = GetFrameLeft();
2306 if(lValue != mxRulerImpl->nColLeftPix)
2308 tools::Long nLeft = PixelHAdjust(
2309 ConvertHPosLogic(lValue) -
2310 lAppNullOffset,
2311 mxColumnItem->GetLeft());
2312 mxColumnItem->SetLeft(nLeft);
2315 lValue = GetMargin2();
2317 if(lValue != mxRulerImpl->nColRightPix)
2319 tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
2320 tools::Long nRight = PixelHAdjust(
2321 nWidthOrHeight -
2322 mxColumnItem->GetLeft() -
2323 ConvertHPosLogic(lValue) -
2324 lAppNullOffset,
2325 mxColumnItem->GetRight() );
2326 mxColumnItem->SetRight(nRight);
2330 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
2332 tools::Long& nEnd = mxColumnItem->At(i).nEnd;
2333 nEnd = PixelHAdjust(
2334 ConvertPosLogic(mpBorders[i].nPos),
2335 mxColumnItem->At(i).nEnd);
2336 tools::Long& nStart = mxColumnItem->At(i + 1).nStart;
2337 nStart = PixelHAdjust(
2338 ConvertSizeLogic(mpBorders[i].nPos +
2339 mpBorders[i].nWidth) -
2340 lAppNullOffset,
2341 mxColumnItem->At(i + 1).nStart);
2342 // It may be that, due to the PixelHAdjust readjustment to old values,
2343 // the width becomes < 0. This we readjust.
2344 if( nEnd > nStart )
2345 nStart = nEnd;
2348 #ifdef DEBUGLIN
2349 Debug_Impl(pEditWin,*mxColumnItem);
2350 #endif // DEBUGLIN
2352 SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY,
2353 bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY));
2355 sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) :
2356 (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2358 pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD,
2359 { mxColumnItem.get(), &aFlag });
2362 void SvxRuler::ApplyObject()
2364 /* Applying object settings, changed by dragging. */
2366 // to the page margin
2367 tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
2368 tools::Long nStartX = PixelAdjust(
2369 ConvertPosLogic(mpObjectBorders[0].nPos) +
2370 nMargin -
2371 lAppNullOffset,
2372 mxObjectItem->GetStartX());
2373 mxObjectItem->SetStartX(nStartX);
2375 tools::Long nEndX = PixelAdjust(
2376 ConvertPosLogic(mpObjectBorders[1].nPos) +
2377 nMargin -
2378 lAppNullOffset,
2379 mxObjectItem->GetEndX());
2380 mxObjectItem->SetEndX(nEndX);
2382 nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
2383 tools::Long nStartY = PixelAdjust(
2384 ConvertPosLogic(mpObjectBorders[2].nPos) +
2385 nMargin -
2386 lAppNullOffset,
2387 mxObjectItem->GetStartY());
2388 mxObjectItem->SetStartY(nStartY);
2390 tools::Long nEndY = PixelAdjust(
2391 ConvertPosLogic(mpObjectBorders[3].nPos) +
2392 nMargin -
2393 lAppNullOffset,
2394 mxObjectItem->GetEndY());
2395 mxObjectItem->SetEndY(nEndY);
2397 pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT,
2398 SfxCallMode::RECORD, { mxObjectItem.get() });
2401 void SvxRuler::PrepareProportional_Impl(RulerType eType)
2404 Preparation proportional dragging, and it is calculated based on the
2405 proportional share of the total width in parts per thousand.
2407 mxRulerImpl->nTotalDist = GetMargin2();
2408 switch(eType)
2410 case RulerType::Margin2:
2411 case RulerType::Margin1:
2412 case RulerType::Border:
2414 DBG_ASSERT(mxColumnItem, "no ColumnItem");
2416 mxRulerImpl->SetPercSize(mxColumnItem->Count());
2418 tools::Long lPos;
2419 tools::Long lWidth=0;
2420 sal_uInt16 nStart;
2421 sal_uInt16 nIdx=GetDragAryPos();
2422 tools::Long lActWidth=0;
2423 tools::Long lActBorderSum;
2424 tools::Long lOrigLPos;
2426 if(eType != RulerType::Border)
2428 lOrigLPos = GetMargin1();
2429 nStart = 0;
2430 lActBorderSum = 0;
2432 else
2434 if(mxRulerImpl->bIsTableRows &&!bHorz)
2436 lOrigLPos = GetMargin1();
2437 nStart = 0;
2439 else
2441 lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth;
2442 nStart = 1;
2444 lActBorderSum = mpBorders[nIdx].nWidth;
2447 //in horizontal mode the percentage value has to be
2448 //calculated on a "current change" position base
2449 //because the height of the table changes while dragging
2450 if(mxRulerImpl->bIsTableRows && RulerType::Border == eType)
2452 sal_uInt16 nStartBorder;
2453 sal_uInt16 nEndBorder;
2454 if(bHorz)
2456 nStartBorder = nIdx + 1;
2457 nEndBorder = mxColumnItem->Count() - 1;
2459 else
2461 nStartBorder = 0;
2462 nEndBorder = nIdx;
2465 lWidth = mpBorders[nIdx].nPos;
2466 if(bHorz)
2467 lWidth = GetMargin2() - lWidth;
2468 mxRulerImpl->nTotalDist = lWidth;
2469 lPos = mpBorders[nIdx].nPos;
2471 for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i)
2473 if(bHorz)
2475 lActWidth += mpBorders[i].nPos - lPos;
2476 lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2478 else
2479 lActWidth = mpBorders[i].nPos;
2480 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2481 / mxRulerImpl->nTotalDist);
2482 mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2483 lActBorderSum += mpBorders[i].nWidth;
2486 else
2488 lPos = lOrigLPos;
2489 for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii)
2491 lWidth += mpBorders[ii].nPos - lPos;
2492 lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth;
2495 lWidth += GetMargin2() - lPos;
2496 mxRulerImpl->nTotalDist = lWidth;
2497 lPos = lOrigLPos;
2499 for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i)
2501 lActWidth += mpBorders[i].nPos - lPos;
2502 lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2503 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2504 / mxRulerImpl->nTotalDist);
2505 mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2506 lActBorderSum += mpBorders[i].nWidth;
2510 break;
2511 case RulerType::Tab:
2513 const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP;
2514 mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos;
2515 mxRulerImpl->SetPercSize(nTabCount);
2516 for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ;
2517 for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
2519 const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos;
2520 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist);
2522 break;
2524 default: break;
2528 void SvxRuler::EvalModifier()
2531 Eval Drag Modifier
2532 Shift: move linear
2533 Control: move proportional
2534 Shift + Control: Table: only current line
2535 Alt: disable snapping
2536 Alt + Shift: coarse snapping
2539 sal_uInt16 nModifier = GetDragModifier();
2540 if(mxRulerImpl->bIsTableRows)
2542 //rows can only be moved in one way, additionally current column is possible
2543 if(nModifier == KEY_SHIFT)
2544 nModifier = 0;
2547 switch(nModifier)
2549 case KEY_SHIFT:
2550 nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR;
2551 break;
2552 case KEY_MOD2 | KEY_SHIFT:
2553 mbCoarseSnapping = true;
2554 break;
2555 case KEY_MOD2:
2556 mbSnapping = false;
2557 break;
2558 case KEY_MOD1:
2560 const RulerType eType = GetDragType();
2561 nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL;
2562 if( RulerType::Tab == eType ||
2563 ( ( RulerType::Border == eType ||
2564 RulerType::Margin1 == eType ||
2565 RulerType::Margin2 == eType ) &&
2566 mxColumnItem ) )
2568 PrepareProportional_Impl(eType);
2571 break;
2572 case KEY_MOD1 | KEY_SHIFT:
2573 if( GetDragType() != RulerType::Margin1 &&
2574 GetDragType() != RulerType::Margin2 )
2576 nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY;
2578 break;
2582 void SvxRuler::Click()
2584 /* Override handler SV; sets Tab per dispatcher call */
2585 Ruler::Click();
2586 if( bActive )
2588 pBindings->Update( SID_RULER_LR_MIN_MAX );
2589 pBindings->Update( SID_ATTR_LONG_ULSPACE );
2590 pBindings->Update( SID_ATTR_LONG_LRSPACE );
2591 pBindings->Update( SID_RULER_PAGE_POS );
2592 pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
2593 pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
2594 pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2595 pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
2596 pBindings->Update( SID_RULER_OBJECT );
2597 pBindings->Update( SID_RULER_PROTECT );
2598 pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL );
2600 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2601 if(!(mxTabStopItem &&
2602 (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS))
2603 return;
2605 bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
2606 if( bContentProtected ) return;
2607 const tools::Long lPos = GetClickPos();
2608 if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) ||
2609 (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())))
2610 return;
2612 //convert position in left-to-right text
2613 tools::Long nTabPos;
2614 //#i24363# tab stops relative to indent
2615 if(bRTL)
2616 nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ?
2617 GetLeftIndent() :
2618 ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) -
2619 lPos;
2620 else
2621 nTabPos = lPos -
2622 ( mxRulerImpl->bIsTabsRelativeToIndent ?
2623 GetLeftIndent() :
2624 ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ));
2626 SvxTabStop aTabStop(ConvertHPosLogic(nTabPos),
2627 ToAttrTab_Impl(nDefTabType));
2628 mxTabStopItem->Insert(aTabStop);
2629 UpdateTabs();
2632 void SvxRuler::CalcMinMax()
2635 Calculates the limits for dragging; which are in pixels relative to the
2636 page edge
2638 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2639 const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset);
2640 mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1;
2641 switch(GetDragType())
2643 case RulerType::Margin1:
2644 { // left edge of the surrounding Frame
2645 // DragPos - NOf between left - right
2646 mxRulerImpl->lMaxLeftLogic = GetLeftMin();
2647 nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic);
2649 if (!mxColumnItem || mxColumnItem->Count() == 1)
2651 if(bRTL)
2653 nMaxRight = lNullPix - GetRightIndent() +
2654 std::max(GetFirstLineIndent(), GetLeftIndent()) -
2655 glMinFrame;
2657 else
2659 nMaxRight = lNullPix + GetRightIndent() -
2660 std::max(GetFirstLineIndent(), GetLeftIndent()) -
2661 glMinFrame;
2664 else if(mxRulerImpl->bIsTableRows)
2666 //top border is not moveable when table rows are displayed
2667 // protection of content means the margin is not moveable
2668 if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected())
2670 nMaxLeft = mpBorders[0].nMinPos + lNullPix;
2671 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2672 nMaxRight = GetRightIndent() + lNullPix -
2673 (mxColumnItem->Count() - 1 ) * glMinFrame;
2674 else
2675 nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix;
2677 else
2678 nMaxLeft = nMaxRight = lNullPix;
2680 else
2682 if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2684 nMaxRight=lNullPix+CalcPropMaxRight();
2686 else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
2688 nMaxRight = ConvertPosPixel(
2689 GetPageWidth() - (
2690 (mxColumnItem->IsTable() && mxLRSpaceItem)
2691 ? mxLRSpaceItem->GetRight() : 0))
2692 - GetMargin2() + GetMargin1();
2694 else
2696 nMaxRight = lNullPix - glMinFrame;
2697 if (mxColumnItem->IsFirstAct())
2699 if(bRTL)
2701 nMaxRight += std::min(
2702 mpBorders[0].nPos,
2703 std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent());
2705 else
2707 nMaxRight += std::min(
2708 mpBorders[0].nPos, GetRightIndent() -
2709 std::max(GetFirstLineIndent(), GetLeftIndent()));
2712 else if ( mxColumnItem->Count() > 1 )
2714 nMaxRight += mpBorders[0].nPos;
2716 else
2718 nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent());
2720 // Do not drag the left table edge over the edge of the page
2721 if(mxLRSpaceItem && mxColumnItem->IsTable())
2723 tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft());
2724 if(nTmp>nMaxLeft)
2725 nMaxLeft=nTmp;
2729 break;
2731 case RulerType::Margin2:
2732 { // right edge of the surrounding Frame
2733 mxRulerImpl->lMaxRightLogic
2734 = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth();
2735 nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
2737 if (!mxColumnItem)
2739 if(bRTL)
2741 nMaxLeft = GetMargin2() + GetRightIndent() -
2742 std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
2743 glMinFrame + lNullPix;
2745 else
2747 nMaxLeft = GetMargin2() - GetRightIndent() +
2748 std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
2749 glMinFrame + lNullPix;
2752 else if(mxRulerImpl->bIsTableRows)
2754 // get the bottom move range from the last border position - only available for rows!
2755 // protection of content means the margin is not moveable
2756 if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected())
2758 nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix;
2760 else
2762 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2764 nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix;
2766 else
2768 if(mxColumnItem->Count() > 1)
2769 nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix;
2770 else
2771 nMaxLeft = glMinFrame + lNullPix;
2773 if(mxColumnItem->Count() > 1)
2774 nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix;
2775 else
2776 nMaxRight -= GetRightIndent() - lNullPix;
2779 else
2781 nMaxLeft = glMinFrame + lNullPix;
2782 if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column
2784 if(bRTL)
2786 nMaxLeft = glMinFrame + lNullPix + GetMargin2() +
2787 GetRightIndent() - std::max(GetFirstLineIndent(),
2788 GetLeftIndent());
2790 else
2792 nMaxLeft = glMinFrame + lNullPix + GetMargin2() -
2793 GetRightIndent() + std::max(GetFirstLineIndent(),
2794 GetLeftIndent());
2797 if( mxColumnItem->Count() >= 2 )
2799 tools::Long nNewMaxLeft =
2800 glMinFrame + lNullPix +
2801 mpBorders[mxColumnItem->Count() - 2].nPos +
2802 mpBorders[mxColumnItem->Count() - 2].nWidth;
2803 nMaxLeft = std::max(nMaxLeft, nNewMaxLeft);
2807 break;
2809 case RulerType::Border:
2810 { // Table, column (Modifier)
2811 const sal_uInt16 nIdx = GetDragAryPos();
2812 switch(GetDragSize())
2814 case RulerDragSize::N1 :
2816 nMaxRight = mpBorders[nIdx].nPos +
2817 mpBorders[nIdx].nWidth + lNullPix;
2819 if(0 == nIdx)
2820 nMaxLeft = lNullPix;
2821 else
2822 nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix;
2823 if (mxColumnItem && nIdx == mxColumnItem->GetActColumn())
2825 if(bRTL)
2827 nMaxLeft += mpBorders[nIdx].nPos +
2828 GetRightIndent() - std::max(GetFirstLineIndent(),
2829 GetLeftIndent());
2831 else
2833 nMaxLeft += mpBorders[nIdx].nPos -
2834 GetRightIndent() + std::max(GetFirstLineIndent(),
2835 GetLeftIndent());
2837 if(0 != nIdx)
2838 nMaxLeft -= mpBorders[nIdx-1].nPos +
2839 mpBorders[nIdx-1].nWidth;
2841 nMaxLeft += glMinFrame;
2842 nMaxLeft += nDragOffset;
2843 break;
2845 case RulerDragSize::Move:
2847 if (mxColumnItem)
2849 //nIdx contains the position of the currently moved item
2850 //next visible separator on the left
2851 sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx);
2852 //next visible separator on the right
2853 sal_uInt16 nRightCol=GetActRightColumn(false, nIdx);
2854 //next separator on the left - regardless if visible or not
2855 sal_uInt16 nActLeftCol=GetActLeftColumn();
2856 //next separator on the right - regardless if visible or not
2857 sal_uInt16 nActRightCol=GetActRightColumn();
2858 if(mxColumnItem->IsTable())
2860 if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)
2862 //the current row/column should be modified only
2863 //then the next/previous visible border position
2864 //marks the min/max positions
2865 nMaxLeft = nLeftCol == USHRT_MAX ?
2867 mpBorders[nLeftCol].nPos;
2868 //rows can always be increased without a limit
2869 if(mxRulerImpl->bIsTableRows)
2870 nMaxRight = mpBorders[nIdx].nMaxPos;
2871 else
2872 nMaxRight = nRightCol == USHRT_MAX ?
2873 GetMargin2():
2874 mpBorders[nRightCol].nPos;
2875 nMaxLeft += lNullPix;
2876 nMaxRight += lNullPix;
2878 else
2880 if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows)
2881 nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix;
2882 else
2883 nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix;
2884 if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2885 (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2887 if(mxRulerImpl->bIsTableRows)
2889 if(bHorz)
2890 nMaxRight = GetRightIndent() + lNullPix -
2891 (mxColumnItem->Count() - nIdx - 1) * glMinFrame;
2892 else
2893 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2895 else
2896 nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2898 else
2899 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2901 nMaxLeft += glMinFrame;
2902 nMaxRight -= glMinFrame;
2905 else
2907 if(nLeftCol==USHRT_MAX)
2908 nMaxLeft=lNullPix;
2909 else
2910 nMaxLeft = mpBorders[nLeftCol].nPos +
2911 mpBorders[nLeftCol].nWidth + lNullPix;
2913 if(nActRightCol == nIdx)
2915 if(bRTL)
2917 nMaxLeft += mpBorders[nIdx].nPos +
2918 GetRightIndent() - std::max(GetFirstLineIndent(),
2919 GetLeftIndent());
2920 if(nActLeftCol!=USHRT_MAX)
2921 nMaxLeft -= mpBorders[nActLeftCol].nPos +
2922 mpBorders[nActLeftCol].nWidth;
2924 else
2926 nMaxLeft += mpBorders[nIdx].nPos -
2927 GetRightIndent() + std::max(GetFirstLineIndent(),
2928 GetLeftIndent());
2929 if(nActLeftCol!=USHRT_MAX)
2930 nMaxLeft -= mpBorders[nActLeftCol].nPos +
2931 mpBorders[nActLeftCol].nWidth;
2934 nMaxLeft += glMinFrame;
2935 nMaxLeft += nDragOffset;
2937 // nMaxRight
2938 // linear / proportional move
2939 if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2940 (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2942 nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2944 else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType)
2946 nMaxRight = lNullPix + GetMargin2() - GetMargin1() +
2947 (mpBorders.size() - nIdx - 1) * glMinFrame;
2949 else
2951 if(nRightCol==USHRT_MAX)
2952 { // last column
2953 nMaxRight = GetMargin2() + lNullPix;
2954 if(IsActLastColumn())
2956 if(bRTL)
2958 nMaxRight -=
2959 GetMargin2() + GetRightIndent() -
2960 std::max(GetFirstLineIndent(),
2961 GetLeftIndent());
2963 else
2965 nMaxRight -=
2966 GetMargin2() - GetRightIndent() +
2967 std::max(GetFirstLineIndent(),
2968 GetLeftIndent());
2970 nMaxRight += mpBorders[nIdx].nPos +
2971 mpBorders[nIdx].nWidth;
2974 else
2976 nMaxRight = lNullPix + mpBorders[nRightCol].nPos;
2977 sal_uInt16 nNotHiddenRightCol =
2978 GetActRightColumn(true, nIdx);
2980 if( nActLeftCol == nIdx )
2982 tools::Long nBorder = nNotHiddenRightCol ==
2983 USHRT_MAX ?
2984 GetMargin2() :
2985 mpBorders[nNotHiddenRightCol].nPos;
2986 if(bRTL)
2988 nMaxRight -= nBorder + GetRightIndent() -
2989 std::max(GetFirstLineIndent(),
2990 GetLeftIndent());
2992 else
2994 nMaxRight -= nBorder - GetRightIndent() +
2995 std::max(GetFirstLineIndent(),
2996 GetLeftIndent());
2998 nMaxRight += mpBorders[nIdx].nPos +
2999 mpBorders[nIdx].nWidth;
3002 nMaxRight -= glMinFrame;
3003 nMaxRight -= mpBorders[nIdx].nWidth;
3007 // ObjectItem
3008 else
3010 nMaxLeft = LONG_MIN;
3011 nMaxRight = LONG_MAX;
3013 break;
3015 case RulerDragSize::N2:
3016 if (mxColumnItem)
3018 nMaxLeft = lNullPix + mpBorders[nIdx].nPos;
3019 if(nIdx == mxColumnItem->Count()-2) { // last column
3020 nMaxRight = GetMargin2() + lNullPix;
3021 if(mxColumnItem->IsLastAct()) {
3022 nMaxRight -=
3023 GetMargin2() - GetRightIndent() +
3024 std::max(GetFirstLineIndent(),
3025 GetLeftIndent());
3026 nMaxRight += mpBorders[nIdx].nPos +
3027 mpBorders[nIdx].nWidth;
3030 else {
3031 nMaxRight = lNullPix + mpBorders[nIdx+1].nPos;
3032 if(mxColumnItem->GetActColumn()-1 == nIdx) {
3033 nMaxRight -= mpBorders[nIdx+1].nPos - GetRightIndent() +
3034 std::max(GetFirstLineIndent(),
3035 GetLeftIndent());
3036 nMaxRight += mpBorders[nIdx].nPos +
3037 mpBorders[nIdx].nWidth;
3040 nMaxRight -= glMinFrame;
3041 nMaxRight -= mpBorders[nIdx].nWidth;
3042 break;
3045 nMaxRight += nDragOffset;
3046 break;
3048 case RulerType::Indent:
3050 const sal_uInt16 nIdx = GetDragAryPos();
3051 switch(nIdx) {
3052 case INDENT_FIRST_LINE - INDENT_GAP:
3053 case INDENT_LEFT_MARGIN - INDENT_GAP:
3055 if(bRTL)
3057 nMaxLeft = lNullPix + GetRightIndent();
3059 if(mxColumnItem && !mxColumnItem->IsFirstAct())
3060 nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
3061 mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
3062 nMaxRight = lNullPix + GetMargin2();
3064 // Dragging along
3065 if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
3066 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
3068 if(GetLeftIndent() > GetFirstLineIndent())
3069 nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
3070 else
3071 nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
3074 else
3076 nMaxLeft = lNullPix;
3078 if(mxColumnItem && !mxColumnItem->IsFirstAct())
3079 nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
3080 mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
3081 nMaxRight = lNullPix + GetRightIndent() - glMinFrame;
3083 // Dragging along
3084 if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
3085 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
3087 if(GetLeftIndent() > GetFirstLineIndent())
3088 nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
3089 else
3090 nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
3094 break;
3095 case INDENT_RIGHT_MARGIN - INDENT_GAP:
3097 if(bRTL)
3099 nMaxLeft = lNullPix;
3100 nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame;
3101 if (mxColumnItem)
3103 sal_uInt16 nRightCol=GetActRightColumn( true );
3104 if(!IsActLastColumn( true ))
3105 nMaxRight += mpBorders[nRightCol].nPos;
3106 else
3107 nMaxRight += GetMargin2();
3109 else
3111 nMaxLeft += GetMargin1();
3113 nMaxLeft += glMinFrame;
3115 else
3117 nMaxLeft = lNullPix +
3118 std::max(GetFirstLineIndent(), GetLeftIndent());
3119 nMaxRight = lNullPix;
3120 if (mxColumnItem)
3122 sal_uInt16 nRightCol=GetActRightColumn( true );
3123 if(!IsActLastColumn( true ))
3124 nMaxRight += mpBorders[nRightCol].nPos;
3125 else
3126 nMaxRight += GetMargin2();
3128 else
3129 nMaxRight += GetMargin2();
3130 nMaxLeft += glMinFrame;
3133 break;
3135 break;
3137 case RulerType::Tab: // Tabs (Modifier)
3138 /* left = NOf + Max(LAR, EZ)
3139 right = NOf + RAR */
3141 if (bRTL)
3142 nMaxLeft = lNullPix + GetRightIndent();
3143 else
3144 nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent());
3146 mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset;
3147 nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
3148 break;
3149 default: ; //prevent warning
3153 bool SvxRuler::StartDrag()
3156 Beginning of a drag operation (SV-handler) evaluates modifier and
3157 calculated values
3159 [Cross-reference]
3161 <SvxRuler::EvalModifier()>
3162 <SvxRuler::CalcMinMax()>
3163 <SvxRuler::EndDrag()>
3165 bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
3167 if(!bValid)
3168 return false;
3170 mxRulerImpl->lLastLMargin = GetMargin1();
3171 mxRulerImpl->lLastRMargin = GetMargin2();
3173 bool bOk = true;
3175 lInitialDragPos = GetDragPos();
3176 switch(GetDragType())
3178 case RulerType::Margin1: // left edge of the surrounding Frame
3179 case RulerType::Margin2: // right edge of the surrounding Frame
3180 if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem))
3182 if (!mxColumnItem)
3183 EvalModifier();
3184 else
3185 nDragType = SvxRulerDragFlags::OBJECT;
3187 else
3189 bOk = false;
3191 break;
3192 case RulerType::Border: // Table, column (Modifier)
3193 if (mxColumnItem)
3195 nDragOffset = 0;
3196 if (!mxColumnItem->IsTable())
3197 nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos;
3198 EvalModifier();
3200 else
3201 nDragOffset = 0;
3202 break;
3203 case RulerType::Indent: // Paragraph indents (Modifier)
3205 if( bContentProtected )
3206 return false;
3207 if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) { // Left paragraph indent
3208 mpIndents[0] = mpIndents[INDENT_FIRST_LINE];
3209 EvalModifier();
3211 else
3213 nDragType = SvxRulerDragFlags::OBJECT;
3215 mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP];
3216 break;
3218 case RulerType::Tab: // Tabs (Modifier)
3219 if( bContentProtected )
3220 return false;
3221 EvalModifier();
3222 mpTabs[0] = mpTabs[GetDragAryPos() + 1];
3223 mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW;
3224 break;
3225 default:
3226 nDragType = SvxRulerDragFlags::NONE;
3229 if(bOk)
3230 CalcMinMax();
3232 return bOk;
3235 void SvxRuler::Drag()
3237 /* SV-Draghandler */
3238 if(IsDragCanceled())
3240 Ruler::Drag();
3241 return;
3243 switch(GetDragType()) {
3244 case RulerType::Margin1: // left edge of the surrounding Frame
3245 DragMargin1();
3246 mxRulerImpl->lLastLMargin = GetMargin1();
3247 break;
3248 case RulerType::Margin2: // right edge of the surrounding Frame
3249 DragMargin2();
3250 mxRulerImpl->lLastRMargin = GetMargin2();
3251 break;
3252 case RulerType::Indent: // Paragraph indents
3253 DragIndents();
3254 break;
3255 case RulerType::Border: // Table, columns
3256 if (mxColumnItem)
3257 DragBorders();
3258 else if (mxObjectItem)
3259 DragObjectBorder();
3260 break;
3261 case RulerType::Tab: // Tabs
3262 DragTabs();
3263 break;
3264 default:
3265 break; //prevent warning
3267 Ruler::Drag();
3270 void SvxRuler::EndDrag()
3273 SV-handler; is called when ending the dragging. Triggers the updating of data
3274 on the application, by calling the respective Apply...() methods to send the
3275 data to the application.
3277 const bool bUndo = IsDragCanceled();
3278 const tools::Long lPos = GetDragPos();
3279 DrawLine_Impl(lTabPos, 6, bHorz);
3280 lTabPos = -1;
3282 if(!bUndo)
3284 switch(GetDragType())
3286 case RulerType::Margin1: // upper left edge of the surrounding Frame
3287 case RulerType::Margin2: // lower right edge of the surrounding Frame
3289 if (!mxColumnItem || !mxColumnItem->IsTable())
3290 ApplyMargins();
3292 if(mxColumnItem &&
3293 (mxColumnItem->IsTable() ||
3294 (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
3295 ApplyBorders();
3298 break;
3299 case RulerType::Border: // Table, columns
3300 if(lInitialDragPos != lPos ||
3301 (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here
3303 if (mxColumnItem)
3305 ApplyBorders();
3306 if(bHorz)
3307 UpdateTabs();
3309 else if (mxObjectItem)
3310 ApplyObject();
3312 break;
3313 case RulerType::Indent: // Paragraph indents
3314 if(lInitialDragPos != lPos)
3315 ApplyIndents();
3316 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
3317 break;
3318 case RulerType::Tab: // Tabs
3320 ApplyTabs();
3321 mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE;
3322 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
3324 break;
3325 default:
3326 break; //prevent warning
3329 nDragType = SvxRulerDragFlags::NONE;
3331 mbCoarseSnapping = false;
3332 mbSnapping = true;
3334 Ruler::EndDrag();
3335 if(bUndo)
3337 for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++)
3339 pCtrlItems[i]->ClearCache();
3340 pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId());
3345 void SvxRuler::ExtraDown()
3347 /* Override SV method, sets the new type for the Default tab. */
3349 // Switch Tab Type
3350 if(mxTabStopItem &&
3351 (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)
3353 ++nDefTabType;
3354 if(RULER_TAB_DEFAULT == nDefTabType)
3355 nDefTabType = RULER_TAB_LEFT;
3356 SetExtraType(RulerExtra::Tab, nDefTabType);
3358 Ruler::ExtraDown();
3361 void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint)
3364 Report through the bindings that the status update is completed. The ruler
3365 updates its appearance and gets registered again in the bindings.
3368 // start update
3369 if (bActive && rHint.GetId() == SfxHintId::UpdateDone)
3371 Update();
3372 EndListening(*pBindings);
3373 bValid = true;
3374 bListening = false;
3378 void SvxRuler::MenuSelect(std::u16string_view ident)
3380 if (ident.empty())
3381 return;
3382 /* Handler of the context menus for switching the unit of measurement */
3383 SetUnit(vcl::EnglishStringToMetric(ident));
3386 void SvxRuler::TabMenuSelect(std::u16string_view rIdent)
3388 if (rIdent.empty())
3389 return;
3390 sal_Int32 nId = o3tl::toInt32(rIdent);
3391 /* Handler of the tab menu for setting the type */
3392 if (mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx)
3394 SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx);
3395 aTabStop.GetAdjustment() = ToAttrTab_Impl(nId - 1);
3396 mxTabStopItem->Remove(mxRulerImpl->nIdx);
3397 mxTabStopItem->Insert(aTabStop);
3398 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
3399 pBindings->GetDispatcher()->ExecuteList(nTabStopId,
3400 SfxCallMode::RECORD, { mxTabStopItem.get() });
3401 UpdateTabs();
3402 mxRulerImpl->nIdx = 0;
3406 const TranslateId RID_SVXSTR_RULER_TAB[] =
3408 RID_SVXSTR_RULER_TAB_LEFT,
3409 RID_SVXSTR_RULER_TAB_RIGHT,
3410 RID_SVXSTR_RULER_TAB_CENTER,
3411 RID_SVXSTR_RULER_TAB_DECIMAL
3414 void SvxRuler::Command( const CommandEvent& rCommandEvent )
3416 /* Mouse context menu for switching the unit of measurement */
3417 if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() )
3419 CancelDrag();
3421 tools::Rectangle aRect(rCommandEvent.GetMousePosPixel(), Size(1, 1));
3422 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
3423 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, u"svx/ui/rulermenu.ui"_ustr));
3424 std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"menu"_ustr));
3426 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
3427 if ( !mpTabs.empty() &&
3428 RulerType::Tab ==
3429 GetRulerType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) &&
3430 mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT )
3432 xMenu->clear();
3434 const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2);
3435 const Point aPt(aSz.Width() / 2, aSz.Height() / 2);
3437 for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i )
3439 ScopedVclPtr<VirtualDevice> xDev(pPopupParent->create_virtual_device());
3440 xDev->SetOutputSize(aSz);
3442 sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i;
3443 nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT);
3445 Color aFillColor(xDev->GetSettings().GetStyleSettings().GetShadowColor());
3446 DrawTab(*xDev, aFillColor, aPt, nStyle);
3448 OUString sId(OUString::number(i + 1));
3449 xMenu->insert(-1, sId, SvxResId(RID_SVXSTR_RULER_TAB[i]),
3450 nullptr, xDev.get(), nullptr, TRISTATE_TRUE);
3451 xMenu->set_active(sId, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle);
3453 TabMenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
3455 else
3457 FieldUnit eUnit = GetUnit();
3458 const int nCount = xMenu->n_children();
3460 bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC);
3461 for ( sal_uInt16 i = nCount; i; --i )
3463 OUString sIdent = xMenu->get_id(i - 1);
3464 FieldUnit eMenuUnit = vcl::EnglishStringToMetric(sIdent);
3465 xMenu->set_active(sIdent, eMenuUnit == eUnit);
3466 if( bReduceMetric )
3468 if (eMenuUnit == FieldUnit::M ||
3469 eMenuUnit == FieldUnit::KM ||
3470 eMenuUnit == FieldUnit::FOOT ||
3471 eMenuUnit == FieldUnit::MILE)
3473 xMenu->remove(sIdent);
3475 else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz )
3477 xMenu->remove(sIdent);
3479 else if (( eMenuUnit == FieldUnit::LINE ) && bHorz )
3481 xMenu->remove(sIdent);
3485 MenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
3488 else
3490 Ruler::Command( rCommandEvent );
3494 sal_uInt16 SvxRuler::GetActRightColumn(
3495 bool bForceDontConsiderHidden,
3496 sal_uInt16 nAct ) const
3498 if( nAct == USHRT_MAX )
3499 nAct = mxColumnItem->GetActColumn();
3500 else
3501 nAct++; //To be able to pass on the ActDrag
3503 bool bConsiderHidden = !bForceDontConsiderHidden &&
3504 !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3506 while( nAct < mxColumnItem->Count() - 1 )
3508 if (mxColumnItem->At(nAct).bVisible || bConsiderHidden)
3509 return nAct;
3510 else
3511 nAct++;
3513 return USHRT_MAX;
3516 sal_uInt16 SvxRuler::GetActLeftColumn(
3517 bool bForceDontConsiderHidden,
3518 sal_uInt16 nAct ) const
3520 if(nAct == USHRT_MAX)
3521 nAct = mxColumnItem->GetActColumn();
3523 sal_uInt16 nLeftOffset = 1;
3525 bool bConsiderHidden = !bForceDontConsiderHidden &&
3526 !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3528 while(nAct >= nLeftOffset)
3530 if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden)
3531 return nAct - nLeftOffset;
3532 else
3533 nLeftOffset++;
3535 return USHRT_MAX;
3538 bool SvxRuler::IsActLastColumn(
3539 bool bForceDontConsiderHidden,
3540 sal_uInt16 nAct) const
3542 return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3545 bool SvxRuler::IsActFirstColumn(
3546 bool bForceDontConsiderHidden,
3547 sal_uInt16 nAct) const
3549 return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3552 tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const
3555 if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
3557 // Remove the minimum width for all affected columns
3558 // starting from the right edge
3559 tools::Long _nMaxRight = GetMargin2() - GetMargin1();
3561 tools::Long lFences = 0;
3562 tools::Long lMinSpace = USHRT_MAX;
3563 tools::Long lOldPos;
3564 tools::Long lColumns = 0;
3566 sal_uInt16 nStart;
3567 if(!mxColumnItem->IsTable())
3569 if(nCol == USHRT_MAX)
3571 lOldPos = GetMargin1();
3572 nStart = 0;
3574 else
3576 lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth;
3577 nStart = nCol + 1;
3578 lFences = mpBorders[nCol].nWidth;
3581 for(size_t i = nStart; i < mpBorders.size() - 1; ++i)
3583 tools::Long lWidth = mpBorders[i].nPos - lOldPos;
3584 lColumns += lWidth;
3585 if(lWidth < lMinSpace)
3586 lMinSpace = lWidth;
3587 lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth;
3588 lFences += mpBorders[i].nWidth;
3590 tools::Long lWidth = GetMargin2() - lOldPos;
3591 lColumns += lWidth;
3592 if(lWidth < lMinSpace)
3593 lMinSpace = lWidth;
3595 else
3597 sal_uInt16 nActCol;
3598 if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin
3600 lOldPos = GetMargin1();
3602 else
3604 lOldPos = mpBorders[nCol].nPos;
3606 lColumns = GetMargin2()-lOldPos;
3607 nActCol = nCol;
3608 lFences = 0;
3609 while(nActCol < mpBorders.size() || nActCol == USHRT_MAX)
3611 sal_uInt16 nRight;
3612 if(nActCol == USHRT_MAX)
3614 nRight = 0;
3615 while (!(*mxColumnItem)[nRight].bVisible)
3617 nRight++;
3620 else
3622 nRight = GetActRightColumn(false, nActCol);
3625 tools::Long lWidth;
3626 if(nRight != USHRT_MAX)
3628 lWidth = mpBorders[nRight].nPos - lOldPos;
3629 lOldPos = mpBorders[nRight].nPos;
3631 else
3633 lWidth=GetMargin2() - lOldPos;
3635 nActCol = nRight;
3636 if(lWidth < lMinSpace)
3637 lMinSpace = lWidth;
3638 if(nActCol == USHRT_MAX)
3639 break;
3643 _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns);
3644 return _nMaxRight;
3646 else
3648 if(mxColumnItem->IsTable())
3650 sal_uInt16 nVisCols = 0;
3651 for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();)
3653 if ((*mxColumnItem)[i].bVisible)
3654 nVisCols++;
3655 i = GetActRightColumn(false, i);
3657 return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame;
3659 else
3661 tools::Long lWidth = 0;
3662 for(size_t i = nCol; i < mpBorders.size() - 1; i++)
3664 lWidth += glMinFrame + mpBorders[i].nWidth;
3666 return GetMargin2() - GetMargin1() - lWidth;
3671 // Tab stops relative to indent (#i24363#)
3672 void SvxRuler::SetTabsRelativeToIndent( bool bRel )
3674 mxRulerImpl->bIsTabsRelativeToIndent = bRel;
3677 void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue)
3679 if (diffValue == 0)
3680 return;
3682 if (type == RulerChangeType::MARGIN1)
3683 AdjustMargin1(diffValue);
3684 else if (type == RulerChangeType::MARGIN2)
3685 SetMargin2( GetMargin2() - diffValue);
3686 ApplyMargins();
3689 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */