Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / dialog / svxruler.cxx
blobffc34cd5bfb5012a11c1460708384f468e560d39
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cstring>
21 #include <climits>
23 #include <vcl/commandevent.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/fieldvalues.hxx>
26 #include <vcl/settings.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/weldutils.hxx>
30 #include <svl/eitem.hxx>
31 #include <svl/rectitem.hxx>
32 #include <svl/hint.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include <svx/strings.hrc>
35 #include <svx/svxids.hrc>
36 #include <svx/dialmgr.hxx>
37 #include <svx/ruler.hxx>
38 #include <svx/rulritem.hxx>
39 #include <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>
45 #include <o3tl/string_view.hxx>
47 #include "rlrcitem.hxx"
48 #include <memory>
50 #define CTRL_ITEM_COUNT 14
51 #define GAP 10
52 #define OBJECT_BORDER_COUNT 4
53 #define TAB_GAP 1
54 #define INDENT_GAP 2
55 #define INDENT_FIRST_LINE 2
56 #define INDENT_LEFT_MARGIN 3
57 #define INDENT_RIGHT_MARGIN 4
58 #define INDENT_COUNT 3 //without the first two old values
60 struct SvxRuler_Impl {
61 std::unique_ptr<sal_uInt16[]> pPercBuf;
62 std::unique_ptr<sal_uInt16[]> pBlockBuf;
63 sal_uInt16 nPercSize;
64 tools::Long nTotalDist;
65 tools::Long lOldWinPos;
66 tools::Long lMaxLeftLogic;
67 tools::Long lMaxRightLogic;
68 tools::Long lLastLMargin;
69 tools::Long lLastRMargin;
70 std::unique_ptr<SvxProtectItem> aProtectItem;
71 std::unique_ptr<SfxBoolItem> pTextRTLItem;
72 sal_uInt16 nControllerItems;
73 sal_uInt16 nIdx;
74 sal_uInt16 nColLeftPix;
75 sal_uInt16 nColRightPix; // Pixel values for left / right edge
76 // For columns; buffered to prevent
77 // recalculation errors
78 // May be has to be widen for future values
79 bool bIsTableRows : 1; // mxColumnItem contains table rows instead of columns
80 //#i24363# tab stops relative to indent
81 bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent?
82 // false means relative to SvxRuler::GetLeftFrameMargin()
84 SvxRuler_Impl() :
85 nPercSize(0), nTotalDist(0),
86 lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0),
87 lLastLMargin(0), lLastRMargin(0),
88 aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)),
89 nControllerItems(0), nIdx(0),
90 nColLeftPix(0), nColRightPix(0),
91 bIsTableRows(false),
92 bIsTabsRelativeToIndent(true)
96 void SetPercSize(sal_uInt16 nSize);
100 static RulerTabData ruler_tab_svx =
102 0, // DPIScaleFactor to be set
103 7, // ruler_tab_width
104 6, // ruler_tab_height
105 0, // ruler_tab_height2
106 0, // ruler_tab_width2
107 0, // ruler_tab_cwidth
108 0, // ruler_tab_cwidth2
109 0, // ruler_tab_cwidth3
110 0, // ruler_tab_cwidth4
111 0, // ruler_tab_dheight
112 0, // ruler_tab_dheight2
113 0, // ruler_tab_dwidth
114 0, // ruler_tab_dwidth2
115 0, // ruler_tab_dwidth3
116 0, // ruler_tab_dwidth4
117 0 // ruler_tab_textoff
120 void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize)
122 if(nSize > nPercSize)
124 nPercSize = nSize;
125 pPercBuf.reset( new sal_uInt16[nPercSize] );
126 pBlockBuf.reset( new sal_uInt16[nPercSize] );
128 size_t nSize2 = sizeof(sal_uInt16) * nPercSize;
129 memset(pPercBuf.get(), 0, nSize2);
130 memset(pBlockBuf.get(), 0, nSize2);
133 // Constructor of the ruler
135 // SID_ATTR_ULSPACE, SID_ATTR_LRSPACE
136 // expects as parameter SvxULSpaceItem for page edge
137 // (either left/right or top/bottom)
138 // Ruler: SetMargin1, SetMargin2
140 // SID_RULER_PAGE_POS
141 // expects as parameter the initial value of the page and page width
142 // Ruler: SetPagePos
144 // SID_ATTR_TABSTOP
145 // expects: SvxTabStopItem
146 // Ruler: SetTabs
148 // SID_ATTR_PARA_LRSPACE
149 // left, right paragraph edge in H-ruler
150 // Ruler: SetIndents
152 // SID_RULER_BORDERS
153 // Table borders, columns
154 // expects: something like SwTabCols
155 // Ruler: SetBorders
157 constexpr tools::Long glMinFrame = 5; // minimal frame width in pixels
159 SvxRuler::SvxRuler(
160 vcl::Window* pParent, // StarView Parent
161 vcl::Window* pWin, // Output window: is used for conversion
162 // logical units <-> pixels
163 SvxRulerSupportFlags flags, // Display flags, see ruler.hxx
164 SfxBindings &rBindings, // associated Bindings
165 WinBits nWinStyle) : // StarView WinBits
166 Ruler(pParent, nWinStyle),
167 pCtrlItems(CTRL_ITEM_COUNT),
168 pEditWin(pWin),
169 mxRulerImpl(new SvxRuler_Impl),
170 bAppSetNullOffset(false), // Is the 0-offset of the ruler set by the application?
171 lLogicNullOffset(0),
172 lAppNullOffset(LONG_MAX),
173 lInitialDragPos(0),
174 nFlags(flags),
175 nDragType(SvxRulerDragFlags::NONE),
176 nDefTabType(RULER_TAB_LEFT),
177 nTabCount(0),
178 nTabBufSize(0),
179 lDefTabDist(50),
180 lTabPos(-1),
181 mpBorders(1), // due to one column tables
182 pBindings(&rBindings),
183 nDragOffset(0),
184 nMaxLeft(0),
185 nMaxRight(0),
186 bValid(false),
187 bListening(false),
188 bActive(true),
189 mbCoarseSnapping(false),
190 mbSnapping(true)
193 /* Constructor; Initialize data buffer; controller items are created */
195 rBindings.EnterRegistrations();
197 // Create Supported Items
198 sal_uInt16 i = 0;
200 // Page edges
201 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings));
202 if((nWinStyle & WB_VSCROLL) == WB_VSCROLL)
204 bHorz = false;
205 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings));
207 else
209 bHorz = true;
210 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings));
213 // Page Position
214 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings));
216 if(nFlags & SvxRulerSupportFlags::TABS)
218 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
219 pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings));
220 SetExtraType(RulerExtra::Tab, nDefTabType);
223 if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
225 if(bHorz)
226 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings));
227 else
228 pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings));
230 mpIndents.resize(5 + INDENT_GAP);
232 for(RulerIndent & rIndent : mpIndents)
234 rIndent.nPos = 0;
235 rIndent.nStyle = RulerIndentStyle::Top;
238 mpIndents[0].nStyle = RulerIndentStyle::Top;
239 mpIndents[1].nStyle = RulerIndentStyle::Top;
240 mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top;
241 mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom;
242 mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom;
245 if( (nFlags & SvxRulerSupportFlags::BORDERS) == SvxRulerSupportFlags::BORDERS )
247 pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings));
248 pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings));
251 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings));
253 if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT )
255 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings));
256 mpObjectBorders.resize(OBJECT_BORDER_COUNT);
257 for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder)
259 mpObjectBorders[nBorder].nPos = 0;
260 mpObjectBorders[nBorder].nWidth = 0;
261 mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable;
265 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings));
266 pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings));
267 mxRulerImpl->nControllerItems=i;
269 if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET )
270 SetExtraType(RulerExtra::NullOffset);
272 rBindings.LeaveRegistrations();
274 ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor();
275 ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor;
276 ruler_tab_svx.width *= ruler_tab_svx.DPIScaleFactor;
280 SvxRuler::~SvxRuler()
282 disposeOnce();
285 void SvxRuler::dispose()
287 /* Destructor ruler; release internal buffer */
288 if(bListening)
289 EndListening(*pBindings);
291 pBindings->EnterRegistrations();
293 pCtrlItems.clear();
295 pBindings->LeaveRegistrations();
297 pEditWin.clear();
298 Ruler::dispose();
301 tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const
303 tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference);
304 tools::Long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin());
305 tools::Long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin());
307 double aTick = GetCurrentRulerUnit().nTick1;
309 if (mbCoarseSnapping)
310 aTick = GetCurrentRulerUnit().nTick2;
312 tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width();
314 double aHalfTick = aTick / 2.0;
315 double aHalfTickPixel = aTickPixel / 2.0;
317 if (aSnapToFrameMargin)
319 if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel)
320 return aLeftFramePosition;
322 if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel)
323 return aRightFramePosition;
326 if (!mbSnapping)
327 return aPosition;
329 // Move "coordinate system" to frame position so ticks are calculated correctly
330 tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel;
331 // Convert position to current selected map mode
332 tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width();
333 // Normalize -- snap to nearest tick
334 aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick;
335 // Convert back to pixels
336 aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width();
337 // Move "coordinate system" back to original position
338 return aPosition + aPointOfReferencePixel;
341 tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const
343 return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
346 tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const
348 return pEditWin->LogicToPixel(Size(0, nVal)).Height();
351 tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const
353 return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
356 tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const
358 return pEditWin->LogicToPixel(Size(0, nVal)).Height();
361 tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const
363 return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal);
366 tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const
368 return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal);
371 inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const
373 return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
376 inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const
378 return pEditWin->PixelToLogic(Size(0, nVal)).Height();
381 inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const
383 return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
386 inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const
388 return pEditWin->PixelToLogic(Size(0, nVal)).Height();
391 inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const
393 return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal);
396 inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const
398 return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal);
401 tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const
403 if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld))
404 return nVal;
405 else
406 return nValOld;
409 tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const
411 if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld))
412 return nVal;
413 else
414 return nValOld;
417 tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const
419 if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld))
420 return nVal;
421 else
422 return nValOld;
425 inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const
427 return bHorz ? nIdx : nIdx + 2;
431 Update Upper Left edge.
432 Items are translated into the representation of the ruler.
434 void SvxRuler::UpdateFrame()
436 const RulerMarginStyle nMarginStyle =
437 ( mxRulerImpl->aProtectItem->IsSizeProtected() ||
438 mxRulerImpl->aProtectItem->IsPosProtected() ) ?
439 RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
441 if(mxLRSpaceItem && mxPagePosItem)
443 // if no initialization by default app behavior
444 const tools::Long nOld = lLogicNullOffset;
445 lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft();
447 if(bAppSetNullOffset)
449 lAppNullOffset += lLogicNullOffset - nOld;
452 if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
454 Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset));
455 SetMargin1(0, nMarginStyle);
456 lAppNullOffset = 0;
458 else
460 SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle);
463 tools::Long lRight = 0;
465 // evaluate the table right edge of the table
466 if(mxColumnItem && mxColumnItem->IsTable())
467 lRight = mxColumnItem->GetRight();
468 else
469 lRight = mxLRSpaceItem->GetRight();
471 tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset;
472 tools::Long aWidthPixel = ConvertHPosPixel(aWidth);
474 SetMargin2(aWidthPixel, nMarginStyle);
476 else if(mxULSpaceItem && mxPagePosItem)
478 // relative the upper edge of the surrounding frame
479 const tools::Long nOld = lLogicNullOffset;
480 lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper();
482 if(bAppSetNullOffset)
484 lAppNullOffset += lLogicNullOffset - nOld;
487 if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
489 Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset));
490 lAppNullOffset = 0;
491 SetMargin1(0, nMarginStyle);
493 else
495 SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle);
498 tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower();
499 tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset;
500 tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2);
502 SetMargin2(nMargin2Pixel, nMarginStyle);
504 else
506 // turns off the view
507 SetMargin1();
508 SetMargin2();
511 if (mxColumnItem)
513 mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft()));
514 mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight()));
518 void SvxRuler::MouseMove( const MouseEvent& rMEvt )
520 if( bActive )
522 pBindings->Update( SID_RULER_LR_MIN_MAX );
523 pBindings->Update( SID_ATTR_LONG_ULSPACE );
524 pBindings->Update( SID_ATTR_LONG_LRSPACE );
525 pBindings->Update( SID_RULER_PAGE_POS );
526 pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
527 pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
528 pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
529 pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
530 pBindings->Update( SID_RULER_OBJECT );
531 pBindings->Update( SID_RULER_PROTECT );
534 Ruler::MouseMove( rMEvt );
536 RulerSelection aSelection = GetHoverSelection();
538 if (aSelection.eType == RulerType::DontKnow)
540 SetQuickHelpText("");
541 return;
544 RulerUnitData aUnitData = GetCurrentRulerUnit();
545 double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
546 sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor));
547 OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr);
549 switch (aSelection.eType)
551 case RulerType::Indent:
553 if (!mxParaItem)
554 break;
556 tools::Long nIndex = aSelection.nAryPos + INDENT_GAP;
558 tools::Long nIndentValue = 0.0;
559 if (nIndex == INDENT_LEFT_MARGIN)
560 nIndentValue = mxParaItem->GetTextLeft();
561 else if (nIndex == INDENT_FIRST_LINE)
562 nIndentValue = mxParaItem->GetTextFirstLineOffset();
563 else if (nIndex == INDENT_RIGHT_MARGIN)
564 nIndentValue = mxParaItem->GetRight();
566 double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
567 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
569 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
570 break;
572 case RulerType::Border:
574 if (mxColumnItem == nullptr)
575 break;
577 SvxColumnItem& aColumnItem = *mxColumnItem;
579 if (aSelection.nAryPos + 1 >= aColumnItem.Count())
580 break;
582 double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
583 fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces);
584 double fEnd = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
585 fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces);
587 SetQuickHelpText(
588 OUString::number(fStart) + " " + sUnit + " - " +
589 OUString::number(fEnd) + " " + sUnit );
590 break;
592 case RulerType::Margin1:
594 tools::Long nLeft = 0.0;
595 if (mxLRSpaceItem)
596 nLeft = mxLRSpaceItem->GetLeft();
597 else if (mxULSpaceItem)
598 nLeft = mxULSpaceItem->GetUpper();
599 else
600 break;
602 double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
603 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
604 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
606 break;
608 case RulerType::Margin2:
610 tools::Long nRight = 0.0;
611 if (mxLRSpaceItem)
612 nRight = mxLRSpaceItem->GetRight();
613 else if (mxULSpaceItem)
614 nRight = mxULSpaceItem->GetLower();
615 else
616 break;
618 double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
619 fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
620 SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
622 break;
624 default:
626 SetQuickHelpText("");
627 break;
632 void SvxRuler::StartListening_Impl()
634 if(!bListening)
636 bValid = false;
637 StartListening(*pBindings);
638 bListening = true;
642 void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace
644 /* Store new value LRSpace; delete old ones if possible */
645 if(bActive)
647 if(pItem)
648 mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem));
649 else
650 mxLRSpaceItem.reset();
651 StartListening_Impl();
655 void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax
657 /* Set new value for MinMax; delete old ones if possible */
658 if(bActive)
660 if(pItem)
661 mxMinMaxItem.reset(new SfxRectangleItem(*pItem));
662 else
663 mxMinMaxItem.reset();
668 void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value
670 /* Update Right/bottom margin */
671 if(bActive && !bHorz)
673 if(pItem)
674 mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem));
675 else
676 mxULSpaceItem.reset();
677 StartListening_Impl();
681 void SvxRuler::Update( const SvxProtectItem* pItem )
683 if( pItem )
684 mxRulerImpl->aProtectItem.reset(pItem->Clone());
687 void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem)
689 if(bActive && bHorz)
691 mxRulerImpl->pTextRTLItem.reset();
692 if(pItem)
693 mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem));
694 SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue());
695 StartListening_Impl();
699 void SvxRuler::Update(
700 const SvxColumnItem *pItem, // new value
701 sal_uInt16 nSID) //Slot Id to identify NULL items
703 /* Set new value for column view */
704 if(!bActive)
705 return;
707 if(pItem)
709 mxColumnItem.reset(new SvxColumnItem(*pItem));
710 mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL);
711 if(!bHorz && !mxRulerImpl->bIsTableRows)
712 mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL);
714 else if(mxColumnItem && mxColumnItem->Which() == nSID)
715 //there are two groups of column items table/frame columns and table rows
716 //both can occur in vertical or horizontal mode
717 //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL
718 //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS
719 //if mxColumnItem is already set with one of the ids then a NULL pItem argument
720 //must not delete it
722 mxColumnItem.reset();
723 mxRulerImpl->bIsTableRows = false;
725 StartListening_Impl();
729 void SvxRuler::UpdateColumns()
731 /* Update column view */
732 if(mxColumnItem && mxColumnItem->Count() > 1)
734 mpBorders.resize(mxColumnItem->Count());
736 RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable;
738 bool bProtectColumns =
739 mxRulerImpl->aProtectItem->IsSizeProtected() ||
740 mxRulerImpl->aProtectItem->IsPosProtected();
742 if( !bProtectColumns )
744 nStyleFlags |= RulerBorderStyle::Moveable;
745 if( !mxColumnItem->IsTable() )
746 nStyleFlags |= RulerBorderStyle::Sizeable;
749 sal_uInt16 nBorders = mxColumnItem->Count();
751 if(!mxRulerImpl->bIsTableRows)
752 --nBorders;
754 for(sal_uInt16 i = 0; i < nBorders; ++i)
756 mpBorders[i].nStyle = nStyleFlags;
757 if(!mxColumnItem->At(i).bVisible)
758 mpBorders[i].nStyle |= RulerBorderStyle::Invisible;
760 mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset);
762 if(mxColumnItem->Count() == i + 1)
764 //with table rows the end of the table is contained in the
765 //column item but it has no width!
766 mpBorders[i].nWidth = 0;
768 else
770 mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd);
772 mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset);
773 mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset);
775 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
777 else
779 SetBorders();
783 void SvxRuler::UpdateObject()
785 /* Update view of object representation */
786 if (mxObjectItem)
788 DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer");
789 // !! to the page margin
790 tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
791 mpObjectBorders[0].nPos =
792 ConvertPosPixel(mxObjectItem->GetStartX() -
793 nMargin + lAppNullOffset);
794 mpObjectBorders[1].nPos =
795 ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset);
796 nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
797 mpObjectBorders[2].nPos =
798 ConvertPosPixel(mxObjectItem->GetStartY() -
799 nMargin + lAppNullOffset);
800 mpObjectBorders[3].nPos =
801 ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset);
803 const sal_uInt16 nOffset = GetObjectBordersOff(0);
804 SetBorders(2, mpObjectBorders.data() + nOffset);
806 else
808 SetBorders();
812 void SvxRuler::UpdatePara()
815 /* Update the view for paragraph indents:
816 Left margin, first line indent, right margin paragraph update
817 mpIndents[0] = Buffer for old intent
818 mpIndents[1] = Buffer for old intent
819 mpIndents[INDENT_FIRST_LINE] = first line indent
820 mpIndents[INDENT_LEFT_MARGIN] = left margin
821 mpIndents[INDENT_RIGHT_MARGIN] = right margin
824 // Dependence on PagePosItem
825 if (mxParaItem && mxPagePosItem && !mxObjectItem)
827 bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
828 // First-line indent is negative to the left paragraph margin
829 tools::Long nLeftFrameMargin = GetLeftFrameMargin();
830 tools::Long nRightFrameMargin = GetRightFrameMargin();
831 SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin));
832 SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin));
834 tools::Long leftMargin;
835 tools::Long leftFirstLine;
836 tools::Long rightMargin;
838 if(bRTLText)
840 leftMargin = nRightFrameMargin - mxParaItem->GetTextLeft() + lAppNullOffset;
841 leftFirstLine = leftMargin - mxParaItem->GetTextFirstLineOffset();
842 rightMargin = nLeftFrameMargin + mxParaItem->GetRight() + lAppNullOffset;
844 else
846 leftMargin = nLeftFrameMargin + mxParaItem->GetTextLeft() + lAppNullOffset;
847 leftFirstLine = leftMargin + mxParaItem->GetTextFirstLineOffset();
848 rightMargin = nRightFrameMargin - mxParaItem->GetRight() + lAppNullOffset;
851 mpIndents[INDENT_LEFT_MARGIN].nPos = ConvertHPosPixel(leftMargin);
852 mpIndents[INDENT_FIRST_LINE].nPos = ConvertHPosPixel(leftFirstLine);
853 mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin);
855 mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst();
857 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
859 else
861 if(!mpIndents.empty())
863 mpIndents[INDENT_FIRST_LINE].nPos = 0;
864 mpIndents[INDENT_LEFT_MARGIN].nPos = 0;
865 mpIndents[INDENT_RIGHT_MARGIN].nPos = 0;
867 SetIndents(); // turn off
871 void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents
873 /* Store new value of paragraph indents */
874 if(bActive)
876 if(pItem)
877 mxParaItem.reset(new SvxLRSpaceItem(*pItem));
878 else
879 mxParaItem.reset();
880 StartListening_Impl();
884 void SvxRuler::UpdateBorder(const SvxLRSpaceItem * pItem)
886 /* Border distance */
887 if(bActive)
889 if (pItem)
890 mxBorderItem.reset(new SvxLRSpaceItem(*pItem));
891 else
892 mxBorderItem.reset();
894 StartListening_Impl();
898 void SvxRuler::UpdatePage()
900 /* Update view of position and width of page */
901 if (mxPagePosItem)
903 // all objects are automatically adjusted
904 if(bHorz)
906 SetPagePos(
907 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(),
908 pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)).
909 Width());
911 else
913 SetPagePos(
914 pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(),
915 pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())).
916 Height());
918 if(bAppSetNullOffset)
919 SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset));
921 else
923 SetPagePos();
926 tools::Long lPos = 0;
927 Point aOwnPos = GetPosPixel();
928 Point aEdtWinPos = pEditWin->GetPosPixel();
929 if( AllSettings::GetLayoutRTL() && bHorz )
931 //#i73321# in RTL the window and the ruler is not mirrored but the
932 // influence of the vertical ruler is inverted
933 Size aOwnSize = GetSizePixel();
934 Size aEdtWinSize = pEditWin->GetSizePixel();
935 lPos = aOwnSize.Width() - aEdtWinSize.Width();
936 lPos -= (aEdtWinPos - aOwnPos).X();
938 else
940 Point aPos(aEdtWinPos - aOwnPos);
941 lPos = bHorz ? aPos.X() : aPos.Y();
944 // Unfortunately, we get the offset of the edit window to the ruler never
945 // through a status message. So we set it ourselves if necessary.
946 if(lPos != mxRulerImpl->lOldWinPos)
948 mxRulerImpl->lOldWinPos=lPos;
949 SetWinPos(lPos);
953 void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes
955 /* Store new value of page attributes */
956 if(bActive)
958 if(pItem)
959 mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem));
960 else
961 mxPagePosItem.reset();
962 StartListening_Impl();
966 void SvxRuler::SetDefTabDist(tools::Long inDefTabDist) // New distance for DefaultTabs in App-Metrics
968 if (lAppNullOffset == LONG_MAX)
969 UpdateFrame(); // hack: try to get lAppNullOffset initialized
970 /* New distance is set for DefaultTabs */
971 lDefTabDist = inDefTabDist;
972 if( !lDefTabDist )
973 lDefTabDist = 1;
975 UpdateTabs();
978 static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj)
980 /* Internal conversion routine between SV-Tab.-Enum and Svx */
981 switch(eAdj) {
982 case SvxTabAdjust::Left: return RULER_TAB_LEFT;
983 case SvxTabAdjust::Right: return RULER_TAB_RIGHT;
984 case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL;
985 case SvxTabAdjust::Center: return RULER_TAB_CENTER;
986 case SvxTabAdjust::Default: return RULER_TAB_DEFAULT;
987 default: ; //prevent warning
989 return 0;
992 static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj)
994 switch(eAdj) {
995 case RULER_TAB_LEFT: return SvxTabAdjust::Left ;
996 case RULER_TAB_RIGHT: return SvxTabAdjust::Right ;
997 case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ;
998 case RULER_TAB_CENTER: return SvxTabAdjust::Center ;
999 case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ;
1001 return SvxTabAdjust::Left;
1004 void SvxRuler::UpdateTabs()
1006 if(IsDrag())
1007 return;
1009 if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem)
1011 // buffer for DefaultTabStop
1012 // Distance last Tab <-> Right paragraph margin / DefaultTabDist
1013 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1015 const tools::Long nLeftFrameMargin = GetLeftFrameMargin();
1016 const tools::Long nRightFrameMargin = GetRightFrameMargin();
1018 //#i24363# tab stops relative to indent
1019 const tools::Long nParaItemTxtLeft = mxParaItem->GetTextLeft();
1021 const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft;
1022 const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft;
1024 const tools::Long lLastTab = mxTabStopItem->Count()
1025 ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos())
1026 : 0;
1027 const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab;
1028 const tools::Long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight());
1030 tools::Long lCurrentDefTabDist = lDefTabDist;
1031 if(mxTabStopItem->GetDefaultDistance())
1032 lCurrentDefTabDist = mxTabStopItem->GetDefaultDistance();
1033 tools::Long nDefTabDist = ConvertHPosPixel(lCurrentDefTabDist);
1035 const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent
1037 : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist );
1039 if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize)
1041 // 10 (GAP) in stock
1042 nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP;
1043 mpTabs.resize(nTabBufSize);
1046 nTabCount = 0;
1047 sal_uInt16 j;
1049 const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent);
1051 tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin)
1052 + lAppNullOffset;
1053 if (bRTL)
1055 lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic;
1057 tools::Long lLastTabOffsetLogic = 0;
1058 for(j = 0; j < mxTabStopItem->Count(); ++j)
1060 const SvxTabStop* pTab = &mxTabStopItem->At(j);
1061 lLastTabOffsetLogic = pTab->GetTabPos();
1062 tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic);
1063 mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos);
1064 mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment());
1065 ++nTabCount;
1068 // Adjust to previous-to-first default tab stop
1069 lLastTabOffsetLogic -= lLastTabOffsetLogic % lCurrentDefTabDist;
1071 // fill the rest with default Tabs
1072 for (j = 0; j < nDefTabBuf; ++j)
1074 //simply add the default distance to the last position
1075 lLastTabOffsetLogic += lCurrentDefTabDist;
1076 if (bRTL)
1078 mpTabs[nTabCount + TAB_GAP].nPos =
1079 ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic);
1080 if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix)
1081 break;
1083 else
1085 mpTabs[nTabCount + TAB_GAP].nPos =
1086 ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic);
1087 if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent)
1088 break;
1091 mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT;
1092 ++nTabCount;
1094 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1095 DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small");
1097 else
1099 SetTabs();
1103 void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs
1105 /* Store new value for tabs; delete old ones if possible */
1106 if(!bActive)
1107 return;
1109 if(pItem)
1111 mxTabStopItem.reset(new SvxTabStopItem(*pItem));
1112 if(!bHorz)
1113 mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL);
1115 else
1117 mxTabStopItem.reset();
1119 StartListening_Impl();
1122 void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects
1124 /* Store new value for objects */
1125 if(bActive)
1127 if(pItem)
1128 mxObjectItem.reset(new SvxObjectItem(*pItem));
1129 else
1130 mxObjectItem.reset();
1131 StartListening_Impl();
1135 void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets
1137 lAppNullOffset = lLogicNullOffset - lVal;
1138 bAppSetNullOffset = true;
1139 Ruler::SetNullOffset(ConvertSizePixel(lVal));
1140 Update();
1143 void SvxRuler::Update()
1145 /* Perform update of view */
1146 if(IsDrag())
1147 return;
1149 UpdatePage();
1150 UpdateFrame();
1151 if(nFlags & SvxRulerSupportFlags::OBJECT)
1152 UpdateObject();
1153 else
1154 UpdateColumns();
1156 if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
1157 UpdatePara();
1159 if(nFlags & SvxRulerSupportFlags::TABS)
1160 UpdateTabs();
1163 tools::Long SvxRuler::GetPageWidth() const
1165 if (!mxPagePosItem)
1166 return 0;
1167 return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
1170 inline tools::Long SvxRuler::GetFrameLeft() const
1172 /* Get Left margin in Pixels */
1173 return bAppSetNullOffset ?
1174 GetMargin1() + ConvertSizePixel(lLogicNullOffset) :
1175 Ruler::GetNullOffset();
1178 tools::Long SvxRuler::GetFirstLineIndent() const
1180 /* Get First-line indent in pixels */
1181 return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1();
1184 tools::Long SvxRuler::GetLeftIndent() const
1186 /* Get Left paragraph margin in Pixels */
1187 return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1();
1190 tools::Long SvxRuler::GetRightIndent() const
1192 /* Get Right paragraph margin in Pixels */
1193 return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2();
1196 tools::Long SvxRuler::GetLogicRightIndent() const
1198 /* Get Right paragraph margin in Logic */
1199 return mxParaItem ? GetRightFrameMargin() - mxParaItem->GetRight() : GetRightFrameMargin();
1202 // Left margin in App values, is either the margin (= 0) or the left edge of
1203 // the column that is set in the column attribute as current column.
1204 tools::Long SvxRuler::GetLeftFrameMargin() const
1206 // #126721# for some unknown reason the current column is set to 0xffff
1207 DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(),
1208 "issue #126721# - invalid current column!");
1209 tools::Long nLeft = 0;
1210 if (mxColumnItem &&
1211 mxColumnItem->Count() &&
1212 mxColumnItem->IsConsistent())
1214 nLeft = mxColumnItem->GetActiveColumnDescription().nStart;
1217 if (mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
1218 nLeft += mxBorderItem->GetLeft();
1220 return nLeft;
1223 inline tools::Long SvxRuler::GetLeftMin() const
1225 DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1226 if (mxMinMaxItem)
1228 if (bHorz)
1229 return mxMinMaxItem->GetValue().Left();
1230 else
1231 return mxMinMaxItem->GetValue().Top();
1233 return 0;
1236 inline tools::Long SvxRuler::GetRightMax() const
1238 DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
1239 if (mxMinMaxItem)
1241 if (bHorz)
1242 return mxMinMaxItem->GetValue().Right();
1243 else
1244 return mxMinMaxItem->GetValue().Bottom();
1246 return 0;
1250 tools::Long SvxRuler::GetRightFrameMargin() const
1252 /* Get right frame margin (in logical units) */
1253 if (mxColumnItem)
1255 if (!IsActLastColumn(true))
1257 return mxColumnItem->At(GetActRightColumn(true)).nEnd;
1261 tools::Long lResult = lLogicNullOffset;
1263 // If possible deduct right table entry
1264 if(mxColumnItem && mxColumnItem->IsTable())
1265 lResult += mxColumnItem->GetRight();
1266 else if(bHorz && mxLRSpaceItem)
1267 lResult += mxLRSpaceItem->GetRight();
1268 else if(!bHorz && mxULSpaceItem)
1269 lResult += mxULSpaceItem->GetLower();
1271 if (bHorz && mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
1272 lResult += mxBorderItem->GetRight();
1274 if(bHorz)
1275 lResult = mxPagePosItem->GetWidth() - lResult;
1276 else
1277 lResult = mxPagePosItem->GetHeight() - lResult;
1279 return lResult;
1282 #define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \
1283 SvxRulerSupportFlags::NEGATIVE_MARGINS )
1284 #define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() )
1286 tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight )
1289 Corrects the position within the calculated limits. The limit values are in
1290 pixels relative to the page edge.
1293 const tools::Long lNullPix = Ruler::GetNullOffset();
1294 tools::Long lDragPos = GetDragPos() + lNullPix;
1295 bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows;
1296 if((bLeft || bHoriRows) && lDragPos < nMaxLeft)
1297 lDragPos = nMaxLeft;
1298 else if((bRight||bHoriRows) && lDragPos > nMaxRight)
1299 lDragPos = nMaxRight;
1300 return lDragPos - lNullPix;
1303 static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs
1304 RulerTab* pTabs, // Tab buffer
1305 tools::Long lDiff) // difference to be added
1307 /* Helper function, move all the tabs by a fixed value */
1308 if( pTabs )
1310 for(sal_uInt16 i = 0; i < nCount; ++i)
1312 pTabs[i].nPos += lDiff;
1317 void SvxRuler::DragMargin1()
1319 /* Dragging the left edge of frame */
1320 tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG );
1322 aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false);
1324 // Check if position changed
1325 if (aDragPosition == 0)
1326 return;
1328 DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz);
1329 if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1330 DragBorders();
1331 AdjustMargin1(aDragPosition);
1334 void SvxRuler::AdjustMargin1(tools::Long lInputDiff)
1336 const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset();
1337 const tools::Long lDragPos = lInputDiff;
1339 bool bProtectColumns =
1340 mxRulerImpl->aProtectItem->IsSizeProtected() ||
1341 mxRulerImpl->aProtectItem->IsPosProtected();
1343 const RulerMarginStyle nMarginStyle =
1344 bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1346 if(!bAppSetNullOffset)
1348 tools::Long lDiff = lDragPos;
1349 SetNullOffset(nOld + lDiff);
1350 if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
1352 SetMargin2( GetMargin2() - lDiff, nMarginStyle );
1354 if (!mxColumnItem && !mxObjectItem && mxParaItem)
1356 // Right indent of the old position
1357 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1358 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1360 if (mxObjectItem)
1362 mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff;
1363 mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff;
1364 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1366 if (mxColumnItem)
1368 for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i)
1369 mpBorders[i].nPos -= lDiff;
1370 SetBorders(mxColumnItem->Count()-1, mpBorders.data());
1371 if(mxColumnItem->IsFirstAct())
1373 // Right indent of the old position
1374 if (mxParaItem)
1376 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1377 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1380 else
1382 if (mxParaItem)
1384 mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1385 mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff;
1386 mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
1387 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1390 if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1391 &&!IsActFirstColumn())
1393 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff);
1394 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1399 else
1401 tools::Long lDiff = lDragPos - nOld;
1402 SetMargin1(nOld + lDiff, nMarginStyle);
1404 if (!mxColumnItem
1405 || !(nDragType
1406 & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR
1407 | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
1409 if (!mxColumnItem && !mxObjectItem && mxParaItem)
1411 // Left indent of the old position
1412 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1413 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1414 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1417 if (mxColumnItem)
1419 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
1420 mpBorders[i].nPos += lDiff;
1421 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1422 if (mxColumnItem->IsFirstAct())
1424 // Left indent of the old position
1425 if (mxParaItem)
1427 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1428 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1429 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1432 else
1434 if (mxParaItem)
1436 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1437 mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
1438 mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff;
1439 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1443 if (mxTabStopItem)
1445 ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff);
1446 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1452 void SvxRuler::DragMargin2()
1454 /* Dragging the right edge of frame */
1455 tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG);
1456 aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false);
1457 tools::Long lDiff = aDragPosition - GetMargin2();
1459 // Check if position changed
1460 if (lDiff == 0)
1461 return;
1463 if( mxRulerImpl->bIsTableRows &&
1464 !bHorz &&
1465 mxColumnItem &&
1466 (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
1468 DragBorders();
1471 bool bProtectColumns =
1472 mxRulerImpl->aProtectItem->IsSizeProtected() ||
1473 mxRulerImpl->aProtectItem->IsPosProtected();
1475 const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
1477 SetMargin2( aDragPosition, nMarginStyle );
1479 // Right indent of the old position
1480 if ((!mxColumnItem || IsActLastColumn()) && mxParaItem)
1482 mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
1483 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1486 DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz);
1489 void SvxRuler::DragIndents()
1491 /* Dragging the paragraph indents */
1492 tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos();
1493 const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP;
1495 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
1497 if(nIndex == INDENT_RIGHT_MARGIN)
1498 aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin());
1499 else
1500 aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
1502 const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition;
1504 // Check if position changed
1505 if (lDiff == 0)
1506 return;
1508 if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN ) &&
1509 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
1511 mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
1514 mpIndents[nIndex].nPos = aDragPosition;
1516 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1517 DrawLine_Impl(lTabPos, 1, bHorz);
1520 void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal)
1523 Output routine for the ledger line when moving tabs, tables and other
1524 columns
1526 if(bHorizontal)
1528 const tools::Long nHeight = pEditWin->GetOutDev()->GetOutputSize().Height();
1529 Point aZero = pEditWin->GetMapMode().GetOrigin();
1530 if(lTabPosition != -1)
1532 pEditWin->InvertTracking(
1533 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1534 Point(lTabPosition, -aZero.Y() + nHeight)),
1535 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1537 if( nNew & 1 )
1539 tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 );
1540 nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1541 lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() );
1542 if (mxPagePosItem)
1543 lTabPosition += mxPagePosItem->GetPos().X();
1544 pEditWin->InvertTracking(
1545 tools::Rectangle( Point(lTabPosition, -aZero.Y()),
1546 Point(lTabPosition, -aZero.Y() + nHeight) ),
1547 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1550 else
1552 const tools::Long nWidth = pEditWin->GetOutDev()->GetOutputSize().Width();
1553 Point aZero = pEditWin->GetMapMode().GetOrigin();
1554 if(lTabPosition != -1)
1556 pEditWin->InvertTracking(
1557 tools::Rectangle( Point(-aZero.X(), lTabPosition),
1558 Point(-aZero.X() + nWidth, lTabPosition)),
1559 ShowTrackFlags::Split | ShowTrackFlags::Clip );
1562 if(nNew & 1)
1564 tools::Long nDrapPosition = GetCorrectedDragPos();
1565 nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
1566 lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset());
1567 if (mxPagePosItem)
1568 lTabPosition += mxPagePosItem->GetPos().Y();
1569 pEditWin->InvertTracking(
1570 tools::Rectangle( Point(-aZero.X(), lTabPosition),
1571 Point(-aZero.X()+nWidth, lTabPosition)),
1572 ShowTrackFlags::Clip | ShowTrackFlags::Split );
1577 void SvxRuler::DragTabs()
1579 /* Dragging of Tabs */
1580 tools::Long aDragPosition = GetCorrectedDragPos(true, false);
1581 aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin());
1583 sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP;
1584 tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos;
1585 if (nDiff == 0)
1586 return;
1588 DrawLine_Impl(lTabPos, 7, bHorz);
1590 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1593 for(sal_uInt16 i = nIdx; i < nTabCount; ++i)
1595 mpTabs[i].nPos += nDiff;
1596 // limit on maximum
1597 if(mpTabs[i].nPos > GetMargin2())
1598 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1599 else
1600 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1603 else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1605 mxRulerImpl->nTotalDist -= nDiff;
1606 mpTabs[nIdx].nPos = aDragPosition;
1607 for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
1609 if(mpTabs[i].nStyle & RULER_TAB_DEFAULT)
1610 // can be canceled at the DefaultTabs
1611 break;
1612 tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i];
1613 nDelta /= 1000;
1614 mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta;
1615 if(mpTabs[i].nPos + GetNullOffset() > nMaxRight)
1616 mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE;
1617 else
1618 mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE;
1621 else
1623 mpTabs[nIdx].nPos = aDragPosition;
1626 if(IsDragDelete())
1627 mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
1628 else
1629 mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
1630 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1633 void SvxRuler::SetActive(bool bOn)
1635 if(bOn)
1637 Activate();
1639 else
1640 Deactivate();
1641 if(bActive!=bOn)
1643 pBindings->EnterRegistrations();
1644 if(bOn)
1645 for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++)
1646 pCtrlItems[i]->ReBind();
1647 else
1648 for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++)
1649 pCtrlItems[j]->UnBind();
1650 pBindings->LeaveRegistrations();
1652 bActive = bOn;
1655 void SvxRuler::UpdateParaContents_Impl(
1656 tools::Long lDifference,
1657 UpdateType eType) // Art (all, left or right)
1659 /* Helper function; carry Tabs and Paragraph Margins */
1660 switch(eType)
1662 case UpdateType::MoveRight:
1663 mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference;
1664 break;
1665 case UpdateType::MoveLeft:
1667 mpIndents[INDENT_FIRST_LINE].nPos += lDifference;
1668 mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference;
1669 if (!mpTabs.empty())
1671 for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i)
1673 mpTabs[i].nPos += lDifference;
1675 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
1677 break;
1680 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
1683 void SvxRuler::DragBorders()
1685 /* Dragging of Borders (Tables and other columns) */
1686 bool bLeftIndentsCorrected = false;
1687 bool bRightIndentsCorrected = false;
1688 int nIndex;
1690 if(GetDragType() == RulerType::Border)
1692 DrawLine_Impl(lTabPos, 7, bHorz);
1693 nIndex = GetDragAryPos();
1695 else
1697 nIndex = 0;
1700 RulerDragSize nDragSize = GetDragSize();
1701 tools::Long lDiff = 0;
1703 // the drag position has to be corrected to be able to prevent borders from passing each other
1704 tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1706 switch(nDragSize)
1708 case RulerDragSize::Move:
1710 if(GetDragType() == RulerType::Border)
1711 lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos;
1712 else
1713 lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin;
1715 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
1717 tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters
1718 for(int i = mpBorders.size() - 2; i >= nIndex; --i)
1720 tools::Long l = mpBorders[i].nPos;
1721 mpBorders[i].nPos += lDiff;
1722 mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth);
1723 nRight = mpBorders[i].nPos - glMinFrame;
1724 // RR update the column
1725 if(i == GetActRightColumn())
1727 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1728 bRightIndentsCorrected = true;
1730 // LAR, EZE update the column
1731 else if(i == GetActLeftColumn())
1733 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1734 bLeftIndentsCorrected = true;
1738 else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
1740 int nLimit;
1741 tools::Long lLeft;
1742 int nStartLimit = mpBorders.size() - 2;
1743 switch(GetDragType())
1745 default: ;//prevent warning
1746 OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" );
1747 [[fallthrough]];
1748 case RulerType::Border:
1749 if(mxRulerImpl->bIsTableRows)
1751 mpBorders[nIndex].nPos += lDiff;
1752 if(bHorz)
1754 lLeft = mpBorders[nIndex].nPos;
1755 mxRulerImpl->nTotalDist -= lDiff;
1756 nLimit = nIndex + 1;
1758 else
1760 lLeft = 0;
1761 nStartLimit = nIndex - 1;
1762 mxRulerImpl->nTotalDist += lDiff;
1763 nLimit = 0;
1766 else
1768 nLimit = nIndex + 1;
1769 mpBorders[nIndex].nPos += lDiff;
1770 lLeft = mpBorders[nIndex].nPos;
1771 mxRulerImpl->nTotalDist -= lDiff;
1773 break;
1774 case RulerType::Margin1:
1775 nLimit = 0;
1776 lLeft = mxRulerImpl->lLastLMargin + lDiff;
1777 mxRulerImpl->nTotalDist -= lDiff;
1778 break;
1779 case RulerType::Margin2:
1780 nLimit = 0;
1781 lLeft= 0;
1782 nStartLimit = mpBorders.size() - 2;
1783 mxRulerImpl->nTotalDist += lDiff;
1784 break;
1787 for(int i = nStartLimit; i >= nLimit; --i)
1790 tools::Long l = mpBorders[i].nPos;
1791 mpBorders[i].nPos =
1792 lLeft +
1793 (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 +
1794 mxRulerImpl->pBlockBuf[i];
1796 // RR update the column
1797 if(!mxRulerImpl->bIsTableRows)
1799 if(i == GetActRightColumn())
1801 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
1802 bRightIndentsCorrected = true;
1804 // LAR, EZE update the column
1805 else if(i == GetActLeftColumn())
1807 UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
1808 bLeftIndentsCorrected = true;
1812 if(mxRulerImpl->bIsTableRows)
1814 //in vertical tables the left borders have to be moved
1815 if(bHorz)
1817 for(int i = 0; i < nIndex; ++i)
1818 mpBorders[i].nPos += lDiff;
1819 AdjustMargin1(lDiff);
1821 else
1823 //otherwise the right borders are moved
1824 for(int i = mxColumnItem->Count() - 1; i > nIndex; --i)
1825 mpBorders[i].nPos += lDiff;
1826 SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1830 else if(mxRulerImpl->bIsTableRows)
1832 //moving rows: if a row is resized all following rows
1833 //have to be moved by the same amount.
1834 //This includes the left border when the table is not limited
1835 //to a lower frame border.
1836 int nLimit;
1837 if(GetDragType()==RulerType::Border)
1839 nLimit = nIndex + 1;
1840 mpBorders[nIndex].nPos += lDiff;
1842 else
1844 nLimit=0;
1846 //in vertical tables the left borders have to be moved
1847 if(bHorz)
1849 for(int i = 0; i < nIndex; ++i)
1851 mpBorders[i].nPos += lDiff;
1853 AdjustMargin1(lDiff);
1855 else
1857 //otherwise the right borders are moved
1858 for(int i = mpBorders.size() - 2; i >= nLimit; --i)
1860 mpBorders[i].nPos += lDiff;
1862 SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
1865 else
1866 mpBorders[nIndex].nPos += lDiff;
1867 break;
1869 case RulerDragSize::N1:
1871 lDiff = lPos - mpBorders[nIndex].nPos;
1872 mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos;
1873 mpBorders[nIndex].nPos = lPos;
1874 break;
1876 case RulerDragSize::N2:
1878 const tools::Long nOld = mpBorders[nIndex].nWidth;
1879 mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos;
1880 lDiff = mpBorders[nIndex].nWidth - nOld;
1881 break;
1884 if(!bRightIndentsCorrected &&
1885 GetActRightColumn() == nIndex &&
1886 nDragSize != RulerDragSize::N2 &&
1887 !mpIndents.empty() &&
1888 !mxRulerImpl->bIsTableRows)
1890 UpdateParaContents_Impl(lDiff, UpdateType::MoveRight);
1892 else if(!bLeftIndentsCorrected &&
1893 GetActLeftColumn() == nIndex &&
1894 nDragSize != RulerDragSize::N1 &&
1895 !mpIndents.empty())
1897 UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft);
1899 SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
1902 void SvxRuler::DragObjectBorder()
1904 /* Dragging of object edges */
1905 if(RulerDragSize::Move == GetDragSize())
1907 const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
1909 const sal_uInt16 nIdx = GetDragAryPos();
1910 mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition;
1911 SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
1912 DrawLine_Impl(lTabPos, 7, bHorz);
1917 void SvxRuler::ApplyMargins()
1919 /* Applying margins; changed by dragging. */
1920 const SfxPoolItem* pItem = nullptr;
1921 sal_uInt16 nId = SID_ATTR_LONG_LRSPACE;
1923 if(bHorz)
1925 const tools::Long lOldNull = lLogicNullOffset;
1926 if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset())
1928 lLogicNullOffset = mxRulerImpl->lMaxLeftLogic;
1929 mxLRSpaceItem->SetLeft(lLogicNullOffset);
1931 else
1933 lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset;
1934 mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft()));
1937 if(bAppSetNullOffset)
1939 lAppNullOffset += lLogicNullOffset - lOldNull;
1942 tools::Long nRight;
1943 if(mxRulerImpl->lMaxRightLogic != -1
1944 && nMaxRight == GetMargin2() + Ruler::GetNullOffset())
1946 nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic;
1948 else
1950 nRight = std::max(tools::Long(0),
1951 mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() -
1952 (ConvertHPosLogic(GetMargin2()) - lAppNullOffset));
1954 nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight());
1956 mxLRSpaceItem->SetRight(nRight);
1958 pItem = mxLRSpaceItem.get();
1960 #ifdef DEBUGLIN
1961 Debug_Impl(pEditWin, *mxLRSpaceItem);
1962 #endif // DEBUGLIN
1965 else
1967 const tools::Long lOldNull = lLogicNullOffset;
1968 lLogicNullOffset =
1969 ConvertVPosLogic(GetFrameLeft()) -
1970 lAppNullOffset;
1971 mxULSpaceItem->SetUpper(
1972 PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper()));
1973 if(bAppSetNullOffset)
1975 lAppNullOffset += lLogicNullOffset - lOldNull;
1977 mxULSpaceItem->SetLower(
1978 PixelVAdjust(
1979 std::max(tools::Long(0), mxPagePosItem->GetHeight() -
1980 mxULSpaceItem->GetUpper() -
1981 (ConvertVPosLogic(GetMargin2()) -
1982 lAppNullOffset)), mxULSpaceItem->GetLower()));
1983 pItem = mxULSpaceItem.get();
1984 nId = SID_ATTR_LONG_ULSPACE;
1986 #ifdef DEBUGLIN
1987 Debug_Impl(pEditWin,*mxULSpaceItem);
1988 #endif // DEBUGLIN
1991 pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem });
1992 if (mxTabStopItem)
1993 UpdateTabs();
1996 tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const
1998 RulerUnitData aUnitData = GetCurrentRulerUnit();
1999 double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
2001 tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
2002 lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit;
2003 return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width();
2006 void SvxRuler::ApplyIndents()
2008 /* Applying paragraph settings; changed by dragging. */
2010 tools::Long nLeftFrameMargin = GetLeftFrameMargin();
2012 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2014 tools::Long nNewTxtLeft;
2015 tools::Long nNewFirstLineOffset;
2016 tools::Long nNewRight;
2018 tools::Long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos);
2019 tools::Long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos);
2020 tools::Long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos);
2022 if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true))))
2024 if(bRTL)
2026 tools::Long nRightColumn = GetActRightColumn(true);
2027 tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2028 nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2030 else
2032 tools::Long nLeftColumn = GetActLeftColumn(true);
2033 tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2034 nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset;
2037 else
2039 if(bRTL)
2041 tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2042 nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
2044 else
2046 tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2047 nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset;
2051 if(bRTL)
2052 nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset;
2053 else
2054 nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset;
2056 if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true))))
2058 if(bRTL)
2060 tools::Long nLeftColumn = GetActLeftColumn(true);
2061 tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
2062 nNewRight = nRightMargin - nLeftBorder - lAppNullOffset;
2064 else
2066 tools::Long nRightColumn = GetActRightColumn(true);
2067 tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
2068 nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2071 else
2073 if(bRTL)
2075 tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
2076 nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset;
2078 else
2080 tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
2081 nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
2085 if (mbSnapping)
2087 nNewTxtLeft = RoundToCurrentMapMode(nNewTxtLeft);
2088 nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset);
2089 nNewRight = RoundToCurrentMapMode(nNewRight);
2092 mxParaItem->SetTextFirstLineOffset(sal::static_int_cast<short>(nNewFirstLineOffset));
2093 mxParaItem->SetTextLeft(nNewTxtLeft);
2094 mxParaItem->SetRight(nNewRight);
2096 sal_uInt16 nParagraphId = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL;
2097 pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD,
2098 { mxParaItem.get() });
2099 UpdateTabs();
2102 void SvxRuler::ApplyTabs()
2104 /* Apply tab settings, changed by dragging. */
2105 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2106 const sal_uInt16 nCoreIdx = GetDragAryPos();
2107 if(IsDragDelete())
2109 mxTabStopItem->Remove(nCoreIdx);
2111 else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType ||
2112 SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType)
2114 SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which());
2115 //remove default tab stops
2116 for ( sal_uInt16 i = 0; i < pItem->Count(); )
2118 if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() )
2120 pItem->Remove(i);
2121 continue;
2123 ++i;
2126 sal_uInt16 j;
2127 for(j = 0; j < nCoreIdx; ++j)
2129 pItem->Insert(mxTabStopItem->At(j));
2131 for(; j < mxTabStopItem->Count(); ++j)
2133 SvxTabStop aTabStop = mxTabStopItem->At(j);
2134 aTabStop.GetTabPos() = PixelHAdjust(
2135 ConvertHPosLogic(
2136 mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset,
2137 aTabStop.GetTabPos());
2138 pItem->Insert(aTabStop);
2140 mxTabStopItem.reset(pItem);
2142 else if( mxTabStopItem->Count() == 0 )
2143 return;
2144 else
2146 SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx);
2147 if( mxRulerImpl->lMaxRightLogic != -1 &&
2148 mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight )
2150 // Set tab pos exactly at the right indent
2151 tools::Long nTmpLeftIndentLogic
2152 = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
2153 if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem)
2155 nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetTextLeft();
2157 aTabStop.GetTabPos()
2158 = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic;
2160 else
2162 if(bRTL)
2164 //#i24363# tab stops relative to indent
2165 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2166 GetLeftIndent() :
2167 ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset );
2169 tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos);
2170 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2172 else
2174 //#i24363# tab stops relative to indent
2175 const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
2176 GetLeftIndent() :
2177 ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset );
2179 tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent);
2180 aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
2183 mxTabStopItem->Remove(nCoreIdx);
2184 mxTabStopItem->Insert(aTabStop);
2186 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
2187 pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD,
2188 { mxTabStopItem.get() });
2189 UpdateTabs();
2192 void SvxRuler::ApplyBorders()
2194 /* Applying (table) column settings; changed by dragging. */
2195 if(mxColumnItem->IsTable())
2197 tools::Long lValue = GetFrameLeft();
2198 if(lValue != mxRulerImpl->nColLeftPix)
2200 tools::Long nLeft = PixelHAdjust(
2201 ConvertHPosLogic(lValue) -
2202 lAppNullOffset,
2203 mxColumnItem->GetLeft());
2204 mxColumnItem->SetLeft(nLeft);
2207 lValue = GetMargin2();
2209 if(lValue != mxRulerImpl->nColRightPix)
2211 tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
2212 tools::Long nRight = PixelHAdjust(
2213 nWidthOrHeight -
2214 mxColumnItem->GetLeft() -
2215 ConvertHPosLogic(lValue) -
2216 lAppNullOffset,
2217 mxColumnItem->GetRight() );
2218 mxColumnItem->SetRight(nRight);
2222 for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
2224 tools::Long& nEnd = mxColumnItem->At(i).nEnd;
2225 nEnd = PixelHAdjust(
2226 ConvertPosLogic(mpBorders[i].nPos),
2227 mxColumnItem->At(i).nEnd);
2228 tools::Long& nStart = mxColumnItem->At(i + 1).nStart;
2229 nStart = PixelHAdjust(
2230 ConvertSizeLogic(mpBorders[i].nPos +
2231 mpBorders[i].nWidth) -
2232 lAppNullOffset,
2233 mxColumnItem->At(i + 1).nStart);
2234 // It may be that, due to the PixelHAdjust readjustment to old values,
2235 // the width becomes < 0. This we readjust.
2236 if( nEnd > nStart )
2237 nStart = nEnd;
2240 #ifdef DEBUGLIN
2241 Debug_Impl(pEditWin,*mxColumnItem);
2242 #endif // DEBUGLIN
2244 SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY,
2245 bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY));
2247 sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) :
2248 (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2250 pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD,
2251 { mxColumnItem.get(), &aFlag });
2254 void SvxRuler::ApplyObject()
2256 /* Applying object settings, changed by dragging. */
2258 // to the page margin
2259 tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
2260 tools::Long nStartX = PixelAdjust(
2261 ConvertPosLogic(mpObjectBorders[0].nPos) +
2262 nMargin -
2263 lAppNullOffset,
2264 mxObjectItem->GetStartX());
2265 mxObjectItem->SetStartX(nStartX);
2267 tools::Long nEndX = PixelAdjust(
2268 ConvertPosLogic(mpObjectBorders[1].nPos) +
2269 nMargin -
2270 lAppNullOffset,
2271 mxObjectItem->GetEndX());
2272 mxObjectItem->SetEndX(nEndX);
2274 nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
2275 tools::Long nStartY = PixelAdjust(
2276 ConvertPosLogic(mpObjectBorders[2].nPos) +
2277 nMargin -
2278 lAppNullOffset,
2279 mxObjectItem->GetStartY());
2280 mxObjectItem->SetStartY(nStartY);
2282 tools::Long nEndY = PixelAdjust(
2283 ConvertPosLogic(mpObjectBorders[3].nPos) +
2284 nMargin -
2285 lAppNullOffset,
2286 mxObjectItem->GetEndY());
2287 mxObjectItem->SetEndY(nEndY);
2289 pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT,
2290 SfxCallMode::RECORD, { mxObjectItem.get() });
2293 void SvxRuler::PrepareProportional_Impl(RulerType eType)
2296 Preparation proportional dragging, and it is calculated based on the
2297 proportional share of the total width in parts per thousand.
2299 mxRulerImpl->nTotalDist = GetMargin2();
2300 switch(eType)
2302 case RulerType::Margin2:
2303 case RulerType::Margin1:
2304 case RulerType::Border:
2306 DBG_ASSERT(mxColumnItem, "no ColumnItem");
2308 mxRulerImpl->SetPercSize(mxColumnItem->Count());
2310 tools::Long lPos;
2311 tools::Long lWidth=0;
2312 sal_uInt16 nStart;
2313 sal_uInt16 nIdx=GetDragAryPos();
2314 tools::Long lActWidth=0;
2315 tools::Long lActBorderSum;
2316 tools::Long lOrigLPos;
2318 if(eType != RulerType::Border)
2320 lOrigLPos = GetMargin1();
2321 nStart = 0;
2322 lActBorderSum = 0;
2324 else
2326 if(mxRulerImpl->bIsTableRows &&!bHorz)
2328 lOrigLPos = GetMargin1();
2329 nStart = 0;
2331 else
2333 lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth;
2334 nStart = 1;
2336 lActBorderSum = mpBorders[nIdx].nWidth;
2339 //in horizontal mode the percentage value has to be
2340 //calculated on a "current change" position base
2341 //because the height of the table changes while dragging
2342 if(mxRulerImpl->bIsTableRows && RulerType::Border == eType)
2344 sal_uInt16 nStartBorder;
2345 sal_uInt16 nEndBorder;
2346 if(bHorz)
2348 nStartBorder = nIdx + 1;
2349 nEndBorder = mxColumnItem->Count() - 1;
2351 else
2353 nStartBorder = 0;
2354 nEndBorder = nIdx;
2357 lWidth = mpBorders[nIdx].nPos;
2358 if(bHorz)
2359 lWidth = GetMargin2() - lWidth;
2360 mxRulerImpl->nTotalDist = lWidth;
2361 lPos = mpBorders[nIdx].nPos;
2363 for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i)
2365 if(bHorz)
2367 lActWidth += mpBorders[i].nPos - lPos;
2368 lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2370 else
2371 lActWidth = mpBorders[i].nPos;
2372 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2373 / mxRulerImpl->nTotalDist);
2374 mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2375 lActBorderSum += mpBorders[i].nWidth;
2378 else
2380 lPos = lOrigLPos;
2381 for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii)
2383 lWidth += mpBorders[ii].nPos - lPos;
2384 lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth;
2387 lWidth += GetMargin2() - lPos;
2388 mxRulerImpl->nTotalDist = lWidth;
2389 lPos = lOrigLPos;
2391 for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i)
2393 lActWidth += mpBorders[i].nPos - lPos;
2394 lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
2395 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
2396 / mxRulerImpl->nTotalDist);
2397 mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
2398 lActBorderSum += mpBorders[i].nWidth;
2402 break;
2403 case RulerType::Tab:
2405 const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP;
2406 mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos;
2407 mxRulerImpl->SetPercSize(nTabCount);
2408 for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ;
2409 for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
2411 const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos;
2412 mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist);
2414 break;
2416 default: break;
2420 void SvxRuler::EvalModifier()
2423 Eval Drag Modifier
2424 Shift: move linear
2425 Control: move proportional
2426 Shift + Control: Table: only current line
2427 Alt: disable snapping
2428 Alt + Shift: coarse snapping
2431 sal_uInt16 nModifier = GetDragModifier();
2432 if(mxRulerImpl->bIsTableRows)
2434 //rows can only be moved in one way, additionally current column is possible
2435 if(nModifier == KEY_SHIFT)
2436 nModifier = 0;
2439 switch(nModifier)
2441 case KEY_SHIFT:
2442 nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR;
2443 break;
2444 case KEY_MOD2 | KEY_SHIFT:
2445 mbCoarseSnapping = true;
2446 break;
2447 case KEY_MOD2:
2448 mbSnapping = false;
2449 break;
2450 case KEY_MOD1:
2452 const RulerType eType = GetDragType();
2453 nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL;
2454 if( RulerType::Tab == eType ||
2455 ( ( RulerType::Border == eType ||
2456 RulerType::Margin1 == eType ||
2457 RulerType::Margin2 == eType ) &&
2458 mxColumnItem ) )
2460 PrepareProportional_Impl(eType);
2463 break;
2464 case KEY_MOD1 | KEY_SHIFT:
2465 if( GetDragType() != RulerType::Margin1 &&
2466 GetDragType() != RulerType::Margin2 )
2468 nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY;
2470 break;
2474 void SvxRuler::Click()
2476 /* Override handler SV; sets Tab per dispatcher call */
2477 Ruler::Click();
2478 if( bActive )
2480 pBindings->Update( SID_RULER_LR_MIN_MAX );
2481 pBindings->Update( SID_ATTR_LONG_ULSPACE );
2482 pBindings->Update( SID_ATTR_LONG_LRSPACE );
2483 pBindings->Update( SID_RULER_PAGE_POS );
2484 pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
2485 pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
2486 pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
2487 pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
2488 pBindings->Update( SID_RULER_OBJECT );
2489 pBindings->Update( SID_RULER_PROTECT );
2490 pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL );
2492 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2493 if(!(mxTabStopItem &&
2494 (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS))
2495 return;
2497 bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
2498 if( bContentProtected ) return;
2499 const tools::Long lPos = GetClickPos();
2500 if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) ||
2501 (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())))
2502 return;
2504 //convert position in left-to-right text
2505 tools::Long nTabPos;
2506 //#i24363# tab stops relative to indent
2507 if(bRTL)
2508 nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ?
2509 GetLeftIndent() :
2510 ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) -
2511 lPos;
2512 else
2513 nTabPos = lPos -
2514 ( mxRulerImpl->bIsTabsRelativeToIndent ?
2515 GetLeftIndent() :
2516 ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ));
2518 SvxTabStop aTabStop(ConvertHPosLogic(nTabPos),
2519 ToAttrTab_Impl(nDefTabType));
2520 mxTabStopItem->Insert(aTabStop);
2521 UpdateTabs();
2524 void SvxRuler::CalcMinMax()
2527 Calculates the limits for dragging; which are in pixels relative to the
2528 page edge
2530 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
2531 const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset);
2532 mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1;
2533 switch(GetDragType())
2535 case RulerType::Margin1:
2536 { // left edge of the surrounding Frame
2537 // DragPos - NOf between left - right
2538 mxRulerImpl->lMaxLeftLogic = GetLeftMin();
2539 nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic);
2541 if (!mxColumnItem || mxColumnItem->Count() == 1)
2543 if(bRTL)
2545 nMaxRight = lNullPix - GetRightIndent() +
2546 std::max(GetFirstLineIndent(), GetLeftIndent()) -
2547 glMinFrame;
2549 else
2551 nMaxRight = lNullPix + GetRightIndent() -
2552 std::max(GetFirstLineIndent(), GetLeftIndent()) -
2553 glMinFrame;
2556 else if(mxRulerImpl->bIsTableRows)
2558 //top border is not moveable when table rows are displayed
2559 // protection of content means the margin is not moveable
2560 if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected())
2562 nMaxLeft = mpBorders[0].nMinPos + lNullPix;
2563 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2564 nMaxRight = GetRightIndent() + lNullPix -
2565 (mxColumnItem->Count() - 1 ) * glMinFrame;
2566 else
2567 nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix;
2569 else
2570 nMaxLeft = nMaxRight = lNullPix;
2572 else
2574 if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2576 nMaxRight=lNullPix+CalcPropMaxRight();
2578 else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
2580 nMaxRight = ConvertPosPixel(
2581 GetPageWidth() - (
2582 (mxColumnItem->IsTable() && mxLRSpaceItem)
2583 ? mxLRSpaceItem->GetRight() : 0))
2584 - GetMargin2() + GetMargin1();
2586 else
2588 nMaxRight = lNullPix - glMinFrame;
2589 if (mxColumnItem->IsFirstAct())
2591 if(bRTL)
2593 nMaxRight += std::min(
2594 mpBorders[0].nPos,
2595 std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent());
2597 else
2599 nMaxRight += std::min(
2600 mpBorders[0].nPos, GetRightIndent() -
2601 std::max(GetFirstLineIndent(), GetLeftIndent()));
2604 else if ( mxColumnItem->Count() > 1 )
2606 nMaxRight += mpBorders[0].nPos;
2608 else
2610 nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent());
2612 // Do not drag the left table edge over the edge of the page
2613 if(mxLRSpaceItem && mxColumnItem->IsTable())
2615 tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft());
2616 if(nTmp>nMaxLeft)
2617 nMaxLeft=nTmp;
2621 break;
2623 case RulerType::Margin2:
2624 { // right edge of the surrounding Frame
2625 mxRulerImpl->lMaxRightLogic
2626 = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth();
2627 nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
2629 if (!mxColumnItem)
2631 if(bRTL)
2633 nMaxLeft = GetMargin2() + GetRightIndent() -
2634 std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
2635 glMinFrame + lNullPix;
2637 else
2639 nMaxLeft = GetMargin2() - GetRightIndent() +
2640 std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
2641 glMinFrame + lNullPix;
2644 else if(mxRulerImpl->bIsTableRows)
2646 // get the bottom move range from the last border position - only available for rows!
2647 // protection of content means the margin is not moveable
2648 if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected())
2650 nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix;
2652 else
2654 if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
2656 nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix;
2658 else
2660 if(mxColumnItem->Count() > 1)
2661 nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix;
2662 else
2663 nMaxLeft = glMinFrame + lNullPix;
2665 if(mxColumnItem->Count() > 1)
2666 nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix;
2667 else
2668 nMaxRight -= GetRightIndent() - lNullPix;
2671 else
2673 nMaxLeft = glMinFrame + lNullPix;
2674 if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column
2676 if(bRTL)
2678 nMaxLeft = glMinFrame + lNullPix + GetMargin2() +
2679 GetRightIndent() - std::max(GetFirstLineIndent(),
2680 GetLeftIndent());
2682 else
2684 nMaxLeft = glMinFrame + lNullPix + GetMargin2() -
2685 GetRightIndent() + std::max(GetFirstLineIndent(),
2686 GetLeftIndent());
2689 if( mxColumnItem->Count() >= 2 )
2691 tools::Long nNewMaxLeft =
2692 glMinFrame + lNullPix +
2693 mpBorders[mxColumnItem->Count() - 2].nPos +
2694 mpBorders[mxColumnItem->Count() - 2].nWidth;
2695 nMaxLeft = std::max(nMaxLeft, nNewMaxLeft);
2699 break;
2701 case RulerType::Border:
2702 { // Table, column (Modifier)
2703 const sal_uInt16 nIdx = GetDragAryPos();
2704 switch(GetDragSize())
2706 case RulerDragSize::N1 :
2708 nMaxRight = mpBorders[nIdx].nPos +
2709 mpBorders[nIdx].nWidth + lNullPix;
2711 if(0 == nIdx)
2712 nMaxLeft = lNullPix;
2713 else
2714 nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix;
2715 if (mxColumnItem && nIdx == mxColumnItem->GetActColumn())
2717 if(bRTL)
2719 nMaxLeft += mpBorders[nIdx].nPos +
2720 GetRightIndent() - std::max(GetFirstLineIndent(),
2721 GetLeftIndent());
2723 else
2725 nMaxLeft += mpBorders[nIdx].nPos -
2726 GetRightIndent() + std::max(GetFirstLineIndent(),
2727 GetLeftIndent());
2729 if(0 != nIdx)
2730 nMaxLeft -= mpBorders[nIdx-1].nPos +
2731 mpBorders[nIdx-1].nWidth;
2733 nMaxLeft += glMinFrame;
2734 nMaxLeft += nDragOffset;
2735 break;
2737 case RulerDragSize::Move:
2739 if (mxColumnItem)
2741 //nIdx contains the position of the currently moved item
2742 //next visible separator on the left
2743 sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx);
2744 //next visible separator on the right
2745 sal_uInt16 nRightCol=GetActRightColumn(false, nIdx);
2746 //next separator on the left - regardless if visible or not
2747 sal_uInt16 nActLeftCol=GetActLeftColumn();
2748 //next separator on the right - regardless if visible or not
2749 sal_uInt16 nActRightCol=GetActRightColumn();
2750 if(mxColumnItem->IsTable())
2752 if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)
2754 //the current row/column should be modified only
2755 //then the next/previous visible border position
2756 //marks the min/max positions
2757 nMaxLeft = nLeftCol == USHRT_MAX ?
2759 mpBorders[nLeftCol].nPos;
2760 //rows can always be increased without a limit
2761 if(mxRulerImpl->bIsTableRows)
2762 nMaxRight = mpBorders[nIdx].nMaxPos;
2763 else
2764 nMaxRight = nRightCol == USHRT_MAX ?
2765 GetMargin2():
2766 mpBorders[nRightCol].nPos;
2767 nMaxLeft += lNullPix;
2768 nMaxRight += lNullPix;
2770 else
2772 if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows)
2773 nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix;
2774 else
2775 nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix;
2776 if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2777 (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2779 if(mxRulerImpl->bIsTableRows)
2781 if(bHorz)
2782 nMaxRight = GetRightIndent() + lNullPix -
2783 (mxColumnItem->Count() - nIdx - 1) * glMinFrame;
2784 else
2785 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2787 else
2788 nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2790 else
2791 nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
2793 nMaxLeft += glMinFrame;
2794 nMaxRight -= glMinFrame;
2797 else
2799 if(nLeftCol==USHRT_MAX)
2800 nMaxLeft=lNullPix;
2801 else
2802 nMaxLeft = mpBorders[nLeftCol].nPos +
2803 mpBorders[nLeftCol].nWidth + lNullPix;
2805 if(nActRightCol == nIdx)
2807 if(bRTL)
2809 nMaxLeft += mpBorders[nIdx].nPos +
2810 GetRightIndent() - std::max(GetFirstLineIndent(),
2811 GetLeftIndent());
2812 if(nActLeftCol!=USHRT_MAX)
2813 nMaxLeft -= mpBorders[nActLeftCol].nPos +
2814 mpBorders[nActLeftCol].nWidth;
2816 else
2818 nMaxLeft += mpBorders[nIdx].nPos -
2819 GetRightIndent() + std::max(GetFirstLineIndent(),
2820 GetLeftIndent());
2821 if(nActLeftCol!=USHRT_MAX)
2822 nMaxLeft -= mpBorders[nActLeftCol].nPos +
2823 mpBorders[nActLeftCol].nWidth;
2826 nMaxLeft += glMinFrame;
2827 nMaxLeft += nDragOffset;
2829 // nMaxRight
2830 // linear / proportional move
2831 if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
2832 (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
2834 nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
2836 else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType)
2838 nMaxRight = lNullPix + GetMargin2() - GetMargin1() +
2839 (mpBorders.size() - nIdx - 1) * glMinFrame;
2841 else
2843 if(nRightCol==USHRT_MAX)
2844 { // last column
2845 nMaxRight = GetMargin2() + lNullPix;
2846 if(IsActLastColumn())
2848 if(bRTL)
2850 nMaxRight -=
2851 GetMargin2() + GetRightIndent() -
2852 std::max(GetFirstLineIndent(),
2853 GetLeftIndent());
2855 else
2857 nMaxRight -=
2858 GetMargin2() - GetRightIndent() +
2859 std::max(GetFirstLineIndent(),
2860 GetLeftIndent());
2862 nMaxRight += mpBorders[nIdx].nPos +
2863 mpBorders[nIdx].nWidth;
2866 else
2868 nMaxRight = lNullPix + mpBorders[nRightCol].nPos;
2869 sal_uInt16 nNotHiddenRightCol =
2870 GetActRightColumn(true, nIdx);
2872 if( nActLeftCol == nIdx )
2874 tools::Long nBorder = nNotHiddenRightCol ==
2875 USHRT_MAX ?
2876 GetMargin2() :
2877 mpBorders[nNotHiddenRightCol].nPos;
2878 if(bRTL)
2880 nMaxRight -= nBorder + GetRightIndent() -
2881 std::max(GetFirstLineIndent(),
2882 GetLeftIndent());
2884 else
2886 nMaxRight -= nBorder - GetRightIndent() +
2887 std::max(GetFirstLineIndent(),
2888 GetLeftIndent());
2890 nMaxRight += mpBorders[nIdx].nPos +
2891 mpBorders[nIdx].nWidth;
2894 nMaxRight -= glMinFrame;
2895 nMaxRight -= mpBorders[nIdx].nWidth;
2899 // ObjectItem
2900 else
2902 nMaxLeft = LONG_MIN;
2903 nMaxRight = LONG_MAX;
2905 break;
2907 case RulerDragSize::N2:
2908 if (mxColumnItem)
2910 nMaxLeft = lNullPix + mpBorders[nIdx].nPos;
2911 if(nIdx == mxColumnItem->Count()-2) { // last column
2912 nMaxRight = GetMargin2() + lNullPix;
2913 if(mxColumnItem->IsLastAct()) {
2914 nMaxRight -=
2915 GetMargin2() - GetRightIndent() +
2916 std::max(GetFirstLineIndent(),
2917 GetLeftIndent());
2918 nMaxRight += mpBorders[nIdx].nPos +
2919 mpBorders[nIdx].nWidth;
2922 else {
2923 nMaxRight = lNullPix + mpBorders[nIdx+1].nPos;
2924 if(mxColumnItem->GetActColumn()-1 == nIdx) {
2925 nMaxRight -= mpBorders[nIdx+1].nPos - GetRightIndent() +
2926 std::max(GetFirstLineIndent(),
2927 GetLeftIndent());
2928 nMaxRight += mpBorders[nIdx].nPos +
2929 mpBorders[nIdx].nWidth;
2932 nMaxRight -= glMinFrame;
2933 nMaxRight -= mpBorders[nIdx].nWidth;
2934 break;
2937 nMaxRight += nDragOffset;
2938 break;
2940 case RulerType::Indent:
2942 const sal_uInt16 nIdx = GetDragAryPos();
2943 switch(nIdx) {
2944 case INDENT_FIRST_LINE - INDENT_GAP:
2945 case INDENT_LEFT_MARGIN - INDENT_GAP:
2947 if(bRTL)
2949 nMaxLeft = lNullPix + GetRightIndent();
2951 if(mxColumnItem && !mxColumnItem->IsFirstAct())
2952 nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
2953 mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
2954 nMaxRight = lNullPix + GetMargin2();
2956 // Dragging along
2957 if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
2958 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
2960 if(GetLeftIndent() > GetFirstLineIndent())
2961 nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
2962 else
2963 nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
2966 else
2968 nMaxLeft = lNullPix;
2970 if(mxColumnItem && !mxColumnItem->IsFirstAct())
2971 nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
2972 mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
2973 nMaxRight = lNullPix + GetRightIndent() - glMinFrame;
2975 // Dragging along
2976 if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
2977 !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
2979 if(GetLeftIndent() > GetFirstLineIndent())
2980 nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
2981 else
2982 nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
2986 break;
2987 case INDENT_RIGHT_MARGIN - INDENT_GAP:
2989 if(bRTL)
2991 nMaxLeft = lNullPix;
2992 nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame;
2993 if (mxColumnItem)
2995 sal_uInt16 nRightCol=GetActRightColumn( true );
2996 if(!IsActLastColumn( true ))
2997 nMaxRight += mpBorders[nRightCol].nPos;
2998 else
2999 nMaxRight += GetMargin2();
3001 else
3003 nMaxLeft += GetMargin1();
3005 nMaxLeft += glMinFrame;
3007 else
3009 nMaxLeft = lNullPix +
3010 std::max(GetFirstLineIndent(), GetLeftIndent());
3011 nMaxRight = lNullPix;
3012 if (mxColumnItem)
3014 sal_uInt16 nRightCol=GetActRightColumn( true );
3015 if(!IsActLastColumn( true ))
3016 nMaxRight += mpBorders[nRightCol].nPos;
3017 else
3018 nMaxRight += GetMargin2();
3020 else
3021 nMaxRight += GetMargin2();
3022 nMaxLeft += glMinFrame;
3025 break;
3027 break;
3029 case RulerType::Tab: // Tabs (Modifier)
3030 /* left = NOf + Max(LAR, EZ)
3031 right = NOf + RAR */
3033 if (bRTL)
3034 nMaxLeft = lNullPix + GetRightIndent();
3035 else
3036 nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent());
3038 mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset;
3039 nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
3040 break;
3041 default: ; //prevent warning
3045 bool SvxRuler::StartDrag()
3048 Beginning of a drag operation (SV-handler) evaluates modifier and
3049 calculated values
3051 [Cross-reference]
3053 <SvxRuler::EvalModifier()>
3054 <SvxRuler::CalcMinMax()>
3055 <SvxRuler::EndDrag()>
3057 bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
3059 if(!bValid)
3060 return false;
3062 mxRulerImpl->lLastLMargin = GetMargin1();
3063 mxRulerImpl->lLastRMargin = GetMargin2();
3065 bool bOk = true;
3067 lInitialDragPos = GetDragPos();
3068 switch(GetDragType())
3070 case RulerType::Margin1: // left edge of the surrounding Frame
3071 case RulerType::Margin2: // right edge of the surrounding Frame
3072 if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem))
3074 if (!mxColumnItem)
3075 EvalModifier();
3076 else
3077 nDragType = SvxRulerDragFlags::OBJECT;
3079 else
3081 bOk = false;
3083 break;
3084 case RulerType::Border: // Table, column (Modifier)
3085 if (mxColumnItem)
3087 nDragOffset = 0;
3088 if (!mxColumnItem->IsTable())
3089 nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos;
3090 EvalModifier();
3092 else
3093 nDragOffset = 0;
3094 break;
3095 case RulerType::Indent: // Paragraph indents (Modifier)
3097 if( bContentProtected )
3098 return false;
3099 if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) { // Left paragraph indent
3100 mpIndents[0] = mpIndents[INDENT_FIRST_LINE];
3101 EvalModifier();
3103 else
3105 nDragType = SvxRulerDragFlags::OBJECT;
3107 mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP];
3108 break;
3110 case RulerType::Tab: // Tabs (Modifier)
3111 if( bContentProtected )
3112 return false;
3113 EvalModifier();
3114 mpTabs[0] = mpTabs[GetDragAryPos() + 1];
3115 mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW;
3116 break;
3117 default:
3118 nDragType = SvxRulerDragFlags::NONE;
3121 if(bOk)
3122 CalcMinMax();
3124 return bOk;
3127 void SvxRuler::Drag()
3129 /* SV-Draghandler */
3130 if(IsDragCanceled())
3132 Ruler::Drag();
3133 return;
3135 switch(GetDragType()) {
3136 case RulerType::Margin1: // left edge of the surrounding Frame
3137 DragMargin1();
3138 mxRulerImpl->lLastLMargin = GetMargin1();
3139 break;
3140 case RulerType::Margin2: // right edge of the surrounding Frame
3141 DragMargin2();
3142 mxRulerImpl->lLastRMargin = GetMargin2();
3143 break;
3144 case RulerType::Indent: // Paragraph indents
3145 DragIndents();
3146 break;
3147 case RulerType::Border: // Table, columns
3148 if (mxColumnItem)
3149 DragBorders();
3150 else if (mxObjectItem)
3151 DragObjectBorder();
3152 break;
3153 case RulerType::Tab: // Tabs
3154 DragTabs();
3155 break;
3156 default:
3157 break; //prevent warning
3159 Ruler::Drag();
3162 void SvxRuler::EndDrag()
3165 SV-handler; is called when ending the dragging. Triggers the updating of data
3166 on the application, by calling the respective Apply...() methods to send the
3167 data to the application.
3169 const bool bUndo = IsDragCanceled();
3170 const tools::Long lPos = GetDragPos();
3171 DrawLine_Impl(lTabPos, 6, bHorz);
3172 lTabPos = -1;
3174 if(!bUndo)
3176 switch(GetDragType())
3178 case RulerType::Margin1: // upper left edge of the surrounding Frame
3179 case RulerType::Margin2: // lower right edge of the surrounding Frame
3181 if (!mxColumnItem || !mxColumnItem->IsTable())
3182 ApplyMargins();
3184 if(mxColumnItem &&
3185 (mxColumnItem->IsTable() ||
3186 (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
3187 ApplyBorders();
3190 break;
3191 case RulerType::Border: // Table, columns
3192 if(lInitialDragPos != lPos ||
3193 (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here
3195 if (mxColumnItem)
3197 ApplyBorders();
3198 if(bHorz)
3199 UpdateTabs();
3201 else if (mxObjectItem)
3202 ApplyObject();
3204 break;
3205 case RulerType::Indent: // Paragraph indents
3206 if(lInitialDragPos != lPos)
3207 ApplyIndents();
3208 SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
3209 break;
3210 case RulerType::Tab: // Tabs
3212 ApplyTabs();
3213 mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE;
3214 SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
3216 break;
3217 default:
3218 break; //prevent warning
3221 nDragType = SvxRulerDragFlags::NONE;
3223 mbCoarseSnapping = false;
3224 mbSnapping = true;
3226 Ruler::EndDrag();
3227 if(bUndo)
3229 for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++)
3231 pCtrlItems[i]->ClearCache();
3232 pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId());
3237 void SvxRuler::ExtraDown()
3239 /* Override SV method, sets the new type for the Default tab. */
3241 // Switch Tab Type
3242 if(mxTabStopItem &&
3243 (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)
3245 ++nDefTabType;
3246 if(RULER_TAB_DEFAULT == nDefTabType)
3247 nDefTabType = RULER_TAB_LEFT;
3248 SetExtraType(RulerExtra::Tab, nDefTabType);
3250 Ruler::ExtraDown();
3253 void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint)
3256 Report through the bindings that the status update is completed. The ruler
3257 updates its appearance and gets registered again in the bindings.
3260 // start update
3261 if (bActive && rHint.GetId() == SfxHintId::UpdateDone)
3263 Update();
3264 EndListening(*pBindings);
3265 bValid = true;
3266 bListening = false;
3270 void SvxRuler::MenuSelect(std::u16string_view ident)
3272 if (ident.empty())
3273 return;
3274 /* Handler of the context menus for switching the unit of measurement */
3275 SetUnit(vcl::EnglishStringToMetric(ident));
3278 void SvxRuler::TabMenuSelect(std::u16string_view rIdent)
3280 if (rIdent.empty())
3281 return;
3282 sal_Int32 nId = o3tl::toInt32(rIdent);
3283 /* Handler of the tab menu for setting the type */
3284 if (mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx)
3286 SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx);
3287 aTabStop.GetAdjustment() = ToAttrTab_Impl(nId - 1);
3288 mxTabStopItem->Remove(mxRulerImpl->nIdx);
3289 mxTabStopItem->Insert(aTabStop);
3290 sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
3291 pBindings->GetDispatcher()->ExecuteList(nTabStopId,
3292 SfxCallMode::RECORD, { mxTabStopItem.get() });
3293 UpdateTabs();
3294 mxRulerImpl->nIdx = 0;
3298 const TranslateId RID_SVXSTR_RULER_TAB[] =
3300 RID_SVXSTR_RULER_TAB_LEFT,
3301 RID_SVXSTR_RULER_TAB_RIGHT,
3302 RID_SVXSTR_RULER_TAB_CENTER,
3303 RID_SVXSTR_RULER_TAB_DECIMAL
3306 void SvxRuler::Command( const CommandEvent& rCommandEvent )
3308 /* Mouse context menu for switching the unit of measurement */
3309 if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() )
3311 CancelDrag();
3313 tools::Rectangle aRect(rCommandEvent.GetMousePosPixel(), Size(1, 1));
3314 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
3315 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/rulermenu.ui"));
3316 std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
3318 bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
3319 if ( !mpTabs.empty() &&
3320 RulerType::Tab ==
3321 GetRulerType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) &&
3322 mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT )
3324 xMenu->clear();
3326 const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2);
3327 const Point aPt(aSz.Width() / 2, aSz.Height() / 2);
3329 for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i )
3331 ScopedVclPtr<VirtualDevice> xDev(pPopupParent->create_virtual_device());
3332 xDev->SetOutputSize(aSz);
3334 sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i;
3335 nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT);
3337 Color aFillColor(xDev->GetSettings().GetStyleSettings().GetShadowColor());
3338 DrawTab(*xDev, aFillColor, aPt, nStyle);
3340 OUString sId(OUString::number(i + 1));
3341 xMenu->insert(-1, sId, SvxResId(RID_SVXSTR_RULER_TAB[i]),
3342 nullptr, xDev.get(), nullptr, TRISTATE_TRUE);
3343 xMenu->set_active(sId, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle);
3345 TabMenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
3347 else
3349 FieldUnit eUnit = GetUnit();
3350 const int nCount = xMenu->n_children();
3352 bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC);
3353 for ( sal_uInt16 i = nCount; i; --i )
3355 OUString sIdent = xMenu->get_id(i - 1);
3356 FieldUnit eMenuUnit = vcl::EnglishStringToMetric(sIdent);
3357 xMenu->set_active(sIdent, eMenuUnit == eUnit);
3358 if( bReduceMetric )
3360 if (eMenuUnit == FieldUnit::M ||
3361 eMenuUnit == FieldUnit::KM ||
3362 eMenuUnit == FieldUnit::FOOT ||
3363 eMenuUnit == FieldUnit::MILE)
3365 xMenu->remove(sIdent);
3367 else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz )
3369 xMenu->remove(sIdent);
3371 else if (( eMenuUnit == FieldUnit::LINE ) && bHorz )
3373 xMenu->remove(sIdent);
3377 MenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
3380 else
3382 Ruler::Command( rCommandEvent );
3386 sal_uInt16 SvxRuler::GetActRightColumn(
3387 bool bForceDontConsiderHidden,
3388 sal_uInt16 nAct ) const
3390 if( nAct == USHRT_MAX )
3391 nAct = mxColumnItem->GetActColumn();
3392 else
3393 nAct++; //To be able to pass on the ActDrag
3395 bool bConsiderHidden = !bForceDontConsiderHidden &&
3396 !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3398 while( nAct < mxColumnItem->Count() - 1 )
3400 if (mxColumnItem->At(nAct).bVisible || bConsiderHidden)
3401 return nAct;
3402 else
3403 nAct++;
3405 return USHRT_MAX;
3408 sal_uInt16 SvxRuler::GetActLeftColumn(
3409 bool bForceDontConsiderHidden,
3410 sal_uInt16 nAct ) const
3412 if(nAct == USHRT_MAX)
3413 nAct = mxColumnItem->GetActColumn();
3415 sal_uInt16 nLeftOffset = 1;
3417 bool bConsiderHidden = !bForceDontConsiderHidden &&
3418 !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
3420 while(nAct >= nLeftOffset)
3422 if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden)
3423 return nAct - nLeftOffset;
3424 else
3425 nLeftOffset++;
3427 return USHRT_MAX;
3430 bool SvxRuler::IsActLastColumn(
3431 bool bForceDontConsiderHidden,
3432 sal_uInt16 nAct) const
3434 return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3437 bool SvxRuler::IsActFirstColumn(
3438 bool bForceDontConsiderHidden,
3439 sal_uInt16 nAct) const
3441 return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
3444 tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const
3447 if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
3449 // Remove the minimum width for all affected columns
3450 // starting from the right edge
3451 tools::Long _nMaxRight = GetMargin2() - GetMargin1();
3453 tools::Long lFences = 0;
3454 tools::Long lMinSpace = USHRT_MAX;
3455 tools::Long lOldPos;
3456 tools::Long lColumns = 0;
3458 sal_uInt16 nStart;
3459 if(!mxColumnItem->IsTable())
3461 if(nCol == USHRT_MAX)
3463 lOldPos = GetMargin1();
3464 nStart = 0;
3466 else
3468 lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth;
3469 nStart = nCol + 1;
3470 lFences = mpBorders[nCol].nWidth;
3473 for(size_t i = nStart; i < mpBorders.size() - 1; ++i)
3475 tools::Long lWidth = mpBorders[i].nPos - lOldPos;
3476 lColumns += lWidth;
3477 if(lWidth < lMinSpace)
3478 lMinSpace = lWidth;
3479 lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth;
3480 lFences += mpBorders[i].nWidth;
3482 tools::Long lWidth = GetMargin2() - lOldPos;
3483 lColumns += lWidth;
3484 if(lWidth < lMinSpace)
3485 lMinSpace = lWidth;
3487 else
3489 sal_uInt16 nActCol;
3490 if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin
3492 lOldPos = GetMargin1();
3494 else
3496 lOldPos = mpBorders[nCol].nPos;
3498 lColumns = GetMargin2()-lOldPos;
3499 nActCol = nCol;
3500 lFences = 0;
3501 while(nActCol < mpBorders.size() || nActCol == USHRT_MAX)
3503 sal_uInt16 nRight;
3504 if(nActCol == USHRT_MAX)
3506 nRight = 0;
3507 while (!(*mxColumnItem)[nRight].bVisible)
3509 nRight++;
3512 else
3514 nRight = GetActRightColumn(false, nActCol);
3517 tools::Long lWidth;
3518 if(nRight != USHRT_MAX)
3520 lWidth = mpBorders[nRight].nPos - lOldPos;
3521 lOldPos = mpBorders[nRight].nPos;
3523 else
3525 lWidth=GetMargin2() - lOldPos;
3527 nActCol = nRight;
3528 if(lWidth < lMinSpace)
3529 lMinSpace = lWidth;
3530 if(nActCol == USHRT_MAX)
3531 break;
3535 _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns);
3536 return _nMaxRight;
3538 else
3540 if(mxColumnItem->IsTable())
3542 sal_uInt16 nVisCols = 0;
3543 for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();)
3545 if ((*mxColumnItem)[i].bVisible)
3546 nVisCols++;
3547 i = GetActRightColumn(false, i);
3549 return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame;
3551 else
3553 tools::Long lWidth = 0;
3554 for(size_t i = nCol; i < mpBorders.size() - 1; i++)
3556 lWidth += glMinFrame + mpBorders[i].nWidth;
3558 return GetMargin2() - GetMargin1() - lWidth;
3563 // Tab stops relative to indent (#i24363#)
3564 void SvxRuler::SetTabsRelativeToIndent( bool bRel )
3566 mxRulerImpl->bIsTabsRelativeToIndent = bRel;
3569 void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue)
3571 if (diffValue == 0)
3572 return;
3574 if (type == RulerChangeType::MARGIN1)
3575 AdjustMargin1(diffValue);
3576 else if (type == RulerChangeType::MARGIN2)
3577 SetMargin2( GetMargin2() - diffValue);
3578 ApplyMargins();
3581 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */