Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / dialog / svxruler.cxx
blob66457d3bca1ef949a218d76d58b34072b21536d9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cstring>
21 #include <climits>
23 #include <vcl/builder.hxx>
24 #include <vcl/commandevent.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/fieldvalues.hxx>
27 #include <vcl/image.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/virdev.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 <editeng/editids.hrc>
40 #include <editeng/tstpitem.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/protitem.hxx>
43 #include <osl/diagnose.h>
44 #include <rtl/math.hxx>
46 #include "rlrcitem.hxx"
47 #include <memory>
49 #define CTRL_ITEM_COUNT 14
50 #define GAP 10
51 #define OBJECT_BORDER_COUNT 4
52 #define TAB_GAP 1
53 #define INDENT_GAP 2
54 #define INDENT_FIRST_LINE 2
55 #define INDENT_LEFT_MARGIN 3
56 #define INDENT_RIGHT_MARGIN 4
57 #define INDENT_COUNT 3 //without the first two old values
59 struct SvxRuler_Impl {
60 std::unique_ptr<sal_uInt16[]> pPercBuf;
61 std::unique_ptr<sal_uInt16[]> pBlockBuf;
62 sal_uInt16 nPercSize;
63 tools::Long nTotalDist;
64 tools::Long lOldWinPos;
65 tools::Long lMaxLeftLogic;
66 tools::Long lMaxRightLogic;
67 tools::Long lLastLMargin;
68 tools::Long lLastRMargin;
69 std::unique_ptr<SvxProtectItem> aProtectItem;
70 std::unique_ptr<SfxBoolItem> pTextRTLItem;
71 sal_uInt16 nControllerItems;
72 sal_uInt16 nIdx;
73 sal_uInt16 nColLeftPix;
74 sal_uInt16 nColRightPix; // Pixel values for left / right edge
75 // For columns; buffered to prevent
76 // recalculation errors
77 // May be has to be widen for future values
78 bool bIsTableRows : 1; // mxColumnItem contains table rows instead of columns
79 //#i24363# tab stops relative to indent
80 bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent?
81 // false means relative to SvxRuler::GetLeftFrameMargin()
83 SvxRuler_Impl() :
84 nPercSize(0), nTotalDist(0),
85 lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0),
86 lLastLMargin(0), lLastRMargin(0),
87 aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)),
88 nControllerItems(0), nIdx(0),
89 nColLeftPix(0), nColRightPix(0),
90 bIsTableRows(false),
91 bIsTabsRelativeToIndent(true)
95 void SetPercSize(sal_uInt16 nSize);
99 static RulerTabData ruler_tab_svx =
101 0, // DPIScaleFactor to be set
102 7, // ruler_tab_width
103 6, // ruler_tab_height
104 0, // ruler_tab_height2
105 0, // ruler_tab_width2
106 0, // ruler_tab_cwidth
107 0, // ruler_tab_cwidth2
108 0, // ruler_tab_cwidth3
109 0, // ruler_tab_cwidth4
110 0, // ruler_tab_dheight
111 0, // ruler_tab_dheight2
112 0, // ruler_tab_dwidth
113 0, // ruler_tab_dwidth2
114 0, // ruler_tab_dwidth3
115 0, // ruler_tab_dwidth4
116 0 // ruler_tab_textoff
119 void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize)
121 if(nSize > nPercSize)
123 nPercSize = nSize;
124 pPercBuf.reset( new sal_uInt16[nPercSize] );
125 pBlockBuf.reset( new sal_uInt16[nPercSize] );
127 size_t nSize2 = sizeof(sal_uInt16) * nPercSize;
128 memset(pPercBuf.get(), 0, nSize2);
129 memset(pBlockBuf.get(), 0, nSize2);
132 // Constructor of the ruler
134 // SID_ATTR_ULSPACE, SID_ATTR_LRSPACE
135 // expects as parameter SvxULSpaceItem for page edge
136 // (either left/right or top/bottom)
137 // Ruler: SetMargin1, SetMargin2
139 // SID_RULER_PAGE_POS
140 // expects as parameter the initial value of the page and page width
141 // Ruler: SetPagePos
143 // SID_ATTR_TABSTOP
144 // expects: SvxTabStopItem
145 // Ruler: SetTabs
147 // SID_ATTR_PARA_LRSPACE
148 // left, right paragraph edge in H-ruler
149 // Ruler: SetIndents
151 // SID_RULER_BORDERS
152 // Table borders, columns
153 // expects: something like SwTabCols
154 // Ruler: SetBorders
156 constexpr tools::Long glMinFrame = 5; // minimal frame width in pixels
158 SvxRuler::SvxRuler(
159 vcl::Window* pParent, // StarView Parent
160 vcl::Window* pWin, // Output window: is used for conversion
161 // logical units <-> pixels
162 SvxRulerSupportFlags flags, // Display flags, see ruler.hxx
163 SfxBindings &rBindings, // associated Bindings
164 WinBits nWinStyle) : // StarView WinBits
165 Ruler(pParent, nWinStyle),
166 pCtrlItems(CTRL_ITEM_COUNT),
167 pEditWin(pWin),
168 mxRulerImpl(new SvxRuler_Impl),
169 bAppSetNullOffset(false), // Is the 0-offset of the ruler set by the application?
170 lLogicNullOffset(0),
171 lAppNullOffset(LONG_MAX),
172 lInitialDragPos(0),
173 nFlags(flags),
174 nDragType(SvxRulerDragFlags::NONE),
175 nDefTabType(RULER_TAB_LEFT),
176 nTabCount(0),
177 nTabBufSize(0),
178 lDefTabDist(50),
179 lTabPos(-1),
180 mpBorders(1), // due to one column tables
181 pBindings(&rBindings),
182 nDragOffset(0),
183 nMaxLeft(0),
184 nMaxRight(0),
185 bValid(false),
186 bListening(false),
187 bActive(true),
188 mbCoarseSnapping(false),
189 mbSnapping(true)
192 /* Constructor; Initialize data buffer; controller items are created */
194 rBindings.EnterRegistrations();
196 // Create Supported Items
197 sal_uInt16 i = 0;
199 // Page edges
200 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings));
201 if((nWinStyle & WB_VSCROLL) == WB_VSCROLL)
203 bHorz = false;
204 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings));
206 else
208 bHorz = true;
209 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings));
212 // Page Position
213 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings));
215 if(nFlags & SvxRulerSupportFlags::TABS)
217 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
218 pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings));
219 SetExtraType(RulerExtra::Tab, nDefTabType);
222 if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
224 if(bHorz)
225 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings));
226 else
227 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings));
229 mpIndents.resize(5 + INDENT_GAP);
231 for(RulerIndent & rIndent : mpIndents)
233 rIndent.nPos = 0;
234 rIndent.nStyle = RulerIndentStyle::Top;
237 mpIndents[0].nStyle = RulerIndentStyle::Top;
238 mpIndents[1].nStyle = RulerIndentStyle::Top;
239 mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top;
240 mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom;
241 mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom;
244 if( (nFlags & SvxRulerSupportFlags::BORDERS) == SvxRulerSupportFlags::BORDERS )
246 pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings));
247 pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings));
250 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings));
252 if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT )
254 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings));
255 mpObjectBorders.resize(OBJECT_BORDER_COUNT);
256 for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder)
258 mpObjectBorders[nBorder].nPos = 0;
259 mpObjectBorders[nBorder].nWidth = 0;
260 mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable;
264 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings));
265 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings));
266 mxRulerImpl->nControllerItems=i;
268 if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET )
269 SetExtraType(RulerExtra::NullOffset);
271 rBindings.LeaveRegistrations();
273 ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor();
274 ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor;
275 ruler_tab_svx.width *= ruler_tab_svx.DPIScaleFactor;
279 SvxRuler::~SvxRuler()
281 disposeOnce();
284 void SvxRuler::dispose()
286 /* Destructor ruler; release internal buffer */
287 if(bListening)
288 EndListening(*pBindings);
290 pBindings->EnterRegistrations();
292 pCtrlItems.clear();
294 pBindings->LeaveRegistrations();
296 pEditWin.clear();
297 Ruler::dispose();
300 tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const
302 tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference);
303 tools::Long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin());
304 tools::Long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin());
306 double aTick = GetCurrentRulerUnit().nTick1;
308 if (mbCoarseSnapping)
309 aTick = GetCurrentRulerUnit().nTick2;
311 tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width();
313 double aHalfTick = aTick / 2.0;
314 double aHalfTickPixel = aTickPixel / 2.0;
316 if (aSnapToFrameMargin)
318 if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel)
319 return aLeftFramePosition;
321 if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel)
322 return aRightFramePosition;
325 if (!mbSnapping)
326 return aPosition;
328 // Move "coordinate system" to frame position so ticks are calculated correctly
329 tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel;
330 // Convert position to current selected map mode
331 tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width();
332 // Normalize -- snap to nearest tick
333 aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick;
334 // Convert back to pixels
335 aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width();
336 // Move "coordinate system" back to original position
337 return aPosition + aPointOfReferencePixel;
340 tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const
342 return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
345 tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const
347 return pEditWin->LogicToPixel(Size(0, nVal)).Height();
350 tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const
352 return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
355 tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const
357 return pEditWin->LogicToPixel(Size(0, nVal)).Height();
360 tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const
362 return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal);
365 tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const
367 return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal);
370 inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const
372 return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
375 inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const
377 return pEditWin->PixelToLogic(Size(0, nVal)).Height();
380 inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const
382 return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
385 inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const
387 return pEditWin->PixelToLogic(Size(0, nVal)).Height();
390 inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const
392 return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal);
395 inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const
397 return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal);
400 tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const
402 if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld))
403 return nVal;
404 else
405 return nValOld;
408 tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const
410 if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld))
411 return nVal;
412 else
413 return nValOld;
416 tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const
418 if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld))
419 return nVal;
420 else
421 return nValOld;
424 inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const
426 return bHorz ? nIdx : nIdx + 2;
430 Update Upper Left edge.
431 Items are translated into the representation of the ruler.
433 void SvxRuler::UpdateFrame()
435 const RulerMarginStyle nMarginStyle =
436 ( mxRulerImpl->aProtectItem->IsSizeProtected() ||
437 mxRulerImpl->aProtectItem->IsPosProtected() ) ?
438 RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
440 if(mxLRSpaceItem && mxPagePosItem)
442 // if no initialization by default app behavior
443 const tools::Long nOld = lLogicNullOffset;
444 lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft();
446 if(bAppSetNullOffset)
448 lAppNullOffset += lLogicNullOffset - nOld;
451 if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
453 Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset));
454 SetMargin1(0, nMarginStyle);
455 lAppNullOffset = 0;
457 else
459 SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle);
462 tools::Long lRight = 0;
464 // evaluate the table right edge of the table
465 if(mxColumnItem && mxColumnItem->IsTable())
466 lRight = mxColumnItem->GetRight();
467 else
468 lRight = mxLRSpaceItem->GetRight();
470 tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset;
471 tools::Long aWidthPixel = ConvertHPosPixel(aWidth);
473 SetMargin2(aWidthPixel, nMarginStyle);
475 else if(mxULSpaceItem && mxPagePosItem)
477 // relative the upper edge of the surrounding frame
478 const tools::Long nOld = lLogicNullOffset;
479 lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper();
481 if(bAppSetNullOffset)
483 lAppNullOffset += lLogicNullOffset - nOld;
486 if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
488 Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset));
489 lAppNullOffset = 0;
490 SetMargin1(0, nMarginStyle);
492 else
494 SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle);
497 tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower();
498 tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset;
499 tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2);
501 SetMargin2(nMargin2Pixel, nMarginStyle);
503 else
505 // turns off the view
506 SetMargin1();
507 SetMargin2();
510 if (mxColumnItem)
512 mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft()));
513 mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight()));
517 void SvxRuler::MouseMove( const MouseEvent& rMEvt )
519 if( bActive )
521 pBindings->Update( SID_RULER_LR_MIN_MAX );
522 pBindings->Update( SID_ATTR_LONG_ULSPACE );
523 pBindings->Update( SID_ATTR_LONG_LRSPACE );
524 pBindings->Update( SID_RULER_PAGE_POS );
525 pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
526 pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
527 pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
528 pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
529 pBindings->Update( SID_RULER_OBJECT );
530 pBindings->Update( SID_RULER_PROTECT );
533 Ruler::MouseMove( rMEvt );
535 RulerSelection aSelection = GetHoverSelection();
537 if (aSelection.eType == RulerType::DontKnow)
539 SetQuickHelpText("");
540 return;
543 RulerUnitData aUnitData = GetCurrentRulerUnit();
544 double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
545 sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor));
546 OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr);
548 switch (aSelection.eType)
550 case RulerType::Indent:
552 if (!mxParaItem)
553 break;
555 tools::Long nIndex = aSelection.nAryPos + INDENT_GAP;
557 tools::Long nIndentValue = 0.0;
558 if (nIndex == INDENT_LEFT_MARGIN)
559 nIndentValue = mxParaItem->GetTextLeft();
560 else if (nIndex == INDENT_FIRST_LINE)
561 nIndentValue = mxParaItem->GetTextFirstLineOffset();
562 else if (nIndex == INDENT_RIGHT_MARGIN)
563 nIndentValue = mxParaItem->GetRight();
565 double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
566 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
568 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
569 break;
571 case RulerType::Border:
573 if (mxColumnItem == nullptr)
574 break;
576 SvxColumnItem& aColumnItem = *mxColumnItem;
578 if (aSelection.nAryPos + 1 >= aColumnItem.Count())
579 break;
581 double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
582 fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces);
583 double fEnd = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
584 fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces);
586 SetQuickHelpText(
587 OUString::number(fStart) + " " + sUnit + " - " +
588 OUString::number(fEnd) + " " + sUnit );
589 break;
591 case RulerType::Margin1:
593 tools::Long nLeft = 0.0;
594 if (mxLRSpaceItem)
595 nLeft = mxLRSpaceItem->GetLeft();
596 else if (mxULSpaceItem)
597 nLeft = mxULSpaceItem->GetUpper();
598 else
599 break;
601 double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
602 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
603 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
605 break;
607 case RulerType::Margin2:
609 tools::Long nRight = 0.0;
610 if (mxLRSpaceItem)
611 nRight = mxLRSpaceItem->GetRight();
612 else if (mxULSpaceItem)
613 nRight = mxULSpaceItem->GetLower();
614 else
615 break;
617 double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
618 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
619 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
621 break;
623 default:
625 SetQuickHelpText("");
626 break;
631 void SvxRuler::StartListening_Impl()
633 if(!bListening)
635 bValid = false;
636 StartListening(*pBindings);
637 bListening = true;
641 void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace
643 /* Store new value LRSpace; delete old ones if possible */
644 if(bActive)
646 if(pItem)
647 mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem));
648 else
649 mxLRSpaceItem.reset();
650 StartListening_Impl();
654 void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax
656 /* Set new value for MinMax; delete old ones if possible */
657 if(bActive)
659 if(pItem)
660 mxMinMaxItem.reset(new SfxRectangleItem(*pItem));
661 else
662 mxMinMaxItem.reset();
667 void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value
669 /* Update Right/bottom margin */
670 if(bActive && !bHorz)
672 if(pItem)
673 mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem));
674 else
675 mxULSpaceItem.reset();
676 StartListening_Impl();
680 void SvxRuler::Update( const SvxProtectItem* pItem )
682 if( pItem )
683 mxRulerImpl->aProtectItem.reset(pItem->Clone());
686 void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem)
688 if(bActive && bHorz)
690 mxRulerImpl->pTextRTLItem.reset();
691 if(pItem)
692 mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem));
693 SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue());
694 StartListening_Impl();
698 void SvxRuler::Update(
699 const SvxColumnItem *pItem, // new value
700 sal_uInt16 nSID) //Slot Id to identify NULL items
702 /* Set new value for column view */
703 if(!bActive)
704 return;
706 if(pItem)
708 mxColumnItem.reset(new SvxColumnItem(*pItem));
709 mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL);
710 if(!bHorz && !mxRulerImpl->bIsTableRows)
711 mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL);
713 else if(mxColumnItem && mxColumnItem->Which() == nSID)
714 //there are two groups of column items table/frame columns and table rows
715 //both can occur in vertical or horizontal mode
716 //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL
717 //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS
718 //if mxColumnItem is already set with one of the ids then a NULL pItem argument
719 //must not delete it
721 mxColumnItem.reset();
722 mxRulerImpl->bIsTableRows = false;
724 StartListening_Impl();
728 void SvxRuler::UpdateColumns()
730 /* Update column view */
731 if(mxColumnItem && mxColumnItem->Count() > 1)
733 mpBorders.resize(mxColumnItem->Count());
735 RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable;
737 bool bProtectColumns =
738 mxRulerImpl->aProtectItem->IsSizeProtected() ||
739 mxRulerImpl->aProtectItem->IsPosProtected();
741 if( !bProtectColumns )
743 nStyleFlags |= RulerBorderStyle::Moveable;
744 if( !mxColumnItem->IsTable() )
745 nStyleFlags |= RulerBorderStyle::Sizeable;
748 sal_uInt16 nBorders = mxColumnItem->Count();
750 if(!mxRulerImpl->bIsTableRows)
751 --nBorders;
753 for(sal_uInt16 i = 0; i < nBorders; ++i)
755 mpBorders[i].nStyle = nStyleFlags;
756 if(!mxColumnItem->At(i).bVisible)
757 mpBorders[i].nStyle |= RulerBorderStyle::Invisible;
759 mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset);
761 if(mxColumnItem->Count() == i + 1)
763 //with table rows the end of the table is contained in the
764 //column item but it has no width!
765 mpBorders[i].nWidth = 0;
767 else
769 mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd);
771 mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset);
772 mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset);
774 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
776 else
778 SetBorders();
782 void SvxRuler::UpdateObject()
784 /* Update view of object representation */
785 if (mxObjectItem)
787 DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer");
788 // !! to the page margin
789 tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
790 mpObjectBorders[0].nPos =
791 ConvertPosPixel(mxObjectItem->GetStartX() -
792 nMargin + lAppNullOffset);
793 mpObjectBorders[1].nPos =
794 ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset);
795 nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
796 mpObjectBorders[2].nPos =
797 ConvertPosPixel(mxObjectItem->GetStartY() -
798 nMargin + lAppNullOffset);
799 mpObjectBorders[3].nPos =
800 ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset);
802 const sal_uInt16 nOffset = GetObjectBordersOff(0);
803 SetBorders(2, mpObjectBorders.data() + nOffset);
805 else
807 SetBorders();
811 void SvxRuler::UpdatePara()
814 /* Update the view for paragraph indents:
815 Left margin, first line indent, right margin paragraph update
816 mpIndents[0] = Buffer for old intent
817 mpIndents[1] = Buffer for old intent
818 mpIndents[INDENT_FIRST_LINE] = first line indent
819 mpIndents[INDENT_LEFT_MARGIN] = left margin
820 mpIndents[INDENT_RIGHT_MARGIN] = right margin
823 // Dependence on PagePosItem
824 if (mxParaItem && mxPagePosItem && !mxObjectItem)
826 bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
827 // First-line indent is negative to the left paragraph margin
828 tools::Long nLeftFrameMargin = GetLeftFrameMargin();
829 tools::Long nRightFrameMargin = GetRightFrameMargin();
830 SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin));
831 SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin));
833 tools::Long leftMargin;
834 tools::Long leftFirstLine;
835 tools::Long rightMargin;
837 if(bRTLText)
839 leftMargin = nRightFrameMargin - mxParaItem->GetTextLeft() + lAppNullOffset;
840 leftFirstLine = leftMargin - mxParaItem->GetTextFirstLineOffset();
841 rightMargin = nLeftFrameMargin + mxParaItem->GetRight() + lAppNullOffset;
843 else
845 leftMargin = nLeftFrameMargin + mxParaItem->GetTextLeft() + lAppNullOffset;
846 leftFirstLine = leftMargin + mxParaItem->GetTextFirstLineOffset();
847 rightMargin = nRightFrameMargin - mxParaItem->GetRight() + lAppNullOffset;
850 mpIndents[INDENT_LEFT_MARGIN].nPos = ConvertHPosPixel(leftMargin);
851 mpIndents[INDENT_FIRST_LINE].nPos = ConvertHPosPixel(leftFirstLine);
852 mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin);
854 mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst();
856 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
858 else
860 if(!mpIndents.empty())
862 mpIndents[INDENT_FIRST_LINE].nPos = 0;
863 mpIndents[INDENT_LEFT_MARGIN].nPos = 0;
864 mpIndents[INDENT_RIGHT_MARGIN].nPos = 0;
866 SetIndents(); // turn off
870 void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents
872 /* Store new value of paragraph indents */
873 if(bActive)
875 if(pItem)
876 mxParaItem.reset(new SvxLRSpaceItem(*pItem));
877 else
878 mxParaItem.reset();
879 StartListening_Impl();
883 void SvxRuler::UpdateParaBorder()
885 /* Border distance */
886 if(bActive)
888 StartListening_Impl();
892 void SvxRuler::UpdatePage()
894 /* Update view of position and width of page */
895 if (mxPagePosItem)
897 // all objects are automatically adjusted
898 if(bHorz)
900 SetPagePos(
901 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(),
902 pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)).
903 Width());
905 else
907 SetPagePos(
908 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(),
909 pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())).
910 Height());
912 if(bAppSetNullOffset)
913 SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset));
915 else
917 SetPagePos();
920 tools::Long lPos = 0;
921 Point aOwnPos = GetPosPixel();
922 Point aEdtWinPos = pEditWin->GetPosPixel();
923 if( AllSettings::GetLayoutRTL() && bHorz )
925 //#i73321# in RTL the window and the ruler is not mirrored but the
926 // influence of the vertical ruler is inverted
927 Size aOwnSize = GetSizePixel();
928 Size aEdtWinSize = pEditWin->GetSizePixel();
929 lPos = aOwnSize.Width() - aEdtWinSize.Width();
930 lPos -= (aEdtWinPos - aOwnPos).X();
932 else
934 Point aPos(aEdtWinPos - aOwnPos);
935 lPos = bHorz ? aPos.X() : aPos.Y();
938 // Unfortunately, we get the offset of the edit window to the ruler never
939 // through a status message. So we set it ourselves if necessary.
940 if(lPos != mxRulerImpl->lOldWinPos)
942 mxRulerImpl->lOldWinPos=lPos;
943 SetWinPos(lPos);
947 void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes
949 /* Store new value of page attributes */
950 if(bActive)
952 if(pItem)
953 mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem));
954 else
955 mxPagePosItem.reset();
956 StartListening_Impl();
960 void SvxRuler::SetDefTabDist(tools::Long inDefTabDist) // New distance for DefaultTabs in App-Metrics
962 if (lAppNullOffset == LONG_MAX)
963 UpdateFrame(); // hack: try to get lAppNullOffset initialized
964 /* New distance is set for DefaultTabs */
965 lDefTabDist = inDefTabDist;
966 UpdateTabs();
969 static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj)
971 /* Internal conversion routine between SV-Tab.-Enum and Svx */
972 switch(eAdj) {
973 case SvxTabAdjust::Left: return RULER_TAB_LEFT;
974 case SvxTabAdjust::Right: return RULER_TAB_RIGHT;
975 case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL;
976 case SvxTabAdjust::Center: return RULER_TAB_CENTER;
977 case SvxTabAdjust::Default: return RULER_TAB_DEFAULT;
978 default: ; //prevent warning
980 return 0;
983 static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj)
985 switch(eAdj) {
986 case RULER_TAB_LEFT: return SvxTabAdjust::Left ;
987 case RULER_TAB_RIGHT: return SvxTabAdjust::Right ;
988 case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ;
989 case RULER_TAB_CENTER: return SvxTabAdjust::Center ;
990 case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ;
992 return SvxTabAdjust::Left;
995 void SvxRuler::UpdateTabs()
997 if(IsDrag())
998 return;
1000 if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem)
1002 // buffer for DefaultTabStop
1003 // Distance last Tab <-> Right paragraph margin / DefaultTabDist
1004 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1006 const tools::Long nLeftFrameMargin = GetLeftFrameMargin();
1007 const tools::Long nRightFrameMargin = GetRightFrameMargin();
1009 //#i24363# tab stops relative to indent
1010 const tools::Long nParaItemTxtLeft = mxParaItem->GetTextLeft();
1012 const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft;
1013 const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft;
1015 const tools::Long lLastTab = mxTabStopItem->Count()
1016 ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos())
1017 : 0;
1018 const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab;
1019 const tools::Long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight());
1021 tools::Long nDefTabDist = ConvertHPosPixel(lDefTabDist);
1023 if( !nDefTabDist )
1024 nDefTabDist = 1;
1026 const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent
1028 : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist );
1030 if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize)
1032 // 10 (GAP) in stock
1033 nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP;
1034 mpTabs.resize(nTabBufSize);
1037 nTabCount = 0;
1038 sal_uInt16 j;
1040 const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent);
1042 tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin)
1043 + lAppNullOffset;
1044 if (bRTL)
1046 lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic;
1048 tools::Long lLastTabOffsetLogic = 0;
1049 for(j = 0; j < mxTabStopItem->Count(); ++j)
1051 const SvxTabStop* pTab = &mxTabStopItem->At(j);
1052 lLastTabOffsetLogic = pTab->GetTabPos();
1053 tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic);
1054 mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos);
1055 mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment());
1056 ++nTabCount;
1059 // Adjust to previous-to-first default tab stop
1060 lLastTabOffsetLogic -= lLastTabOffsetLogic % lDefTabDist;
1062 // fill the rest with default Tabs
1063 for (j = 0; j < nDefTabBuf; ++j)
1065 //simply add the default distance to the last position
1066 lLastTabOffsetLogic += lDefTabDist;
1067 if (bRTL)
1069 mpTabs[nTabCount + TAB_GAP].nPos =
1070 ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic);
1071 if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix)
1072 break;
1074 else
1076 mpTabs[nTabCount + TAB_GAP].nPos =
1077 ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic);
1078 if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent)
1079 break;
1082 mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT;
1083 ++nTabCount;
1085 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1086 DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small");
1088 else
1090 SetTabs();
1094 void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs
1096 /* Store new value for tabs; delete old ones if possible */
1097 if(!bActive)
1098 return;
1100 if(pItem)
1102 mxTabStopItem.reset(new SvxTabStopItem(*pItem));
1103 if(!bHorz)
1104 mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL);
1106 else
1108 mxTabStopItem.reset();
1110 StartListening_Impl();
1113 void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects
1115 /* Store new value for objects */
1116 if(bActive)
1118 if(pItem)
1119 mxObjectItem.reset(new SvxObjectItem(*pItem));
1120 else
1121 mxObjectItem.reset();
1122 StartListening_Impl();
1126 void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets
1128 lAppNullOffset = lLogicNullOffset - lVal;
1129 bAppSetNullOffset = true;
1130 Ruler::SetNullOffset(ConvertSizePixel(lVal));
1131 Update();
1134 void SvxRuler::Update()
1136 /* Perform update of view */
1137 if(IsDrag())
1138 return;
1140 UpdatePage();
1141 UpdateFrame();
1142 if(nFlags & SvxRulerSupportFlags::OBJECT)
1143 UpdateObject();
1144 else
1145 UpdateColumns();
1147 if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
1148 UpdatePara();
1150 if(nFlags & SvxRulerSupportFlags::TABS)
1151 UpdateTabs();
1154 tools::Long SvxRuler::GetPageWidth() const
1156 if (!mxPagePosItem)
1157 return 0;
1158 return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
1161 inline tools::Long SvxRuler::GetFrameLeft() const
1163 /* Get Left margin in Pixels */
1164 return bAppSetNullOffset ?
1165 GetMargin1() + ConvertSizePixel(lLogicNullOffset) :
1166 Ruler::GetNullOffset();
1169 tools::Long SvxRuler::GetFirstLineIndent() const
1171 /* Get First-line indent in pixels */
1172 return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1();
1175 tools::Long SvxRuler::GetLeftIndent() const
1177 /* Get Left paragraph margin in Pixels */
1178 return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1();
1181 tools::Long SvxRuler::GetRightIndent() const
1183 /* Get Right paragraph margin in Pixels */
1184 return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2();
1187 tools::Long SvxRuler::GetLogicRightIndent() const
1189 /* Get Right paragraph margin in Logic */
1190 return mxParaItem ? GetRightFrameMargin() - mxParaItem->GetRight() : GetRightFrameMargin();
1193 // Left margin in App values, is either the margin (= 0) or the left edge of
1194 // the column that is set in the column attribute as current column.
1195 tools::Long SvxRuler::GetLeftFrameMargin() const
1197 // #126721# for some unknown reason the current column is set to 0xffff
1198 DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(),
1199 "issue #126721# - invalid current column!");
1200 tools::Long nLeft = 0;
1201 if (mxColumnItem &&
1202 mxColumnItem->Count() &&
1203 mxColumnItem->IsConsistent())
1205 nLeft = mxColumnItem->GetActiveColumnDescription().nStart;
1208 return nLeft;
1211 inline tools::Long SvxRuler::GetLeftMin() const
1213 DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1214 if (mxMinMaxItem)
1216 if (bHorz)
1217 return mxMinMaxItem->GetValue().Left();
1218 else
1219 return mxMinMaxItem->GetValue().Top();
1221 return 0;
1224 inline tools::Long SvxRuler::GetRightMax() const
1226 DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1227 if (mxMinMaxItem)
1229 if (bHorz)
1230 return mxMinMaxItem->GetValue().Right();
1231 else
1232 return mxMinMaxItem->GetValue().Bottom();
1234 return 0;
1238 tools::Long SvxRuler::GetRightFrameMargin() const
1240 /* Get right frame margin (in logical units) */
1241 if (mxColumnItem)
1243 if (!IsActLastColumn(true))
1245 return mxColumnItem->At(GetActRightColumn(true)).nEnd;
1249 tools::Long lResult = lLogicNullOffset;
1251 // If possible deduct right table entry
1252 if(mxColumnItem && mxColumnItem->IsTable())
1253 lResult += mxColumnItem->GetRight();
1254 else if(bHorz && mxLRSpaceItem)
1255 lResult += mxLRSpaceItem->GetRight();
1256 else if(!bHorz && mxULSpaceItem)
1257 lResult += mxULSpaceItem->GetLower();
1259 if(bHorz)
1260 lResult = mxPagePosItem->GetWidth() - lResult;
1261 else
1262 lResult = mxPagePosItem->GetHeight() - lResult;
1264 return lResult;
1267 #define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \
1268 SvxRulerSupportFlags::NEGATIVE_MARGINS )
1269 #define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() )
1271 tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight )
1274 Corrects the position within the calculated limits. The limit values are in
1275 pixels relative to the page edge.
1278 const tools::Long lNullPix = Ruler::GetNullOffset();
1279 tools::Long lDragPos = GetDragPos() + lNullPix;
1280 bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows;
1281 if((bLeft || bHoriRows) && lDragPos < nMaxLeft)
1282 lDragPos = nMaxLeft;
1283 else if((bRight||bHoriRows) && lDragPos > nMaxRight)
1284 lDragPos = nMaxRight;
1285 return lDragPos - lNullPix;
1288 static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs
1289 RulerTab* pTabs, // Tab buffer
1290 tools::Long lDiff) // difference to be added
1292 /* Helper function, move all the tabs by a fixed value */
1293 if( pTabs )
1295 for(sal_uInt16 i = 0; i < nCount; ++i)
1297 pTabs[i].nPos += lDiff;
1302 void SvxRuler::DragMargin1()
1304 /* Dragging the left edge of frame */
1305 tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG );
1307 aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false);
1309 // Check if position changed
1310 if (aDragPosition == 0)
1311 return;
1313 DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz);
1314 if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1315 DragBorders();
1316 AdjustMargin1(aDragPosition);
1319 void SvxRuler::AdjustMargin1(tools::Long lInputDiff)
1321 const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset();
1322 const tools::Long lDragPos = lInputDiff;
1324 bool bProtectColumns =
1325 mxRulerImpl->aProtectItem->IsSizeProtected() ||
1326 mxRulerImpl->aProtectItem->IsPosProtected();
1328 const RulerMarginStyle nMarginStyle =
1329 bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1331 if(!bAppSetNullOffset)
1333 tools::Long lDiff = lDragPos;
1334 SetNullOffset(nOld + lDiff);
1335 if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
1337 SetMargin2( GetMargin2() - lDiff, nMarginStyle );
1339 if (!mxColumnItem && !mxObjectItem && mxParaItem)
1341 // Right indent of the old position
1342 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1343 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1345 if (mxObjectItem)
1347 mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff;
1348 mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff;
1349 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1351 if (mxColumnItem)
1353 for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i)
1354 mpBorders[i].nPos -= lDiff;
1355 SetBorders(mxColumnItem->Count()-1, mpBorders.data());
1356 if(mxColumnItem->IsFirstAct())
1358 // Right indent of the old position
1359 if (mxParaItem)
1361 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1362 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1365 else
1367 if (mxParaItem)
1369 mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1370 mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff;
1371 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1372 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1375 if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1376 &&!IsActFirstColumn())
1378 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff);
1379 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1384 else
1386 tools::Long lDiff = lDragPos - nOld;
1387 SetMargin1(nOld + lDiff, nMarginStyle);
1389 if (!mxColumnItem
1390 || !(nDragType
1391 & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR
1392 | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
1394 if (!mxColumnItem && !mxObjectItem && mxParaItem)
1396 // Left indent of the old position
1397 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1398 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1399 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1402 if (mxColumnItem)
1404 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
1405 mpBorders[i].nPos += lDiff;
1406 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1407 if (mxColumnItem->IsFirstAct())
1409 // Left indent of the old position
1410 if (mxParaItem)
1412 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1413 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1414 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1417 else
1419 if (mxParaItem)
1421 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1422 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1423 mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff;
1424 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1428 if (mxTabStopItem)
1430 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff);
1431 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1437 void SvxRuler::DragMargin2()
1439 /* Dragging the right edge of frame */
1440 tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG);
1441 aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false);
1442 tools::Long lDiff = aDragPosition - GetMargin2();
1444 // Check if position changed
1445 if (lDiff == 0)
1446 return;
1448 if( mxRulerImpl->bIsTableRows &&
1449 !bHorz &&
1450 mxColumnItem &&
1451 (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1453 DragBorders();
1456 bool bProtectColumns =
1457 mxRulerImpl->aProtectItem->IsSizeProtected() ||
1458 mxRulerImpl->aProtectItem->IsPosProtected();
1460 const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1462 SetMargin2( aDragPosition, nMarginStyle );
1464 // Right indent of the old position
1465 if ((!mxColumnItem || IsActLastColumn()) && mxParaItem)
1467 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1468 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1471 DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz);
1474 void SvxRuler::DragIndents()
1476 /* Dragging the paragraph indents */
1477 tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos();
1478 const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP;
1480 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1482 if(nIndex == INDENT_RIGHT_MARGIN)
1483 aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin());
1484 else
1485 aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
1487 const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition;
1489 // Check if position changed
1490 if (lDiff == 0)
1491 return;
1493 if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN ) &&
1494 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
1496 mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1499 mpIndents[nIndex].nPos = aDragPosition;
1501 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1502 DrawLine_Impl(lTabPos, 1, bHorz);
1505 void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal)
1508 Output routine for the ledger line when moving tabs, tables and other
1509 columns
1511 if(bHorizontal)
1513 const tools::Long nHeight = pEditWin->GetOutputSize().Height();
1514 Point aZero = pEditWin->GetMapMode().GetOrigin();
1515 if(lTabPosition != -1)
1517 pEditWin->InvertTracking(
1518 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1519 Point(lTabPosition, -aZero.Y() + nHeight)),
1520 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1522 if( nNew & 1 )
1524 tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 );
1525 nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1526 lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() );
1527 if (mxPagePosItem)
1528 lTabPosition += mxPagePosItem->GetPos().X();
1529 pEditWin->InvertTracking(
1530 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1531 Point(lTabPosition, -aZero.Y() + nHeight) ),
1532 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1535 else
1537 const tools::Long nWidth = pEditWin->GetOutputSize().Width();
1538 Point aZero = pEditWin->GetMapMode().GetOrigin();
1539 if(lTabPosition != -1)
1541 pEditWin->InvertTracking(
1542 tools::Rectangle( Point(-aZero.X(), lTabPosition),
1543 Point(-aZero.X() + nWidth, lTabPosition)),
1544 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1547 if(nNew & 1)
1549 tools::Long nDrapPosition = GetCorrectedDragPos();
1550 nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1551 lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset());
1552 if (mxPagePosItem)
1553 lTabPosition += mxPagePosItem->GetPos().Y();
1554 pEditWin->InvertTracking(
1555 tools::Rectangle( Point(-aZero.X(), lTabPosition),
1556 Point(-aZero.X()+nWidth, lTabPosition)),
1557 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1562 void SvxRuler::DragTabs()
1564 /* Dragging of Tabs */
1565 tools::Long aDragPosition = GetCorrectedDragPos(true, false);
1566 aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin());
1568 sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP;
1569 tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos;
1570 if (nDiff == 0)
1571 return;
1573 DrawLine_Impl(lTabPos, 7, bHorz);
1575 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1578 for(sal_uInt16 i = nIdx; i < nTabCount; ++i)
1580 mpTabs[i].nPos += nDiff;
1581 // limit on maximum
1582 if(mpTabs[i].nPos > GetMargin2())
1583 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1584 else
1585 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1588 else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1590 mxRulerImpl->nTotalDist -= nDiff;
1591 mpTabs[nIdx].nPos = aDragPosition;
1592 for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
1594 if(mpTabs[i].nStyle & RULER_TAB_DEFAULT)
1595 // can be canceled at the DefaultTabs
1596 break;
1597 tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i];
1598 nDelta /= 1000;
1599 mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta;
1600 if(mpTabs[i].nPos + GetNullOffset() > nMaxRight)
1601 mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE;
1602 else
1603 mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE;
1606 else
1608 mpTabs[nIdx].nPos = aDragPosition;
1611 if(IsDragDelete())
1612 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1613 else
1614 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1615 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1618 void SvxRuler::SetActive(bool bOn)
1620 if(bOn)
1622 Activate();
1624 else
1625 Deactivate();
1626 if(bActive!=bOn)
1628 pBindings->EnterRegistrations();
1629 if(bOn)
1630 for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++)
1631 pCtrlItems[i]->ReBind();
1632 else
1633 for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++)
1634 pCtrlItems[j]->UnBind();
1635 pBindings->LeaveRegistrations();
1637 bActive = bOn;
1640 void SvxRuler::UpdateParaContents_Impl(
1641 tools::Long lDifference,
1642 UpdateType eType) // Art (all, left or right)
1644 /* Helper function; carry Tabs and Paragraph Margins */
1645 switch(eType)
1647 case UpdateType::MoveRight:
1648 mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference;
1649 break;
1650 case UpdateType::MoveLeft:
1652 mpIndents[INDENT_FIRST_LINE].nPos += lDifference;
1653 mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference;
1654 if (!mpTabs.empty())
1656 for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i)
1658 mpTabs[i].nPos += lDifference;
1660 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1662 break;
1665 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1668 void SvxRuler::DragBorders()
1670 /* Dragging of Borders (Tables and other columns) */
1671 bool bLeftIndentsCorrected = false;
1672 bool bRightIndentsCorrected = false;
1673 int nIndex;
1675 if(GetDragType() == RulerType::Border)
1677 DrawLine_Impl(lTabPos, 7, bHorz);
1678 nIndex = GetDragAryPos();
1680 else
1682 nIndex = 0;
1685 RulerDragSize nDragSize = GetDragSize();
1686 tools::Long lDiff = 0;
1688 // the drag position has to be corrected to be able to prevent borders from passing each other
1689 tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1691 switch(nDragSize)
1693 case RulerDragSize::Move:
1695 if(GetDragType() == RulerType::Border)
1696 lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos;
1697 else
1698 lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin;
1700 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1702 tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters
1703 for(int i = mpBorders.size() - 2; i >= nIndex; --i)
1705 tools::Long l = mpBorders[i].nPos;
1706 mpBorders[i].nPos += lDiff;
1707 mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth);
1708 nRight = mpBorders[i].nPos - glMinFrame;
1709 // RR update the column
1710 if(i == GetActRightColumn())
1712 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1713 bRightIndentsCorrected = true;
1715 // LAR, EZE update the column
1716 else if(i == GetActLeftColumn())
1718 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1719 bLeftIndentsCorrected = true;
1723 else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1725 int nLimit;
1726 tools::Long lLeft;
1727 int nStartLimit = mpBorders.size() - 2;
1728 switch(GetDragType())
1730 default: ;//prevent warning
1731 OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" );
1732 [[fallthrough]];
1733 case RulerType::Border:
1734 if(mxRulerImpl->bIsTableRows)
1736 mpBorders[nIndex].nPos += lDiff;
1737 if(bHorz)
1739 lLeft = mpBorders[nIndex].nPos;
1740 mxRulerImpl->nTotalDist -= lDiff;
1741 nLimit = nIndex + 1;
1743 else
1745 lLeft = 0;
1746 nStartLimit = nIndex - 1;
1747 mxRulerImpl->nTotalDist += lDiff;
1748 nLimit = 0;
1751 else
1753 nLimit = nIndex + 1;
1754 mpBorders[nIndex].nPos += lDiff;
1755 lLeft = mpBorders[nIndex].nPos;
1756 mxRulerImpl->nTotalDist -= lDiff;
1758 break;
1759 case RulerType::Margin1:
1760 nLimit = 0;
1761 lLeft = mxRulerImpl->lLastLMargin + lDiff;
1762 mxRulerImpl->nTotalDist -= lDiff;
1763 break;
1764 case RulerType::Margin2:
1765 nLimit = 0;
1766 lLeft= 0;
1767 nStartLimit = mpBorders.size() - 2;
1768 mxRulerImpl->nTotalDist += lDiff;
1769 break;
1772 for(int i = nStartLimit; i >= nLimit; --i)
1775 tools::Long l = mpBorders[i].nPos;
1776 mpBorders[i].nPos =
1777 lLeft +
1778 (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 +
1779 mxRulerImpl->pBlockBuf[i];
1781 // RR update the column
1782 if(!mxRulerImpl->bIsTableRows)
1784 if(i == GetActRightColumn())
1786 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1787 bRightIndentsCorrected = true;
1789 // LAR, EZE update the column
1790 else if(i == GetActLeftColumn())
1792 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1793 bLeftIndentsCorrected = true;
1797 if(mxRulerImpl->bIsTableRows)
1799 //in vertical tables the left borders have to be moved
1800 if(bHorz)
1802 for(int i = 0; i < nIndex; ++i)
1803 mpBorders[i].nPos += lDiff;
1804 AdjustMargin1(lDiff);
1806 else
1808 //otherwise the right borders are moved
1809 for(int i = mxColumnItem->Count() - 1; i > nIndex; --i)
1810 mpBorders[i].nPos += lDiff;
1811 SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1815 else if(mxRulerImpl->bIsTableRows)
1817 //moving rows: if a row is resized all following rows
1818 //have to be moved by the same amount.
1819 //This includes the left border when the table is not limited
1820 //to a lower frame border.
1821 int nLimit;
1822 if(GetDragType()==RulerType::Border)
1824 nLimit = nIndex + 1;
1825 mpBorders[nIndex].nPos += lDiff;
1827 else
1829 nLimit=0;
1831 //in vertical tables the left borders have to be moved
1832 if(bHorz)
1834 for(int i = 0; i < nIndex; ++i)
1836 mpBorders[i].nPos += lDiff;
1838 AdjustMargin1(lDiff);
1840 else
1842 //otherwise the right borders are moved
1843 for(int i = mpBorders.size() - 2; i >= nLimit; --i)
1845 mpBorders[i].nPos += lDiff;
1847 SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1850 else
1851 mpBorders[nIndex].nPos += lDiff;
1852 break;
1854 case RulerDragSize::N1:
1856 lDiff = lPos - mpBorders[nIndex].nPos;
1857 mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos;
1858 mpBorders[nIndex].nPos = lPos;
1859 break;
1861 case RulerDragSize::N2:
1863 const tools::Long nOld = mpBorders[nIndex].nWidth;
1864 mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos;
1865 lDiff = mpBorders[nIndex].nWidth - nOld;
1866 break;
1869 if(!bRightIndentsCorrected &&
1870 GetActRightColumn() == nIndex &&
1871 nDragSize != RulerDragSize::N2 &&
1872 !mpIndents.empty() &&
1873 !mxRulerImpl->bIsTableRows)
1875 UpdateParaContents_Impl(lDiff, UpdateType::MoveRight);
1877 else if(!bLeftIndentsCorrected &&
1878 GetActLeftColumn() == nIndex &&
1879 nDragSize != RulerDragSize::N1 &&
1880 !mpIndents.empty())
1882 UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft);
1884 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1887 void SvxRuler::DragObjectBorder()
1889 /* Dragging of object edges */
1890 if(RulerDragSize::Move == GetDragSize())
1892 const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1894 const sal_uInt16 nIdx = GetDragAryPos();
1895 mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition;
1896 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1897 DrawLine_Impl(lTabPos, 7, bHorz);
1902 void SvxRuler::ApplyMargins()
1904 /* Applying margins; changed by dragging. */
1905 const SfxPoolItem* pItem = nullptr;
1906 sal_uInt16 nId = SID_ATTR_LONG_LRSPACE;
1908 if(bHorz)
1910 const tools::Long lOldNull = lLogicNullOffset;
1911 if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset())
1913 lLogicNullOffset = mxRulerImpl->lMaxLeftLogic;
1914 mxLRSpaceItem->SetLeft(lLogicNullOffset);
1916 else
1918 lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset;
1919 mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft()));
1922 if(bAppSetNullOffset)
1924 lAppNullOffset += lLogicNullOffset - lOldNull;
1927 tools::Long nRight;
1928 if(mxRulerImpl->lMaxRightLogic != -1
1929 && nMaxRight == GetMargin2() + Ruler::GetNullOffset())
1931 nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic;
1933 else
1935 nRight = std::max(tools::Long(0),
1936 mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() -
1937 (ConvertHPosLogic(GetMargin2()) - lAppNullOffset));
1939 nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight());
1941 mxLRSpaceItem->SetRight(nRight);
1943 pItem = mxLRSpaceItem.get();
1945 #ifdef DEBUGLIN
1946 Debug_Impl(pEditWin, *mxLRSpaceItem);
1947 #endif // DEBUGLIN
1950 else
1952 const tools::Long lOldNull = lLogicNullOffset;
1953 lLogicNullOffset =
1954 ConvertVPosLogic(GetFrameLeft()) -
1955 lAppNullOffset;
1956 mxULSpaceItem->SetUpper(
1957 PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper()));
1958 if(bAppSetNullOffset)
1960 lAppNullOffset += lLogicNullOffset - lOldNull;
1962 mxULSpaceItem->SetLower(
1963 PixelVAdjust(
1964 std::max(tools::Long(0), mxPagePosItem->GetHeight() -
1965 mxULSpaceItem->GetUpper() -
1966 (ConvertVPosLogic(GetMargin2()) -
1967 lAppNullOffset)), mxULSpaceItem->GetLower()));
1968 pItem = mxULSpaceItem.get();
1969 nId = SID_ATTR_LONG_ULSPACE;
1971 #ifdef DEBUGLIN
1972 Debug_Impl(pEditWin,*mxULSpaceItem);
1973 #endif // DEBUGLIN
1976 pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem });
1977 if (mxTabStopItem)
1978 UpdateTabs();
1981 tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const
1983 RulerUnitData aUnitData = GetCurrentRulerUnit();
1984 double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
1986 tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
1987 lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit;
1988 return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width();
1991 void SvxRuler::ApplyIndents()
1993 /* Applying paragraph settings; changed by dragging. */
1995 tools::Long nLeftFrameMargin = GetLeftFrameMargin();
1997 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1999 tools::Long nNewTxtLeft;
2000 tools::Long nNewFirstLineOffset;
2001 tools::Long nNewRight;
2003 tools::Long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos);
2004 tools::Long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos);
2005 tools::Long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos);
2007 if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true))))
2009 if(bRTL)
2011 tools::Long nRightColumn = GetActRightColumn(true);
2012 tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2013 nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2015 else
2017 tools::Long nLeftColumn = GetActLeftColumn(true);
2018 tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2019 nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset;
2022 else
2024 if(bRTL)
2026 tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2027 nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2029 else
2031 tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2032 nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset;
2036 if(bRTL)
2037 nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset;
2038 else
2039 nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset;
2041 if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true))))
2043 if(bRTL)
2045 tools::Long nLeftColumn = GetActLeftColumn(true);
2046 tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2047 nNewRight = nRightMargin - nLeftBorder - lAppNullOffset;
2049 else
2051 tools::Long nRightColumn = GetActRightColumn(true);
2052 tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2053 nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2056 else
2058 if(bRTL)
2060 tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2061 nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset;
2063 else
2065 tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2066 nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2070 if (mbSnapping)
2072 nNewTxtLeft = RoundToCurrentMapMode(nNewTxtLeft);
2073 nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset);
2074 nNewRight = RoundToCurrentMapMode(nNewRight);
2077 mxParaItem->SetTextFirstLineOffset(sal::static_int_cast<short>(nNewFirstLineOffset));
2078 mxParaItem->SetTextLeft(nNewTxtLeft);
2079 mxParaItem->SetRight(nNewRight);
2081 sal_uInt16 nParagraphId = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL;
2082 pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD,
2083 { mxParaItem.get() });
2084 UpdateTabs();
2087 void SvxRuler::ApplyTabs()
2089 /* Apply tab settings, changed by dragging. */
2090 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2091 const sal_uInt16 nCoreIdx = GetDragAryPos();
2092 if(IsDragDelete())
2094 mxTabStopItem->Remove(nCoreIdx);
2096 else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType ||
2097 SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType)
2099 SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which());
2100 //remove default tab stops
2101 for ( sal_uInt16 i = 0; i < pItem->Count(); )
2103 if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() )
2105 pItem->Remove(i);
2106 continue;
2108 ++i;
2111 sal_uInt16 j;
2112 for(j = 0; j < nCoreIdx; ++j)
2114 pItem->Insert(mxTabStopItem->At(j));
2116 for(; j < mxTabStopItem->Count(); ++j)
2118 SvxTabStop aTabStop = mxTabStopItem->At(j);
2119 aTabStop.GetTabPos() = PixelHAdjust(
2120 ConvertHPosLogic(
2121 mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset,
2122 aTabStop.GetTabPos());
2123 pItem->Insert(aTabStop);
2125 mxTabStopItem.reset(pItem);
2127 else if( mxTabStopItem->Count() == 0 )
2128 return;
2129 else
2131 SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx);
2132 if( mxRulerImpl->lMaxRightLogic != -1 &&
2133 mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight )
2135 // Set tab pos exactly at the right indent
2136 tools::Long nTmpLeftIndentLogic
2137 = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
2138 if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem)
2140 nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetLeft();
2142 aTabStop.GetTabPos()
2143 = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic;
2145 else
2147 if(bRTL)
2149 //#i24363# tab stops relative to indent
2150 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2151 GetLeftIndent() :
2152 ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset );
2154 tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos);
2155 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2157 else
2159 //#i24363# tab stops relative to indent
2160 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2161 GetLeftIndent() :
2162 ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset );
2164 tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent);
2165 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2168 mxTabStopItem->Remove(nCoreIdx);
2169 mxTabStopItem->Insert(aTabStop);
2171 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
2172 pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD,
2173 { mxTabStopItem.get() });
2174 UpdateTabs();
2177 void SvxRuler::ApplyBorders()
2179 /* Applying (table) column settings; changed by dragging. */
2180 if(mxColumnItem->IsTable())
2182 tools::Long lValue = GetFrameLeft();
2183 if(lValue != mxRulerImpl->nColLeftPix)
2185 tools::Long nLeft = PixelHAdjust(
2186 ConvertHPosLogic(lValue) -
2187 lAppNullOffset,
2188 mxColumnItem->GetLeft());
2189 mxColumnItem->SetLeft(nLeft);
2192 lValue = GetMargin2();
2194 if(lValue != mxRulerImpl->nColRightPix)
2196 tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
2197 tools::Long nRight = PixelHAdjust(
2198 nWidthOrHeight -
2199 mxColumnItem->GetLeft() -
2200 ConvertHPosLogic(lValue) -
2201 lAppNullOffset,
2202 mxColumnItem->GetRight() );
2203 mxColumnItem->SetRight(nRight);
2207 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
2209 tools::Long& nEnd = mxColumnItem->At(i).nEnd;
2210 nEnd = PixelHAdjust(
2211 ConvertPosLogic(mpBorders[i].nPos),
2212 mxColumnItem->At(i).nEnd);
2213 tools::Long& nStart = mxColumnItem->At(i + 1).nStart;
2214 nStart = PixelHAdjust(
2215 ConvertSizeLogic(mpBorders[i].nPos +
2216 mpBorders[i].nWidth) -
2217 lAppNullOffset,
2218 mxColumnItem->At(i + 1).nStart);
2219 // It may be that, due to the PixelHAdjust readjustment to old values,
2220 // the width becomes < 0. This we readjust.
2221 if( nEnd > nStart )
2222 nStart = nEnd;
2225 #ifdef DEBUGLIN
2226 Debug_Impl(pEditWin,*mxColumnItem);
2227 #endif // DEBUGLIN
2229 SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY,
2230 bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY));
2232 sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) :
2233 (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2235 pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD,
2236 { mxColumnItem.get(), &aFlag });
2239 void SvxRuler::ApplyObject()
2241 /* Applying object settings, changed by dragging. */
2243 // to the page margin
2244 tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
2245 tools::Long nStartX = PixelAdjust(
2246 ConvertPosLogic(mpObjectBorders[0].nPos) +
2247 nMargin -
2248 lAppNullOffset,
2249 mxObjectItem->GetStartX());
2250 mxObjectItem->SetStartX(nStartX);
2252 tools::Long nEndX = PixelAdjust(
2253 ConvertPosLogic(mpObjectBorders[1].nPos) +
2254 nMargin -
2255 lAppNullOffset,
2256 mxObjectItem->GetEndX());
2257 mxObjectItem->SetEndX(nEndX);
2259 nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
2260 tools::Long nStartY = PixelAdjust(
2261 ConvertPosLogic(mpObjectBorders[2].nPos) +
2262 nMargin -
2263 lAppNullOffset,
2264 mxObjectItem->GetStartY());
2265 mxObjectItem->SetStartY(nStartY);
2267 tools::Long nEndY = PixelAdjust(
2268 ConvertPosLogic(mpObjectBorders[3].nPos) +
2269 nMargin -
2270 lAppNullOffset,
2271 mxObjectItem->GetEndY());
2272 mxObjectItem->SetEndY(nEndY);
2274 pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT,
2275 SfxCallMode::RECORD, { mxObjectItem.get() });
2278 void SvxRuler::PrepareProportional_Impl(RulerType eType)
2281 Preparation proportional dragging, and it is calculated based on the
2282 proportional share of the total width in parts per thousand.
2284 mxRulerImpl->nTotalDist = GetMargin2();
2285 switch(eType)
2287 case RulerType::Margin2:
2288 case RulerType::Margin1:
2289 case RulerType::Border:
2291 DBG_ASSERT(mxColumnItem, "no ColumnItem");
2293 mxRulerImpl->SetPercSize(mxColumnItem->Count());
2295 tools::Long lPos;
2296 tools::Long lWidth=0;
2297 sal_uInt16 nStart;
2298 sal_uInt16 nIdx=GetDragAryPos();
2299 tools::Long lActWidth=0;
2300 tools::Long lActBorderSum;
2301 tools::Long lOrigLPos;
2303 if(eType != RulerType::Border)
2305 lOrigLPos = GetMargin1();
2306 nStart = 0;
2307 lActBorderSum = 0;
2309 else
2311 if(mxRulerImpl->bIsTableRows &&!bHorz)
2313 lOrigLPos = GetMargin1();
2314 nStart = 0;
2316 else
2318 lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth;
2319 nStart = 1;
2321 lActBorderSum = mpBorders[nIdx].nWidth;
2324 //in horizontal mode the percentage value has to be
2325 //calculated on a "current change" position base
2326 //because the height of the table changes while dragging
2327 if(mxRulerImpl->bIsTableRows && RulerType::Border == eType)
2329 sal_uInt16 nStartBorder;
2330 sal_uInt16 nEndBorder;
2331 if(bHorz)
2333 nStartBorder = nIdx + 1;
2334 nEndBorder = mxColumnItem->Count() - 1;
2336 else
2338 nStartBorder = 0;
2339 nEndBorder = nIdx;
2342 lWidth = mpBorders[nIdx].nPos;
2343 if(bHorz)
2344 lWidth = GetMargin2() - lWidth;
2345 mxRulerImpl->nTotalDist = lWidth;
2346 lPos = mpBorders[nIdx].nPos;
2348 for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i)
2350 if(bHorz)
2352 lActWidth += mpBorders[i].nPos - lPos;
2353 lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2355 else
2356 lActWidth = mpBorders[i].nPos;
2357 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2358 / mxRulerImpl->nTotalDist);
2359 mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2360 lActBorderSum += mpBorders[i].nWidth;
2363 else
2365 lPos = lOrigLPos;
2366 for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii)
2368 lWidth += mpBorders[ii].nPos - lPos;
2369 lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth;
2372 lWidth += GetMargin2() - lPos;
2373 mxRulerImpl->nTotalDist = lWidth;
2374 lPos = lOrigLPos;
2376 for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i)
2378 lActWidth += mpBorders[i].nPos - lPos;
2379 lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2380 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2381 / mxRulerImpl->nTotalDist);
2382 mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2383 lActBorderSum += mpBorders[i].nWidth;
2387 break;
2388 case RulerType::Tab:
2390 const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP;
2391 mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos;
2392 mxRulerImpl->SetPercSize(nTabCount);
2393 for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ;
2394 for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
2396 const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos;
2397 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist);
2399 break;
2401 default: break;
2405 void SvxRuler::EvalModifier()
2408 Eval Drag Modifier
2409 Shift: move linear
2410 Control: move proportional
2411 Shift + Control: Table: only current line
2412 Alt: disable snapping
2413 Alt + Shift: coarse snapping
2416 sal_uInt16 nModifier = GetDragModifier();
2417 if(mxRulerImpl->bIsTableRows)
2419 //rows can only be moved in one way, additionally current column is possible
2420 if(nModifier == KEY_SHIFT)
2421 nModifier = 0;
2424 switch(nModifier)
2426 case KEY_SHIFT:
2427 nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR;
2428 break;
2429 case KEY_MOD2 | KEY_SHIFT:
2430 mbCoarseSnapping = true;
2431 break;
2432 case KEY_MOD2:
2433 mbSnapping = false;
2434 break;
2435 case KEY_MOD1:
2437 const RulerType eType = GetDragType();
2438 nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL;
2439 if( RulerType::Tab == eType ||
2440 ( ( RulerType::Border == eType ||
2441 RulerType::Margin1 == eType ||
2442 RulerType::Margin2 == eType ) &&
2443 mxColumnItem ) )
2445 PrepareProportional_Impl(eType);
2448 break;
2449 case KEY_MOD1 | KEY_SHIFT:
2450 if( GetDragType() != RulerType::Margin1 &&
2451 GetDragType() != RulerType::Margin2 )
2453 nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY;
2455 break;
2459 void SvxRuler::Click()
2461 /* Override handler SV; sets Tab per dispatcher call */
2462 Ruler::Click();
2463 if( bActive )
2465 pBindings->Update( SID_RULER_LR_MIN_MAX );
2466 pBindings->Update( SID_ATTR_LONG_ULSPACE );
2467 pBindings->Update( SID_ATTR_LONG_LRSPACE );
2468 pBindings->Update( SID_RULER_PAGE_POS );
2469 pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
2470 pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
2471 pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2472 pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
2473 pBindings->Update( SID_RULER_OBJECT );
2474 pBindings->Update( SID_RULER_PROTECT );
2475 pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL );
2477 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2478 if(!(mxTabStopItem &&
2479 (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS))
2480 return;
2482 bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
2483 if( bContentProtected ) return;
2484 const tools::Long lPos = GetClickPos();
2485 if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) ||
2486 (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())))
2487 return;
2489 //convert position in left-to-right text
2490 tools::Long nTabPos;
2491 //#i24363# tab stops relative to indent
2492 if(bRTL)
2493 nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ?
2494 GetLeftIndent() :
2495 ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) -
2496 lPos;
2497 else
2498 nTabPos = lPos -
2499 ( mxRulerImpl->bIsTabsRelativeToIndent ?
2500 GetLeftIndent() :
2501 ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ));
2503 SvxTabStop aTabStop(ConvertHPosLogic(nTabPos),
2504 ToAttrTab_Impl(nDefTabType));
2505 mxTabStopItem->Insert(aTabStop);
2506 UpdateTabs();
2509 void SvxRuler::CalcMinMax()
2512 Calculates the limits for dragging; which are in pixels relative to the
2513 page edge
2515 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2516 const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset);
2517 mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1;
2518 switch(GetDragType())
2520 case RulerType::Margin1:
2521 { // left edge of the surrounding Frame
2522 // DragPos - NOf between left - right
2523 mxRulerImpl->lMaxLeftLogic = GetLeftMin();
2524 nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic);
2526 if (!mxColumnItem || mxColumnItem->Count() == 1)
2528 if(bRTL)
2530 nMaxRight = lNullPix - GetRightIndent() +
2531 std::max(GetFirstLineIndent(), GetLeftIndent()) -
2532 glMinFrame;
2534 else
2536 nMaxRight = lNullPix + GetRightIndent() -
2537 std::max(GetFirstLineIndent(), GetLeftIndent()) -
2538 glMinFrame;
2541 else if(mxRulerImpl->bIsTableRows)
2543 //top border is not moveable when table rows are displayed
2544 // protection of content means the margin is not moveable
2545 if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected())
2547 nMaxLeft = mpBorders[0].nMinPos + lNullPix;
2548 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2549 nMaxRight = GetRightIndent() + lNullPix -
2550 (mxColumnItem->Count() - 1 ) * glMinFrame;
2551 else
2552 nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix;
2554 else
2555 nMaxLeft = nMaxRight = lNullPix;
2557 else
2559 if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2561 nMaxRight=lNullPix+CalcPropMaxRight();
2563 else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
2565 nMaxRight = ConvertPosPixel(
2566 GetPageWidth() - (
2567 (mxColumnItem->IsTable() && mxLRSpaceItem)
2568 ? mxLRSpaceItem->GetRight() : 0))
2569 - GetMargin2() + GetMargin1();
2571 else
2573 nMaxRight = lNullPix - glMinFrame;
2574 if (mxColumnItem->IsFirstAct())
2576 if(bRTL)
2578 nMaxRight += std::min(
2579 mpBorders[0].nPos,
2580 std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent());
2582 else
2584 nMaxRight += std::min(
2585 mpBorders[0].nPos, GetRightIndent() -
2586 std::max(GetFirstLineIndent(), GetLeftIndent()));
2589 else if ( mxColumnItem->Count() > 1 )
2591 nMaxRight += mpBorders[0].nPos;
2593 else
2595 nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent());
2597 // Do not drag the left table edge over the edge of the page
2598 if(mxLRSpaceItem && mxColumnItem->IsTable())
2600 tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft());
2601 if(nTmp>nMaxLeft)
2602 nMaxLeft=nTmp;
2606 break;
2608 case RulerType::Margin2:
2609 { // right edge of the surrounding Frame
2610 mxRulerImpl->lMaxRightLogic
2611 = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth();
2612 nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
2614 if (!mxColumnItem)
2616 if(bRTL)
2618 nMaxLeft = GetMargin2() + GetRightIndent() -
2619 std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
2620 glMinFrame + lNullPix;
2622 else
2624 nMaxLeft = GetMargin2() - GetRightIndent() +
2625 std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
2626 glMinFrame + lNullPix;
2629 else if(mxRulerImpl->bIsTableRows)
2631 // get the bottom move range from the last border position - only available for rows!
2632 // protection of content means the margin is not moveable
2633 if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected())
2635 nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix;
2637 else
2639 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2641 nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix;
2643 else
2645 if(mxColumnItem->Count() > 1)
2646 nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix;
2647 else
2648 nMaxLeft = glMinFrame + lNullPix;
2650 if(mxColumnItem->Count() > 1)
2651 nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix;
2652 else
2653 nMaxRight -= GetRightIndent() - lNullPix;
2656 else
2658 nMaxLeft = glMinFrame + lNullPix;
2659 if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column
2661 if(bRTL)
2663 nMaxLeft = glMinFrame + lNullPix + GetMargin2() +
2664 GetRightIndent() - std::max(GetFirstLineIndent(),
2665 GetLeftIndent());
2667 else
2669 nMaxLeft = glMinFrame + lNullPix + GetMargin2() -
2670 GetRightIndent() + std::max(GetFirstLineIndent(),
2671 GetLeftIndent());
2674 if( mxColumnItem->Count() >= 2 )
2676 tools::Long nNewMaxLeft =
2677 glMinFrame + lNullPix +
2678 mpBorders[mxColumnItem->Count() - 2].nPos +
2679 mpBorders[mxColumnItem->Count() - 2].nWidth;
2680 nMaxLeft = std::max(nMaxLeft, nNewMaxLeft);
2684 break;
2686 case RulerType::Border:
2687 { // Table, column (Modifier)
2688 const sal_uInt16 nIdx = GetDragAryPos();
2689 switch(GetDragSize())
2691 case RulerDragSize::N1 :
2693 nMaxRight = mpBorders[nIdx].nPos +
2694 mpBorders[nIdx].nWidth + lNullPix;
2696 if(0 == nIdx)
2697 nMaxLeft = lNullPix;
2698 else
2699 nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix;
2700 if(nIdx == mxColumnItem->GetActColumn())
2702 if(bRTL)
2704 nMaxLeft += mpBorders[nIdx].nPos +
2705 GetRightIndent() - std::max(GetFirstLineIndent(),
2706 GetLeftIndent());
2708 else
2710 nMaxLeft += mpBorders[nIdx].nPos -
2711 GetRightIndent() + std::max(GetFirstLineIndent(),
2712 GetLeftIndent());
2714 if(0 != nIdx)
2715 nMaxLeft -= mpBorders[nIdx-1].nPos +
2716 mpBorders[nIdx-1].nWidth;
2718 nMaxLeft += glMinFrame;
2719 nMaxLeft += nDragOffset;
2720 break;
2722 case RulerDragSize::Move:
2724 if (mxColumnItem)
2726 //nIdx contains the position of the currently moved item
2727 //next visible separator on the left
2728 sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx);
2729 //next visible separator on the right
2730 sal_uInt16 nRightCol=GetActRightColumn(false, nIdx);
2731 //next separator on the left - regardless if visible or not
2732 sal_uInt16 nActLeftCol=GetActLeftColumn();
2733 //next separator on the right - regardless if visible or not
2734 sal_uInt16 nActRightCol=GetActRightColumn();
2735 if(mxColumnItem->IsTable())
2737 if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)
2739 //the current row/column should be modified only
2740 //then the next/previous visible border position
2741 //marks the min/max positions
2742 nMaxLeft = nLeftCol == USHRT_MAX ?
2744 mpBorders[nLeftCol].nPos;
2745 //rows can always be increased without a limit
2746 if(mxRulerImpl->bIsTableRows)
2747 nMaxRight = mpBorders[nIdx].nMaxPos;
2748 else
2749 nMaxRight = nRightCol == USHRT_MAX ?
2750 GetMargin2():
2751 mpBorders[nRightCol].nPos;
2752 nMaxLeft += lNullPix;
2753 nMaxRight += lNullPix;
2755 else
2757 if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows)
2758 nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix;
2759 else
2760 nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix;
2761 if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2762 (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2764 if(mxRulerImpl->bIsTableRows)
2766 if(bHorz)
2767 nMaxRight = GetRightIndent() + lNullPix -
2768 (mxColumnItem->Count() - nIdx - 1) * glMinFrame;
2769 else
2770 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2772 else
2773 nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2775 else
2776 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2778 nMaxLeft += glMinFrame;
2779 nMaxRight -= glMinFrame;
2782 else
2784 if(nLeftCol==USHRT_MAX)
2785 nMaxLeft=lNullPix;
2786 else
2787 nMaxLeft = mpBorders[nLeftCol].nPos +
2788 mpBorders[nLeftCol].nWidth + lNullPix;
2790 if(nActRightCol == nIdx)
2792 if(bRTL)
2794 nMaxLeft += mpBorders[nIdx].nPos +
2795 GetRightIndent() - std::max(GetFirstLineIndent(),
2796 GetLeftIndent());
2797 if(nActLeftCol!=USHRT_MAX)
2798 nMaxLeft -= mpBorders[nActLeftCol].nPos +
2799 mpBorders[nActLeftCol].nWidth;
2801 else
2803 nMaxLeft += mpBorders[nIdx].nPos -
2804 GetRightIndent() + std::max(GetFirstLineIndent(),
2805 GetLeftIndent());
2806 if(nActLeftCol!=USHRT_MAX)
2807 nMaxLeft -= mpBorders[nActLeftCol].nPos +
2808 mpBorders[nActLeftCol].nWidth;
2811 nMaxLeft += glMinFrame;
2812 nMaxLeft += nDragOffset;
2814 // nMaxRight
2815 // linear / proportional move
2816 if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2817 (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2819 nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2821 else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType)
2823 nMaxRight = lNullPix + GetMargin2() - GetMargin1() +
2824 (mpBorders.size() - nIdx - 1) * glMinFrame;
2826 else
2828 if(nRightCol==USHRT_MAX)
2829 { // last column
2830 nMaxRight = GetMargin2() + lNullPix;
2831 if(IsActLastColumn())
2833 if(bRTL)
2835 nMaxRight -=
2836 GetMargin2() + GetRightIndent() -
2837 std::max(GetFirstLineIndent(),
2838 GetLeftIndent());
2840 else
2842 nMaxRight -=
2843 GetMargin2() - GetRightIndent() +
2844 std::max(GetFirstLineIndent(),
2845 GetLeftIndent());
2847 nMaxRight += mpBorders[nIdx].nPos +
2848 mpBorders[nIdx].nWidth;
2851 else
2853 nMaxRight = lNullPix + mpBorders[nRightCol].nPos;
2854 sal_uInt16 nNotHiddenRightCol =
2855 GetActRightColumn(true, nIdx);
2857 if( nActLeftCol == nIdx )
2859 tools::Long nBorder = nNotHiddenRightCol ==
2860 USHRT_MAX ?
2861 GetMargin2() :
2862 mpBorders[nNotHiddenRightCol].nPos;
2863 if(bRTL)
2865 nMaxRight -= nBorder + GetRightIndent() -
2866 std::max(GetFirstLineIndent(),
2867 GetLeftIndent());
2869 else
2871 nMaxRight -= nBorder - GetRightIndent() +
2872 std::max(GetFirstLineIndent(),
2873 GetLeftIndent());
2875 nMaxRight += mpBorders[nIdx].nPos +
2876 mpBorders[nIdx].nWidth;
2879 nMaxRight -= glMinFrame;
2880 nMaxRight -= mpBorders[nIdx].nWidth;
2884 // ObjectItem
2885 else
2887 nMaxLeft = LONG_MIN;
2888 nMaxRight = LONG_MAX;
2890 break;
2892 case RulerDragSize::N2:
2894 nMaxLeft = lNullPix + mpBorders[nIdx].nPos;
2895 if(nIdx == mxColumnItem->Count()-2) { // last column
2896 nMaxRight = GetMargin2() + lNullPix;
2897 if(mxColumnItem->IsLastAct()) {
2898 nMaxRight -=
2899 GetMargin2() - GetRightIndent() +
2900 std::max(GetFirstLineIndent(),
2901 GetLeftIndent());
2902 nMaxRight += mpBorders[nIdx].nPos +
2903 mpBorders[nIdx].nWidth;
2906 else {
2907 nMaxRight = lNullPix + mpBorders[nIdx+1].nPos;
2908 if(mxColumnItem->GetActColumn()-1 == nIdx) {
2909 nMaxRight -= mpBorders[nIdx+1].nPos - GetRightIndent() +
2910 std::max(GetFirstLineIndent(),
2911 GetLeftIndent());
2912 nMaxRight += mpBorders[nIdx].nPos +
2913 mpBorders[nIdx].nWidth;
2916 nMaxRight -= glMinFrame;
2917 nMaxRight -= mpBorders[nIdx].nWidth;
2918 break;
2921 nMaxRight += nDragOffset;
2922 break;
2924 case RulerType::Indent:
2926 const sal_uInt16 nIdx = GetDragAryPos();
2927 switch(nIdx) {
2928 case INDENT_FIRST_LINE - INDENT_GAP:
2929 case INDENT_LEFT_MARGIN - INDENT_GAP:
2931 if(bRTL)
2933 nMaxLeft = lNullPix + GetRightIndent();
2935 if(mxColumnItem && !mxColumnItem->IsFirstAct())
2936 nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
2937 mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
2938 nMaxRight = lNullPix + GetMargin2();
2940 // Dragging along
2941 if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
2942 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
2944 if(GetLeftIndent() > GetFirstLineIndent())
2945 nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
2946 else
2947 nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
2950 else
2952 nMaxLeft = lNullPix;
2954 if(mxColumnItem && !mxColumnItem->IsFirstAct())
2955 nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
2956 mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
2957 nMaxRight = lNullPix + GetRightIndent() - glMinFrame;
2959 // Dragging along
2960 if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
2961 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
2963 if(GetLeftIndent() > GetFirstLineIndent())
2964 nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
2965 else
2966 nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
2970 break;
2971 case INDENT_RIGHT_MARGIN - INDENT_GAP:
2973 if(bRTL)
2975 nMaxLeft = lNullPix;
2976 nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame;
2977 if (mxColumnItem)
2979 sal_uInt16 nRightCol=GetActRightColumn( true );
2980 if(!IsActLastColumn( true ))
2981 nMaxRight += mpBorders[nRightCol].nPos;
2982 else
2983 nMaxRight += GetMargin2();
2985 else
2987 nMaxLeft += GetMargin1();
2989 nMaxLeft += glMinFrame;
2991 else
2993 nMaxLeft = lNullPix +
2994 std::max(GetFirstLineIndent(), GetLeftIndent());
2995 nMaxRight = lNullPix;
2996 if (mxColumnItem)
2998 sal_uInt16 nRightCol=GetActRightColumn( true );
2999 if(!IsActLastColumn( true ))
3000 nMaxRight += mpBorders[nRightCol].nPos;
3001 else
3002 nMaxRight += GetMargin2();
3004 else
3005 nMaxRight += GetMargin2();
3006 nMaxLeft += glMinFrame;
3009 break;
3011 break;
3013 case RulerType::Tab: // Tabs (Modifier)
3014 /* left = NOf + Max(LAR, EZ)
3015 right = NOf + RAR */
3017 if (bRTL)
3018 nMaxLeft = lNullPix + GetRightIndent();
3019 else
3020 nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent());
3022 mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset;
3023 nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
3024 break;
3025 default: ; //prevent warning
3029 bool SvxRuler::StartDrag()
3032 Beginning of a drag operation (SV-handler) evaluates modifier and
3033 calculated values
3035 [Cross-reference]
3037 <SvxRuler::EvalModifier()>
3038 <SvxRuler::CalcMinMax()>
3039 <SvxRuler::EndDrag()>
3041 bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
3043 if(!bValid)
3044 return false;
3046 mxRulerImpl->lLastLMargin = GetMargin1();
3047 mxRulerImpl->lLastRMargin = GetMargin2();
3049 bool bOk = true;
3051 lInitialDragPos = GetDragPos();
3052 switch(GetDragType())
3054 case RulerType::Margin1: // left edge of the surrounding Frame
3055 case RulerType::Margin2: // right edge of the surrounding Frame
3056 if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem))
3058 if (!mxColumnItem)
3059 EvalModifier();
3060 else
3061 nDragType = SvxRulerDragFlags::OBJECT;
3063 else
3065 bOk = false;
3067 break;
3068 case RulerType::Border: // Table, column (Modifier)
3069 if (mxColumnItem)
3071 nDragOffset = 0;
3072 if (!mxColumnItem->IsTable())
3073 nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos;
3074 EvalModifier();
3076 else
3077 nDragOffset = 0;
3078 break;
3079 case RulerType::Indent: // Paragraph indents (Modifier)
3081 if( bContentProtected )
3082 return false;
3083 if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) { // Left paragraph indent
3084 mpIndents[0] = mpIndents[INDENT_FIRST_LINE];
3085 EvalModifier();
3087 else
3089 nDragType = SvxRulerDragFlags::OBJECT;
3091 mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP];
3092 break;
3094 case RulerType::Tab: // Tabs (Modifier)
3095 if( bContentProtected )
3096 return false;
3097 EvalModifier();
3098 mpTabs[0] = mpTabs[GetDragAryPos() + 1];
3099 mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW;
3100 break;
3101 default:
3102 nDragType = SvxRulerDragFlags::NONE;
3105 if(bOk)
3106 CalcMinMax();
3108 return bOk;
3111 void SvxRuler::Drag()
3113 /* SV-Draghandler */
3114 if(IsDragCanceled())
3116 Ruler::Drag();
3117 return;
3119 switch(GetDragType()) {
3120 case RulerType::Margin1: // left edge of the surrounding Frame
3121 DragMargin1();
3122 mxRulerImpl->lLastLMargin = GetMargin1();
3123 break;
3124 case RulerType::Margin2: // right edge of the surrounding Frame
3125 DragMargin2();
3126 mxRulerImpl->lLastRMargin = GetMargin2();
3127 break;
3128 case RulerType::Indent: // Paragraph indents
3129 DragIndents();
3130 break;
3131 case RulerType::Border: // Table, columns
3132 if (mxColumnItem)
3133 DragBorders();
3134 else if (mxObjectItem)
3135 DragObjectBorder();
3136 break;
3137 case RulerType::Tab: // Tabs
3138 DragTabs();
3139 break;
3140 default:
3141 break; //prevent warning
3143 Ruler::Drag();
3146 void SvxRuler::EndDrag()
3149 SV-handler; is called when ending the dragging. Triggers the updating of data
3150 on the application, by calling the respective Apply...() methods to send the
3151 data to the application.
3153 const bool bUndo = IsDragCanceled();
3154 const tools::Long lPos = GetDragPos();
3155 DrawLine_Impl(lTabPos, 6, bHorz);
3156 lTabPos = -1;
3158 if(!bUndo)
3160 switch(GetDragType())
3162 case RulerType::Margin1: // upper left edge of the surrounding Frame
3163 case RulerType::Margin2: // lower right edge of the surrounding Frame
3165 if (!mxColumnItem || !mxColumnItem->IsTable())
3166 ApplyMargins();
3168 if(mxColumnItem &&
3169 (mxColumnItem->IsTable() ||
3170 (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
3171 ApplyBorders();
3174 break;
3175 case RulerType::Border: // Table, columns
3176 if(lInitialDragPos != lPos ||
3177 (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here
3179 if (mxColumnItem)
3181 ApplyBorders();
3182 if(bHorz)
3183 UpdateTabs();
3185 else if (mxObjectItem)
3186 ApplyObject();
3188 break;
3189 case RulerType::Indent: // Paragraph indents
3190 if(lInitialDragPos != lPos)
3191 ApplyIndents();
3192 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
3193 break;
3194 case RulerType::Tab: // Tabs
3196 ApplyTabs();
3197 mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE;
3198 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
3200 break;
3201 default:
3202 break; //prevent warning
3205 nDragType = SvxRulerDragFlags::NONE;
3207 mbCoarseSnapping = false;
3208 mbSnapping = true;
3210 Ruler::EndDrag();
3211 if(bUndo)
3213 for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++)
3215 pCtrlItems[i]->ClearCache();
3216 pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId());
3221 void SvxRuler::ExtraDown()
3223 /* Override SV method, sets the new type for the Default tab. */
3225 // Switch Tab Type
3226 if(mxTabStopItem &&
3227 (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)
3229 ++nDefTabType;
3230 if(RULER_TAB_DEFAULT == nDefTabType)
3231 nDefTabType = RULER_TAB_LEFT;
3232 SetExtraType(RulerExtra::Tab, nDefTabType);
3234 Ruler::ExtraDown();
3237 void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint)
3240 Report through the bindings that the status update is completed. The ruler
3241 updates its appearance and gets registered again in the bindings.
3244 // start update
3245 if (bActive && rHint.GetId() == SfxHintId::UpdateDone)
3247 Update();
3248 EndListening(*pBindings);
3249 bValid = true;
3250 bListening = false;
3254 IMPL_LINK( SvxRuler, MenuSelect, Menu *, pMenu, bool )
3256 /* Handler of the context menus for switching the unit of measurement */
3257 SetUnit(vcl::StringToMetric(OUString::fromUtf8(pMenu->GetCurItemIdent())));
3258 return false;
3261 IMPL_LINK( SvxRuler, TabMenuSelect, Menu *, pMenu, bool )
3263 /* Handler of the tab menu for setting the type */
3264 if(mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx)
3266 SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx);
3267 aTabStop.GetAdjustment() = ToAttrTab_Impl(pMenu->GetCurItemId() - 1);
3268 mxTabStopItem->Remove(mxRulerImpl->nIdx);
3269 mxTabStopItem->Insert(aTabStop);
3270 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
3271 pBindings->GetDispatcher()->ExecuteList(nTabStopId,
3272 SfxCallMode::RECORD, { mxTabStopItem.get() });
3273 UpdateTabs();
3274 mxRulerImpl->nIdx = 0;
3276 return false;
3279 static const char* RID_SVXSTR_RULER_TAB[] =
3281 RID_SVXSTR_RULER_TAB_LEFT,
3282 RID_SVXSTR_RULER_TAB_RIGHT,
3283 RID_SVXSTR_RULER_TAB_CENTER,
3284 RID_SVXSTR_RULER_TAB_DECIMAL
3287 void SvxRuler::Command( const CommandEvent& rCommandEvent )
3289 /* Mouse context menu for switching the unit of measurement */
3290 if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() )
3292 CancelDrag();
3293 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
3294 if ( !mpTabs.empty() &&
3295 RulerType::Tab ==
3296 GetType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) &&
3297 mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT )
3299 ScopedVclPtrInstance<PopupMenu> aMenu;
3300 aMenu->SetSelectHdl(LINK(this, SvxRuler, TabMenuSelect));
3301 ScopedVclPtrInstance< VirtualDevice > pDev;
3302 const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2);
3303 pDev->SetOutputSize(aSz);
3304 pDev->SetBackground(Wallpaper(COL_WHITE));
3305 Color aFillColor(pDev->GetSettings().GetStyleSettings().GetShadowColor());
3306 const Point aPt(aSz.Width() / 2, aSz.Height() / 2);
3308 for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i )
3310 sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i;
3311 nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT);
3312 DrawTab(*pDev, aFillColor, aPt, nStyle);
3313 BitmapEx aItemBitmapEx(pDev->GetBitmapEx(Point(), aSz));
3314 aItemBitmapEx.Replace(COL_WHITE, COL_TRANSPARENT);
3315 aMenu->InsertItem(i + 1,
3316 SvxResId(RID_SVXSTR_RULER_TAB[i]),
3317 Image(aItemBitmapEx));
3318 aMenu->CheckItem(i + 1, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle);
3319 pDev->SetOutputSize(aSz); // delete device
3321 aMenu->Execute( this, rCommandEvent.GetMousePosPixel() );
3323 else
3325 VclBuilder aBuilder(nullptr, AllSettings::GetUIRootDir(), "svx/ui/rulermenu.ui", "");
3326 VclPtr<PopupMenu> aMenu(aBuilder.get_menu("menu"));
3327 aMenu->SetSelectHdl(LINK(this, SvxRuler, MenuSelect));
3328 FieldUnit eUnit = GetUnit();
3329 const sal_uInt16 nCount = aMenu->GetItemCount();
3331 bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC);
3332 for ( sal_uInt16 i = nCount; i; --i )
3334 sal_uInt16 nId = aMenu->GetItemId(i - 1);
3335 OString sIdent = aMenu->GetItemIdent(nId);
3336 FieldUnit eMenuUnit = vcl::StringToMetric(OUString::fromUtf8(sIdent));
3337 aMenu->CheckItem(nId, eMenuUnit == eUnit);
3338 if( bReduceMetric )
3340 if (eMenuUnit == FieldUnit::M ||
3341 eMenuUnit == FieldUnit::KM ||
3342 eMenuUnit == FieldUnit::FOOT ||
3343 eMenuUnit == FieldUnit::MILE)
3345 aMenu->RemoveItem(i - 1);
3347 else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz )
3349 aMenu->RemoveItem(i - 1);
3351 else if (( eMenuUnit == FieldUnit::LINE ) && bHorz )
3353 aMenu->RemoveItem(i - 1);
3357 aMenu->Execute( this, rCommandEvent.GetMousePosPixel() );
3360 else
3362 Ruler::Command( rCommandEvent );
3366 sal_uInt16 SvxRuler::GetActRightColumn(
3367 bool bForceDontConsiderHidden,
3368 sal_uInt16 nAct ) const
3370 if( nAct == USHRT_MAX )
3371 nAct = mxColumnItem->GetActColumn();
3372 else
3373 nAct++; //To be able to pass on the ActDrag
3375 bool bConsiderHidden = !bForceDontConsiderHidden &&
3376 !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3378 while( nAct < mxColumnItem->Count() - 1 )
3380 if (mxColumnItem->At(nAct).bVisible || bConsiderHidden)
3381 return nAct;
3382 else
3383 nAct++;
3385 return USHRT_MAX;
3388 sal_uInt16 SvxRuler::GetActLeftColumn(
3389 bool bForceDontConsiderHidden,
3390 sal_uInt16 nAct ) const
3392 if(nAct == USHRT_MAX)
3393 nAct = mxColumnItem->GetActColumn();
3395 sal_uInt16 nLeftOffset = 1;
3397 bool bConsiderHidden = !bForceDontConsiderHidden &&
3398 !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3400 while(nAct >= nLeftOffset)
3402 if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden)
3403 return nAct - nLeftOffset;
3404 else
3405 nLeftOffset++;
3407 return USHRT_MAX;
3410 bool SvxRuler::IsActLastColumn(
3411 bool bForceDontConsiderHidden,
3412 sal_uInt16 nAct) const
3414 return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3417 bool SvxRuler::IsActFirstColumn(
3418 bool bForceDontConsiderHidden,
3419 sal_uInt16 nAct) const
3421 return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3424 tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const
3427 if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
3429 // Remove the minimum width for all affected columns
3430 // starting from the right edge
3431 tools::Long _nMaxRight = GetMargin2() - GetMargin1();
3433 tools::Long lFences = 0;
3434 tools::Long lMinSpace = USHRT_MAX;
3435 tools::Long lOldPos;
3436 tools::Long lColumns = 0;
3438 sal_uInt16 nStart;
3439 if(!mxColumnItem->IsTable())
3441 if(nCol == USHRT_MAX)
3443 lOldPos = GetMargin1();
3444 nStart = 0;
3446 else
3448 lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth;
3449 nStart = nCol + 1;
3450 lFences = mpBorders[nCol].nWidth;
3453 for(size_t i = nStart; i < mpBorders.size() - 1; ++i)
3455 tools::Long lWidth = mpBorders[i].nPos - lOldPos;
3456 lColumns += lWidth;
3457 if(lWidth < lMinSpace)
3458 lMinSpace = lWidth;
3459 lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth;
3460 lFences += mpBorders[i].nWidth;
3462 tools::Long lWidth = GetMargin2() - lOldPos;
3463 lColumns += lWidth;
3464 if(lWidth < lMinSpace)
3465 lMinSpace = lWidth;
3467 else
3469 sal_uInt16 nActCol;
3470 if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin
3472 lOldPos = GetMargin1();
3474 else
3476 lOldPos = mpBorders[nCol].nPos;
3478 lColumns = GetMargin2()-lOldPos;
3479 nActCol = nCol;
3480 lFences = 0;
3481 while(nActCol < mpBorders.size() || nActCol == USHRT_MAX)
3483 sal_uInt16 nRight;
3484 if(nActCol == USHRT_MAX)
3486 nRight = 0;
3487 while (!(*mxColumnItem)[nRight].bVisible)
3489 nRight++;
3492 else
3494 nRight = GetActRightColumn(false, nActCol);
3497 tools::Long lWidth;
3498 if(nRight != USHRT_MAX)
3500 lWidth = mpBorders[nRight].nPos - lOldPos;
3501 lOldPos = mpBorders[nRight].nPos;
3503 else
3505 lWidth=GetMargin2() - lOldPos;
3507 nActCol = nRight;
3508 if(lWidth < lMinSpace)
3509 lMinSpace = lWidth;
3510 if(nActCol == USHRT_MAX)
3511 break;
3515 _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns);
3516 return _nMaxRight;
3518 else
3520 if(mxColumnItem->IsTable())
3522 sal_uInt16 nVisCols = 0;
3523 for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();)
3525 if ((*mxColumnItem)[i].bVisible)
3526 nVisCols++;
3527 i = GetActRightColumn(false, i);
3529 return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame;
3531 else
3533 tools::Long lWidth = 0;
3534 for(size_t i = nCol; i < mpBorders.size() - 1; i++)
3536 lWidth += glMinFrame + mpBorders[i].nWidth;
3538 return GetMargin2() - GetMargin1() - lWidth;
3543 // Tab stops relative to indent (#i24363#)
3544 void SvxRuler::SetTabsRelativeToIndent( bool bRel )
3546 mxRulerImpl->bIsTabsRelativeToIndent = bRel;
3549 void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue)
3551 if (diffValue == 0)
3552 return;
3554 if (type == RulerChangeType::MARGIN1)
3555 AdjustMargin1(diffValue);
3556 else if (type == RulerChangeType::MARGIN2)
3557 SetMargin2( GetMargin2() - diffValue);
3558 ApplyMargins();