diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /svx/source/dialog/svxruler.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/source/dialog/svxruler.cxx')
-rw-r--r-- | svx/source/dialog/svxruler.cxx | 3582 |
1 files changed, 3582 insertions, 0 deletions
diff --git a/svx/source/dialog/svxruler.cxx b/svx/source/dialog/svxruler.cxx new file mode 100644 index 0000000000..6323583fd2 --- /dev/null +++ b/svx/source/dialog/svxruler.cxx @@ -0,0 +1,3582 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cstring> +#include <climits> + +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/fieldvalues.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <vcl/weldutils.hxx> +#include <svl/eitem.hxx> +#include <svl/rectitem.hxx> +#include <svl/hint.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/strings.hrc> +#include <svx/svxids.hrc> +#include <svx/dialmgr.hxx> +#include <svx/ruler.hxx> +#include <svx/rulritem.hxx> +#include <editeng/editids.hrc> +#include <editeng/tstpitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/protitem.hxx> +#include <osl/diagnose.h> +#include <rtl/math.hxx> +#include <o3tl/string_view.hxx> +#include <svl/itemset.hxx> + +#include "rlrcitem.hxx" +#include <memory> + +#define CTRL_ITEM_COUNT 14 +#define GAP 10 +#define OBJECT_BORDER_COUNT 4 +#define TAB_GAP 1 +#define INDENT_GAP 2 +#define INDENT_FIRST_LINE 2 +#define INDENT_LEFT_MARGIN 3 +#define INDENT_RIGHT_MARGIN 4 +#define INDENT_COUNT 3 //without the first two old values + +struct SvxRuler_Impl { + std::unique_ptr<sal_uInt16[]> pPercBuf; + std::unique_ptr<sal_uInt16[]> pBlockBuf; + sal_uInt16 nPercSize; + tools::Long nTotalDist; + tools::Long lOldWinPos; + tools::Long lMaxLeftLogic; + tools::Long lMaxRightLogic; + tools::Long lLastLMargin; + tools::Long lLastRMargin; + std::unique_ptr<SvxProtectItem> aProtectItem; + std::unique_ptr<SfxBoolItem> pTextRTLItem; + sal_uInt16 nControllerItems; + sal_uInt16 nIdx; + sal_uInt16 nColLeftPix; + sal_uInt16 nColRightPix; // Pixel values for left / right edge + // For columns; buffered to prevent + // recalculation errors + // May be has to be widen for future values + bool bIsTableRows : 1; // mxColumnItem contains table rows instead of columns + //#i24363# tab stops relative to indent + bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent? + // false means relative to SvxRuler::GetLeftFrameMargin() + + SvxRuler_Impl() : + nPercSize(0), nTotalDist(0), + lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0), + lLastLMargin(0), lLastRMargin(0), + aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)), + nControllerItems(0), nIdx(0), + nColLeftPix(0), nColRightPix(0), + bIsTableRows(false), + bIsTabsRelativeToIndent(true) + { + } + + void SetPercSize(sal_uInt16 nSize); + +}; + +static RulerTabData ruler_tab_svx = +{ + 0, // DPIScaleFactor to be set + 7, // ruler_tab_width + 6, // ruler_tab_height + 0, // ruler_tab_height2 + 0, // ruler_tab_width2 + 0, // ruler_tab_cwidth + 0, // ruler_tab_cwidth2 + 0, // ruler_tab_cwidth3 + 0, // ruler_tab_cwidth4 + 0, // ruler_tab_dheight + 0, // ruler_tab_dheight2 + 0, // ruler_tab_dwidth + 0, // ruler_tab_dwidth2 + 0, // ruler_tab_dwidth3 + 0, // ruler_tab_dwidth4 + 0 // ruler_tab_textoff +}; + +void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize) +{ + if(nSize > nPercSize) + { + nPercSize = nSize; + pPercBuf.reset( new sal_uInt16[nPercSize] ); + pBlockBuf.reset( new sal_uInt16[nPercSize] ); + } + size_t nSize2 = sizeof(sal_uInt16) * nPercSize; + memset(pPercBuf.get(), 0, nSize2); + memset(pBlockBuf.get(), 0, nSize2); +} + +// Constructor of the ruler + +// SID_ATTR_ULSPACE, SID_ATTR_LRSPACE +// expects as parameter SvxULSpaceItem for page edge +// (either left/right or top/bottom) +// Ruler: SetMargin1, SetMargin2 + +// SID_RULER_PAGE_POS +// expects as parameter the initial value of the page and page width +// Ruler: SetPagePos + +// SID_ATTR_TABSTOP +// expects: SvxTabStopItem +// Ruler: SetTabs + +// SID_ATTR_PARA_LRSPACE +// left, right paragraph edge in H-ruler +// Ruler: SetIndents + +// SID_RULER_BORDERS +// Table borders, columns +// expects: something like SwTabCols +// Ruler: SetBorders + +constexpr tools::Long glMinFrame = 5; // minimal frame width in pixels + +SvxRuler::SvxRuler( + vcl::Window* pParent, // StarView Parent + vcl::Window* pWin, // Output window: is used for conversion + // logical units <-> pixels + SvxRulerSupportFlags flags, // Display flags, see ruler.hxx + SfxBindings &rBindings, // associated Bindings + WinBits nWinStyle) : // StarView WinBits + Ruler(pParent, nWinStyle), + pCtrlItems(CTRL_ITEM_COUNT), + pEditWin(pWin), + mxRulerImpl(new SvxRuler_Impl), + bAppSetNullOffset(false), // Is the 0-offset of the ruler set by the application? + lLogicNullOffset(0), + lAppNullOffset(LONG_MAX), + lInitialDragPos(0), + nFlags(flags), + nDragType(SvxRulerDragFlags::NONE), + nDefTabType(RULER_TAB_LEFT), + nTabCount(0), + nTabBufSize(0), + lDefTabDist(50), + lTabPos(-1), + mpBorders(1), // due to one column tables + pBindings(&rBindings), + nDragOffset(0), + nMaxLeft(0), + nMaxRight(0), + bValid(false), + bListening(false), + bActive(true), + mbCoarseSnapping(false), + mbSnapping(true) + +{ + /* Constructor; Initialize data buffer; controller items are created */ + + rBindings.EnterRegistrations(); + + // Create Supported Items + sal_uInt16 i = 0; + + // Page edges + pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings)); + if((nWinStyle & WB_VSCROLL) == WB_VSCROLL) + { + bHorz = false; + pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings)); + } + else + { + bHorz = true; + pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings)); + } + + // Page Position + pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings)); + + if(nFlags & SvxRulerSupportFlags::TABS) + { + sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL; + pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings)); + SetExtraType(RulerExtra::Tab, nDefTabType); + } + + if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL)) + { + if(bHorz) + pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings)); + else + pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings)); + + mpIndents.resize(5 + INDENT_GAP); + + for(RulerIndent & rIndent : mpIndents) + { + rIndent.nPos = 0; + rIndent.nStyle = RulerIndentStyle::Top; + } + + mpIndents[0].nStyle = RulerIndentStyle::Top; + mpIndents[1].nStyle = RulerIndentStyle::Top; + mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top; + mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom; + mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom; + } + + if( (nFlags & SvxRulerSupportFlags::BORDERS) == SvxRulerSupportFlags::BORDERS ) + { + pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings)); + pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings)); + } + + pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings)); + + if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT ) + { + pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings)); + mpObjectBorders.resize(OBJECT_BORDER_COUNT); + for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder) + { + mpObjectBorders[nBorder].nPos = 0; + mpObjectBorders[nBorder].nWidth = 0; + mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable; + } + } + + pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings)); + pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings)); + mxRulerImpl->nControllerItems=i; + + if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET ) + SetExtraType(RulerExtra::NullOffset); + + rBindings.LeaveRegistrations(); + + ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor(); + ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor; + ruler_tab_svx.width *= ruler_tab_svx.DPIScaleFactor; + +} + +SvxRuler::~SvxRuler() +{ + disposeOnce(); +} + +void SvxRuler::dispose() +{ + /* Destructor ruler; release internal buffer */ + if(bListening) + EndListening(*pBindings); + + pBindings->EnterRegistrations(); + + pCtrlItems.clear(); + + pBindings->LeaveRegistrations(); + + pEditWin.clear(); + Ruler::dispose(); +} + +tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const +{ + tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference); + tools::Long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin()); + tools::Long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin()); + + double aTick = GetCurrentRulerUnit().nTick1; + + if (mbCoarseSnapping) + aTick = GetCurrentRulerUnit().nTick2; + + tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width(); + + double aHalfTick = aTick / 2.0; + double aHalfTickPixel = aTickPixel / 2.0; + + if (aSnapToFrameMargin) + { + if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel) + return aLeftFramePosition; + + if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel) + return aRightFramePosition; + } + + if (!mbSnapping) + return aPosition; + + // Move "coordinate system" to frame position so ticks are calculated correctly + tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel; + // Convert position to current selected map mode + tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width(); + // Normalize -- snap to nearest tick + aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick; + // Convert back to pixels + aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width(); + // Move "coordinate system" back to original position + return aPosition + aPointOfReferencePixel; +} + +tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const +{ + return pEditWin->LogicToPixel(Size(nVal, 0)).Width(); +} + +tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const +{ + return pEditWin->LogicToPixel(Size(0, nVal)).Height(); +} + +tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const +{ + return pEditWin->LogicToPixel(Size(nVal, 0)).Width(); +} + +tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const +{ + return pEditWin->LogicToPixel(Size(0, nVal)).Height(); +} + +tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const +{ + return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal); +} + +tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const +{ + return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal); +} + +inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const +{ + return pEditWin->PixelToLogic(Size(nVal, 0)).Width(); +} + +inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const +{ + return pEditWin->PixelToLogic(Size(0, nVal)).Height(); +} + +inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const +{ + return pEditWin->PixelToLogic(Size(nVal, 0)).Width(); +} + +inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const +{ + return pEditWin->PixelToLogic(Size(0, nVal)).Height(); +} + +inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const +{ + return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal); +} + +inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const +{ + return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal); +} + +tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const +{ + if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld)) + return nVal; + else + return nValOld; +} + +tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const +{ + if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld)) + return nVal; + else + return nValOld; +} + +tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const +{ + if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld)) + return nVal; + else + return nValOld; +} + +inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const +{ + return bHorz ? nIdx : nIdx + 2; +} + +/* + Update Upper Left edge. + Items are translated into the representation of the ruler. +*/ +void SvxRuler::UpdateFrame() +{ + const RulerMarginStyle nMarginStyle = + ( mxRulerImpl->aProtectItem->IsSizeProtected() || + mxRulerImpl->aProtectItem->IsPosProtected() ) ? + RulerMarginStyle::NONE : RulerMarginStyle::Sizeable; + + if(mxLRSpaceItem && mxPagePosItem) + { + // if no initialization by default app behavior + const tools::Long nOld = lLogicNullOffset; + lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft(); + + if(bAppSetNullOffset) + { + lAppNullOffset += lLogicNullOffset - nOld; + } + + if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX) + { + Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset)); + SetMargin1(0, nMarginStyle); + lAppNullOffset = 0; + } + else + { + SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle); + } + + tools::Long lRight = 0; + + // evaluate the table right edge of the table + if(mxColumnItem && mxColumnItem->IsTable()) + lRight = mxColumnItem->GetRight(); + else + lRight = mxLRSpaceItem->GetRight(); + + tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset; + tools::Long aWidthPixel = ConvertHPosPixel(aWidth); + + SetMargin2(aWidthPixel, nMarginStyle); + } + else if(mxULSpaceItem && mxPagePosItem) + { + // relative the upper edge of the surrounding frame + const tools::Long nOld = lLogicNullOffset; + lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper(); + + if(bAppSetNullOffset) + { + lAppNullOffset += lLogicNullOffset - nOld; + } + + if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX) + { + Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset)); + lAppNullOffset = 0; + SetMargin1(0, nMarginStyle); + } + else + { + SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle); + } + + tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower(); + tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset; + tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2); + + SetMargin2(nMargin2Pixel, nMarginStyle); + } + else + { + // turns off the view + SetMargin1(); + SetMargin2(); + } + + if (mxColumnItem) + { + mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft())); + mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight())); + } +} + +void SvxRuler::MouseMove( const MouseEvent& rMEvt ) +{ + if( bActive ) + { + pBindings->Update( SID_RULER_LR_MIN_MAX ); + pBindings->Update( SID_ATTR_LONG_ULSPACE ); + pBindings->Update( SID_ATTR_LONG_LRSPACE ); + pBindings->Update( SID_RULER_PAGE_POS ); + pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL); + pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL); + pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL); + pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL); + pBindings->Update( SID_RULER_OBJECT ); + pBindings->Update( SID_RULER_PROTECT ); + } + + Ruler::MouseMove( rMEvt ); + + RulerSelection aSelection = GetHoverSelection(); + + if (aSelection.eType == RulerType::DontKnow) + { + SetQuickHelpText(""); + return; + } + + RulerUnitData aUnitData = GetCurrentRulerUnit(); + double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1; + sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor)); + OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr); + + switch (aSelection.eType) + { + case RulerType::Indent: + { + if (!mxParaItem) + break; + + tools::Long nIndex = aSelection.nAryPos + INDENT_GAP; + + tools::Long nIndentValue = 0.0; + if (nIndex == INDENT_LEFT_MARGIN) + nIndentValue = mxParaItem->GetTextLeft(); + else if (nIndex == INDENT_FIRST_LINE) + nIndentValue = mxParaItem->GetTextFirstLineOffset(); + else if (nIndex == INDENT_RIGHT_MARGIN) + nIndentValue = mxParaItem->GetRight(); + + double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces); + + SetQuickHelpText(OUString::number(fValue) + " " + sUnit); + break; + } + case RulerType::Border: + { + if (mxColumnItem == nullptr) + break; + + SvxColumnItem& aColumnItem = *mxColumnItem; + + if (aSelection.nAryPos + 1 >= aColumnItem.Count()) + break; + + double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces); + double fEnd = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces); + + SetQuickHelpText( + OUString::number(fStart) + " " + sUnit + " - " + + OUString::number(fEnd) + " " + sUnit ); + break; + } + case RulerType::Margin1: + { + tools::Long nLeft = 0.0; + if (mxLRSpaceItem) + nLeft = mxLRSpaceItem->GetLeft(); + else if (mxULSpaceItem) + nLeft = mxULSpaceItem->GetUpper(); + else + break; + + double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces); + SetQuickHelpText(OUString::number(fValue) + " " + sUnit); + + break; + } + case RulerType::Margin2: + { + tools::Long nRight = 0.0; + if (mxLRSpaceItem) + nRight = mxLRSpaceItem->GetRight(); + else if (mxULSpaceItem) + nRight = mxULSpaceItem->GetLower(); + else + break; + + double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces); + SetQuickHelpText(OUString::number(fValue) + " " + sUnit); + + break; + } + default: + { + SetQuickHelpText(""); + break; + } + } +} + +void SvxRuler::StartListening_Impl() +{ + if(!bListening) + { + bValid = false; + StartListening(*pBindings); + bListening = true; + } +} + +void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace +{ + /* Store new value LRSpace; delete old ones if possible */ + if(bActive) + { + if(pItem) + mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem)); + else + mxLRSpaceItem.reset(); + StartListening_Impl(); + } +} + +void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax +{ + /* Set new value for MinMax; delete old ones if possible */ + if(bActive) + { + if(pItem) + mxMinMaxItem.reset(new SfxRectangleItem(*pItem)); + else + mxMinMaxItem.reset(); + } +} + + +void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value +{ + /* Update Right/bottom margin */ + if(bActive && !bHorz) + { + if(pItem) + mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem)); + else + mxULSpaceItem.reset(); + StartListening_Impl(); + } +} + +void SvxRuler::Update( const SvxProtectItem* pItem ) +{ + if( pItem ) + mxRulerImpl->aProtectItem.reset(pItem->Clone()); +} + +void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem) +{ + if(bActive && bHorz) + { + mxRulerImpl->pTextRTLItem.reset(); + if(pItem) + mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem)); + SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue()); + StartListening_Impl(); + } +} + +void SvxRuler::Update( + const SvxColumnItem *pItem, // new value + sal_uInt16 nSID) //Slot Id to identify NULL items +{ + /* Set new value for column view */ + if(!bActive) + return; + + if(pItem) + { + mxColumnItem.reset(new SvxColumnItem(*pItem)); + mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL); + if(!bHorz && !mxRulerImpl->bIsTableRows) + mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL); + } + else if(mxColumnItem && mxColumnItem->Which() == nSID) + //there are two groups of column items table/frame columns and table rows + //both can occur in vertical or horizontal mode + //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL + //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS + //if mxColumnItem is already set with one of the ids then a NULL pItem argument + //must not delete it + { + mxColumnItem.reset(); + mxRulerImpl->bIsTableRows = false; + } + StartListening_Impl(); +} + + +void SvxRuler::UpdateColumns() +{ + /* Update column view */ + if(mxColumnItem && mxColumnItem->Count() > 1) + { + mpBorders.resize(mxColumnItem->Count()); + + RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable; + + bool bProtectColumns = + mxRulerImpl->aProtectItem->IsSizeProtected() || + mxRulerImpl->aProtectItem->IsPosProtected(); + + if( !bProtectColumns ) + { + nStyleFlags |= RulerBorderStyle::Moveable; + if( !mxColumnItem->IsTable() ) + nStyleFlags |= RulerBorderStyle::Sizeable; + } + + sal_uInt16 nBorders = mxColumnItem->Count(); + + if(!mxRulerImpl->bIsTableRows) + --nBorders; + + for(sal_uInt16 i = 0; i < nBorders; ++i) + { + mpBorders[i].nStyle = nStyleFlags; + if(!mxColumnItem->At(i).bVisible) + mpBorders[i].nStyle |= RulerBorderStyle::Invisible; + + mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset); + + if(mxColumnItem->Count() == i + 1) + { + //with table rows the end of the table is contained in the + //column item but it has no width! + mpBorders[i].nWidth = 0; + } + else + { + mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd); + } + mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset); + mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset); + } + SetBorders(mxColumnItem->Count() - 1, mpBorders.data()); + } + else + { + SetBorders(); + } +} + +void SvxRuler::UpdateObject() +{ + /* Update view of object representation */ + if (mxObjectItem) + { + DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer"); + // !! to the page margin + tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0; + mpObjectBorders[0].nPos = + ConvertPosPixel(mxObjectItem->GetStartX() - + nMargin + lAppNullOffset); + mpObjectBorders[1].nPos = + ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset); + nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0; + mpObjectBorders[2].nPos = + ConvertPosPixel(mxObjectItem->GetStartY() - + nMargin + lAppNullOffset); + mpObjectBorders[3].nPos = + ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset); + + const sal_uInt16 nOffset = GetObjectBordersOff(0); + SetBorders(2, mpObjectBorders.data() + nOffset); + } + else + { + SetBorders(); + } +} + +void SvxRuler::UpdatePara() +{ + + /* Update the view for paragraph indents: + Left margin, first line indent, right margin paragraph update + mpIndents[0] = Buffer for old intent + mpIndents[1] = Buffer for old intent + mpIndents[INDENT_FIRST_LINE] = first line indent + mpIndents[INDENT_LEFT_MARGIN] = left margin + mpIndents[INDENT_RIGHT_MARGIN] = right margin + */ + + // Dependence on PagePosItem + if (mxParaItem && mxPagePosItem && !mxObjectItem) + { + bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + // First-line indent is negative to the left paragraph margin + tools::Long nLeftFrameMargin = GetLeftFrameMargin(); + tools::Long nRightFrameMargin = GetRightFrameMargin(); + SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin)); + SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin)); + + tools::Long leftMargin; + tools::Long leftFirstLine; + tools::Long rightMargin; + + if(bRTLText) + { + leftMargin = nRightFrameMargin - mxParaItem->GetTextLeft() + lAppNullOffset; + leftFirstLine = leftMargin - mxParaItem->GetTextFirstLineOffset(); + rightMargin = nLeftFrameMargin + mxParaItem->GetRight() + lAppNullOffset; + } + else + { + leftMargin = nLeftFrameMargin + mxParaItem->GetTextLeft() + lAppNullOffset; + leftFirstLine = leftMargin + mxParaItem->GetTextFirstLineOffset(); + rightMargin = nRightFrameMargin - mxParaItem->GetRight() + lAppNullOffset; + } + + mpIndents[INDENT_LEFT_MARGIN].nPos = ConvertHPosPixel(leftMargin); + mpIndents[INDENT_FIRST_LINE].nPos = ConvertHPosPixel(leftFirstLine); + mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin); + + mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst(); + + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + else + { + if(!mpIndents.empty()) + { + mpIndents[INDENT_FIRST_LINE].nPos = 0; + mpIndents[INDENT_LEFT_MARGIN].nPos = 0; + mpIndents[INDENT_RIGHT_MARGIN].nPos = 0; + } + SetIndents(); // turn off + } +} + +void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents +{ + /* Store new value of paragraph indents */ + if(bActive) + { + if(pItem) + mxParaItem.reset(new SvxLRSpaceItem(*pItem)); + else + mxParaItem.reset(); + StartListening_Impl(); + } +} + +void SvxRuler::UpdateBorder(const SvxLRSpaceItem * pItem) +{ + /* Border distance */ + if(bActive) + { + if (pItem) + mxBorderItem.reset(new SvxLRSpaceItem(*pItem)); + else + mxBorderItem.reset(); + + StartListening_Impl(); + } +} + +void SvxRuler::UpdatePage() +{ + /* Update view of position and width of page */ + if (mxPagePosItem) + { + // all objects are automatically adjusted + if(bHorz) + { + SetPagePos( + pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(), + pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)). + Width()); + } + else + { + SetPagePos( + pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(), + pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())). + Height()); + } + if(bAppSetNullOffset) + SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset)); + } + else + { + SetPagePos(); + } + + tools::Long lPos = 0; + Point aOwnPos = GetPosPixel(); + Point aEdtWinPos = pEditWin->GetPosPixel(); + if( AllSettings::GetLayoutRTL() && bHorz ) + { + //#i73321# in RTL the window and the ruler is not mirrored but the + // influence of the vertical ruler is inverted + Size aOwnSize = GetSizePixel(); + Size aEdtWinSize = pEditWin->GetSizePixel(); + lPos = aOwnSize.Width() - aEdtWinSize.Width(); + lPos -= (aEdtWinPos - aOwnPos).X(); + } + else + { + Point aPos(aEdtWinPos - aOwnPos); + lPos = bHorz ? aPos.X() : aPos.Y(); + } + + // Unfortunately, we get the offset of the edit window to the ruler never + // through a status message. So we set it ourselves if necessary. + if(lPos != mxRulerImpl->lOldWinPos) + { + mxRulerImpl->lOldWinPos=lPos; + SetWinPos(lPos); + } +} + +void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes +{ + /* Store new value of page attributes */ + if(bActive) + { + if(pItem) + mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem)); + else + mxPagePosItem.reset(); + StartListening_Impl(); + } +} + +void SvxRuler::SetDefTabDist(tools::Long inDefTabDist) // New distance for DefaultTabs in App-Metrics +{ + if (lAppNullOffset == LONG_MAX) + UpdateFrame(); // hack: try to get lAppNullOffset initialized + /* New distance is set for DefaultTabs */ + lDefTabDist = inDefTabDist; + if( !lDefTabDist ) + lDefTabDist = 1; + + UpdateTabs(); +} + +static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj) +{ + /* Internal conversion routine between SV-Tab.-Enum and Svx */ + switch(eAdj) { + case SvxTabAdjust::Left: return RULER_TAB_LEFT; + case SvxTabAdjust::Right: return RULER_TAB_RIGHT; + case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL; + case SvxTabAdjust::Center: return RULER_TAB_CENTER; + case SvxTabAdjust::Default: return RULER_TAB_DEFAULT; + default: ; //prevent warning + } + return 0; +} + +static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj) +{ + switch(eAdj) { + case RULER_TAB_LEFT: return SvxTabAdjust::Left ; + case RULER_TAB_RIGHT: return SvxTabAdjust::Right ; + case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ; + case RULER_TAB_CENTER: return SvxTabAdjust::Center ; + case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ; + } + return SvxTabAdjust::Left; +} + +void SvxRuler::UpdateTabs() +{ + if(IsDrag()) + return; + + if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem) + { + // buffer for DefaultTabStop + // Distance last Tab <-> Right paragraph margin / DefaultTabDist + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + + const tools::Long nLeftFrameMargin = GetLeftFrameMargin(); + const tools::Long nRightFrameMargin = GetRightFrameMargin(); + + //#i24363# tab stops relative to indent + const tools::Long nParaItemTxtLeft = mxParaItem->GetTextLeft(); + + const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft; + const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft; + + const tools::Long lLastTab = mxTabStopItem->Count() + ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos()) + : 0; + const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab; + const tools::Long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight()); + + tools::Long lCurrentDefTabDist = lDefTabDist; + if(mxTabStopItem->GetDefaultDistance()) + lCurrentDefTabDist = mxTabStopItem->GetDefaultDistance(); + tools::Long nDefTabDist = ConvertHPosPixel(lCurrentDefTabDist); + + const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent + ? 0 + : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist ); + + if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize) + { + // 10 (GAP) in stock + nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP; + mpTabs.resize(nTabBufSize); + } + + nTabCount = 0; + sal_uInt16 j; + + const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent); + + tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin) + + lAppNullOffset; + if (bRTL) + { + lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic; + } + tools::Long lLastTabOffsetLogic = 0; + for(j = 0; j < mxTabStopItem->Count(); ++j) + { + const SvxTabStop* pTab = &mxTabStopItem->At(j); + lLastTabOffsetLogic = pTab->GetTabPos(); + tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic); + mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos); + mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment()); + ++nTabCount; + } + + // Adjust to previous-to-first default tab stop + lLastTabOffsetLogic -= lLastTabOffsetLogic % lCurrentDefTabDist; + + // fill the rest with default Tabs + for (j = 0; j < nDefTabBuf; ++j) + { + //simply add the default distance to the last position + lLastTabOffsetLogic += lCurrentDefTabDist; + if (bRTL) + { + mpTabs[nTabCount + TAB_GAP].nPos = + ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic); + if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix) + break; + } + else + { + mpTabs[nTabCount + TAB_GAP].nPos = + ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic); + if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent) + break; + } + + mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT; + ++nTabCount; + } + SetTabs(nTabCount, mpTabs.data() + TAB_GAP); + DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small"); + } + else + { + SetTabs(); + } +} + +void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs +{ + /* Store new value for tabs; delete old ones if possible */ + if(!bActive) + return; + + if(pItem) + { + mxTabStopItem.reset(new SvxTabStopItem(*pItem)); + if(!bHorz) + mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL); + } + else + { + mxTabStopItem.reset(); + } + StartListening_Impl(); +} + +void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects +{ + /* Store new value for objects */ + if(bActive) + { + if(pItem) + mxObjectItem.reset(new SvxObjectItem(*pItem)); + else + mxObjectItem.reset(); + StartListening_Impl(); + } +} + +void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets +{ + lAppNullOffset = lLogicNullOffset - lVal; + bAppSetNullOffset = true; + Ruler::SetNullOffset(ConvertSizePixel(lVal)); + Update(); +} + +void SvxRuler::Update() +{ + /* Perform update of view */ + if(IsDrag()) + return; + + UpdatePage(); + UpdateFrame(); + if(nFlags & SvxRulerSupportFlags::OBJECT) + UpdateObject(); + else + UpdateColumns(); + + if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL)) + UpdatePara(); + + if(nFlags & SvxRulerSupportFlags::TABS) + UpdateTabs(); +} + +tools::Long SvxRuler::GetPageWidth() const +{ + if (!mxPagePosItem) + return 0; + return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight(); +} + +inline tools::Long SvxRuler::GetFrameLeft() const +{ + /* Get Left margin in Pixels */ + return bAppSetNullOffset ? + GetMargin1() + ConvertSizePixel(lLogicNullOffset) : + Ruler::GetNullOffset(); +} + +tools::Long SvxRuler::GetFirstLineIndent() const +{ + /* Get First-line indent in pixels */ + return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1(); +} + +tools::Long SvxRuler::GetLeftIndent() const +{ + /* Get Left paragraph margin in Pixels */ + return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1(); +} + +tools::Long SvxRuler::GetRightIndent() const +{ + /* Get Right paragraph margin in Pixels */ + return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2(); +} + +tools::Long SvxRuler::GetLogicRightIndent() const +{ + /* Get Right paragraph margin in Logic */ + return mxParaItem ? GetRightFrameMargin() - mxParaItem->GetRight() : GetRightFrameMargin(); +} + +// Left margin in App values, is either the margin (= 0) or the left edge of +// the column that is set in the column attribute as current column. +tools::Long SvxRuler::GetLeftFrameMargin() const +{ + // #126721# for some unknown reason the current column is set to 0xffff + DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(), + "issue #126721# - invalid current column!"); + tools::Long nLeft = 0; + if (mxColumnItem && + mxColumnItem->Count() && + mxColumnItem->IsConsistent()) + { + nLeft = mxColumnItem->GetActiveColumnDescription().nStart; + } + + if (mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable())) + nLeft += mxBorderItem->GetLeft(); + + return nLeft; +} + +inline tools::Long SvxRuler::GetLeftMin() const +{ + DBG_ASSERT(mxMinMaxItem, "no MinMax value set"); + if (mxMinMaxItem) + { + if (bHorz) + return mxMinMaxItem->GetValue().Left(); + else + return mxMinMaxItem->GetValue().Top(); + } + return 0; +} + +inline tools::Long SvxRuler::GetRightMax() const +{ + DBG_ASSERT(mxMinMaxItem, "no MinMax value set"); + if (mxMinMaxItem) + { + if (bHorz) + return mxMinMaxItem->GetValue().Right(); + else + return mxMinMaxItem->GetValue().Bottom(); + } + return 0; +} + + +tools::Long SvxRuler::GetRightFrameMargin() const +{ + /* Get right frame margin (in logical units) */ + if (mxColumnItem) + { + if (!IsActLastColumn(true)) + { + return mxColumnItem->At(GetActRightColumn(true)).nEnd; + } + } + + tools::Long lResult = lLogicNullOffset; + + // If possible deduct right table entry + if(mxColumnItem && mxColumnItem->IsTable()) + lResult += mxColumnItem->GetRight(); + else if(bHorz && mxLRSpaceItem) + lResult += mxLRSpaceItem->GetRight(); + else if(!bHorz && mxULSpaceItem) + lResult += mxULSpaceItem->GetLower(); + + if (bHorz && mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable())) + lResult += mxBorderItem->GetRight(); + + if(bHorz) + lResult = mxPagePosItem->GetWidth() - lResult; + else + lResult = mxPagePosItem->GetHeight() - lResult; + + return lResult; +} + +#define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \ + SvxRulerSupportFlags::NEGATIVE_MARGINS ) +#define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() ) + +tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight ) +{ + /* + Corrects the position within the calculated limits. The limit values are in + pixels relative to the page edge. + */ + + const tools::Long lNullPix = Ruler::GetNullOffset(); + tools::Long lDragPos = GetDragPos() + lNullPix; + bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows; + if((bLeft || bHoriRows) && lDragPos < nMaxLeft) + lDragPos = nMaxLeft; + else if((bRight||bHoriRows) && lDragPos > nMaxRight) + lDragPos = nMaxRight; + return lDragPos - lNullPix; +} + +static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs + RulerTab* pTabs, // Tab buffer + tools::Long lDiff) // difference to be added +{ + /* Helper function, move all the tabs by a fixed value */ + if( pTabs ) + { + for(sal_uInt16 i = 0; i < nCount; ++i) + { + pTabs[i].nPos += lDiff; + } + } +} + +void SvxRuler::DragMargin1() +{ + /* Dragging the left edge of frame */ + tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG ); + + aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false); + + // Check if position changed + if (aDragPosition == 0) + return; + + DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz); + if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)) + DragBorders(); + AdjustMargin1(aDragPosition); +} + +void SvxRuler::AdjustMargin1(tools::Long lInputDiff) +{ + const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset(); + const tools::Long lDragPos = lInputDiff; + + bool bProtectColumns = + mxRulerImpl->aProtectItem->IsSizeProtected() || + mxRulerImpl->aProtectItem->IsPosProtected(); + + const RulerMarginStyle nMarginStyle = + bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable; + + if(!bAppSetNullOffset) + { + tools::Long lDiff = lDragPos; + SetNullOffset(nOld + lDiff); + if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)) + { + SetMargin2( GetMargin2() - lDiff, nMarginStyle ); + + if (!mxColumnItem && !mxObjectItem && mxParaItem) + { + // Right indent of the old position + mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + if (mxObjectItem) + { + mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff; + mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff; + SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0)); + } + if (mxColumnItem) + { + for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i) + mpBorders[i].nPos -= lDiff; + SetBorders(mxColumnItem->Count()-1, mpBorders.data()); + if(mxColumnItem->IsFirstAct()) + { + // Right indent of the old position + if (mxParaItem) + { + mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + } + else + { + if (mxParaItem) + { + mpIndents[INDENT_FIRST_LINE].nPos -= lDiff; + mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff; + mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + } + if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL) + &&!IsActFirstColumn()) + { + ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff); + SetTabs(nTabCount, mpTabs.data() + TAB_GAP); + } + } + } + } + else + { + tools::Long lDiff = lDragPos - nOld; + SetMargin1(nOld + lDiff, nMarginStyle); + + if (!mxColumnItem + || !(nDragType + & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR + | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))) + { + if (!mxColumnItem && !mxObjectItem && mxParaItem) + { + // Left indent of the old position + mpIndents[INDENT_FIRST_LINE].nPos += lDiff; + mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + + if (mxColumnItem) + { + for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i) + mpBorders[i].nPos += lDiff; + SetBorders(mxColumnItem->Count() - 1, mpBorders.data()); + if (mxColumnItem->IsFirstAct()) + { + // Left indent of the old position + if (mxParaItem) + { + mpIndents[INDENT_FIRST_LINE].nPos += lDiff; + mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + } + else + { + if (mxParaItem) + { + mpIndents[INDENT_FIRST_LINE].nPos += lDiff; + mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff; + mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + } + } + if (mxTabStopItem) + { + ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff); + SetTabs(nTabCount, mpTabs.data() + TAB_GAP); + } + } + } +} + +void SvxRuler::DragMargin2() +{ + /* Dragging the right edge of frame */ + tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG); + aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false); + tools::Long lDiff = aDragPosition - GetMargin2(); + + // Check if position changed + if (lDiff == 0) + return; + + if( mxRulerImpl->bIsTableRows && + !bHorz && + mxColumnItem && + (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)) + { + DragBorders(); + } + + bool bProtectColumns = + mxRulerImpl->aProtectItem->IsSizeProtected() || + mxRulerImpl->aProtectItem->IsPosProtected(); + + const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable; + + SetMargin2( aDragPosition, nMarginStyle ); + + // Right indent of the old position + if ((!mxColumnItem || IsActLastColumn()) && mxParaItem) + { + mpIndents[INDENT_FIRST_LINE].nPos += lDiff; + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + } + + DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz); +} + +void SvxRuler::DragIndents() +{ + /* Dragging the paragraph indents */ + tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos(); + const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP; + + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + + if(nIndex == INDENT_RIGHT_MARGIN) + aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin()); + else + aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin()); + + const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition; + + // Check if position changed + if (lDiff == 0) + return; + + if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN ) && + !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY)) + { + mpIndents[INDENT_FIRST_LINE].nPos -= lDiff; + } + + mpIndents[nIndex].nPos = aDragPosition; + + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + DrawLine_Impl(lTabPos, 1, bHorz); +} + +void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal) +{ + /* + Output routine for the ledger line when moving tabs, tables and other + columns + */ + if(bHorizontal) + { + const tools::Long nHeight = pEditWin->GetOutDev()->GetOutputSize().Height(); + Point aZero = pEditWin->GetMapMode().GetOrigin(); + if(lTabPosition != -1) + { + pEditWin->InvertTracking( + tools::Rectangle( Point(lTabPosition, -aZero.Y()), + Point(lTabPosition, -aZero.Y() + nHeight)), + ShowTrackFlags::Split | ShowTrackFlags::Clip ); + } + if( nNew & 1 ) + { + tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 ); + nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin()); + lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() ); + if (mxPagePosItem) + lTabPosition += mxPagePosItem->GetPos().X(); + pEditWin->InvertTracking( + tools::Rectangle( Point(lTabPosition, -aZero.Y()), + Point(lTabPosition, -aZero.Y() + nHeight) ), + ShowTrackFlags::Clip | ShowTrackFlags::Split ); + } + } + else + { + const tools::Long nWidth = pEditWin->GetOutDev()->GetOutputSize().Width(); + Point aZero = pEditWin->GetMapMode().GetOrigin(); + if(lTabPosition != -1) + { + pEditWin->InvertTracking( + tools::Rectangle( Point(-aZero.X(), lTabPosition), + Point(-aZero.X() + nWidth, lTabPosition)), + ShowTrackFlags::Split | ShowTrackFlags::Clip ); + } + + if(nNew & 1) + { + tools::Long nDrapPosition = GetCorrectedDragPos(); + nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin()); + lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset()); + if (mxPagePosItem) + lTabPosition += mxPagePosItem->GetPos().Y(); + pEditWin->InvertTracking( + tools::Rectangle( Point(-aZero.X(), lTabPosition), + Point(-aZero.X()+nWidth, lTabPosition)), + ShowTrackFlags::Clip | ShowTrackFlags::Split ); + } + } +} + +void SvxRuler::DragTabs() +{ + /* Dragging of Tabs */ + tools::Long aDragPosition = GetCorrectedDragPos(true, false); + aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin()); + + sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP; + tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos; + if (nDiff == 0) + return; + + DrawLine_Impl(lTabPos, 7, bHorz); + + if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR) + { + + for(sal_uInt16 i = nIdx; i < nTabCount; ++i) + { + mpTabs[i].nPos += nDiff; + // limit on maximum + if(mpTabs[i].nPos > GetMargin2()) + mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE; + else + mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE; + } + } + else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL) + { + mxRulerImpl->nTotalDist -= nDiff; + mpTabs[nIdx].nPos = aDragPosition; + for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i) + { + if(mpTabs[i].nStyle & RULER_TAB_DEFAULT) + // can be canceled at the DefaultTabs + break; + tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]; + nDelta /= 1000; + mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta; + if(mpTabs[i].nPos + GetNullOffset() > nMaxRight) + mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE; + else + mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE; + } + } + else + { + mpTabs[nIdx].nPos = aDragPosition; + } + + if(IsDragDelete()) + mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE; + else + mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE; + SetTabs(nTabCount, mpTabs.data() + TAB_GAP); +} + +void SvxRuler::SetActive(bool bOn) +{ + if(bOn) + { + Activate(); + } + else + Deactivate(); + if(bActive!=bOn) + { + pBindings->EnterRegistrations(); + if(bOn) + for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++) + pCtrlItems[i]->ReBind(); + else + for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++) + pCtrlItems[j]->UnBind(); + pBindings->LeaveRegistrations(); + } + bActive = bOn; +} + +void SvxRuler::UpdateParaContents_Impl( + tools::Long lDifference, + UpdateType eType) // Art (all, left or right) +{ + /* Helper function; carry Tabs and Paragraph Margins */ + switch(eType) + { + case UpdateType::MoveRight: + mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference; + break; + case UpdateType::MoveLeft: + { + mpIndents[INDENT_FIRST_LINE].nPos += lDifference; + mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference; + if (!mpTabs.empty()) + { + for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i) + { + mpTabs[i].nPos += lDifference; + } + SetTabs(nTabCount, mpTabs.data() + TAB_GAP); + } + break; + } + } + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); +} + +void SvxRuler::DragBorders() +{ + /* Dragging of Borders (Tables and other columns) */ + bool bLeftIndentsCorrected = false; + bool bRightIndentsCorrected = false; + int nIndex; + + if(GetDragType() == RulerType::Border) + { + DrawLine_Impl(lTabPos, 7, bHorz); + nIndex = GetDragAryPos(); + } + else + { + nIndex = 0; + } + + RulerDragSize nDragSize = GetDragSize(); + tools::Long lDiff = 0; + + // the drag position has to be corrected to be able to prevent borders from passing each other + tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin()); + + switch(nDragSize) + { + case RulerDragSize::Move: + { + if(GetDragType() == RulerType::Border) + lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos; + else + lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin; + + if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR) + { + tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters + for(int i = mpBorders.size() - 2; i >= nIndex; --i) + { + tools::Long l = mpBorders[i].nPos; + mpBorders[i].nPos += lDiff; + mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth); + nRight = mpBorders[i].nPos - glMinFrame; + // RR update the column + if(i == GetActRightColumn()) + { + UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight); + bRightIndentsCorrected = true; + } + // LAR, EZE update the column + else if(i == GetActLeftColumn()) + { + UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft); + bLeftIndentsCorrected = true; + } + } + } + else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL) + { + int nLimit; + tools::Long lLeft; + int nStartLimit = mpBorders.size() - 2; + switch(GetDragType()) + { + default: ;//prevent warning + OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" ); + [[fallthrough]]; + case RulerType::Border: + if(mxRulerImpl->bIsTableRows) + { + mpBorders[nIndex].nPos += lDiff; + if(bHorz) + { + lLeft = mpBorders[nIndex].nPos; + mxRulerImpl->nTotalDist -= lDiff; + nLimit = nIndex + 1; + } + else + { + lLeft = 0; + nStartLimit = nIndex - 1; + mxRulerImpl->nTotalDist += lDiff; + nLimit = 0; + } + } + else + { + nLimit = nIndex + 1; + mpBorders[nIndex].nPos += lDiff; + lLeft = mpBorders[nIndex].nPos; + mxRulerImpl->nTotalDist -= lDiff; + } + break; + case RulerType::Margin1: + nLimit = 0; + lLeft = mxRulerImpl->lLastLMargin + lDiff; + mxRulerImpl->nTotalDist -= lDiff; + break; + case RulerType::Margin2: + nLimit = 0; + lLeft= 0; + nStartLimit = mpBorders.size() - 2; + mxRulerImpl->nTotalDist += lDiff; + break; + } + + for(int i = nStartLimit; i >= nLimit; --i) + { + + tools::Long l = mpBorders[i].nPos; + mpBorders[i].nPos = + lLeft + + (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 + + mxRulerImpl->pBlockBuf[i]; + + // RR update the column + if(!mxRulerImpl->bIsTableRows) + { + if(i == GetActRightColumn()) + { + UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight); + bRightIndentsCorrected = true; + } + // LAR, EZE update the column + else if(i == GetActLeftColumn()) + { + UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft); + bLeftIndentsCorrected = true; + } + } + } + if(mxRulerImpl->bIsTableRows) + { + //in vertical tables the left borders have to be moved + if(bHorz) + { + for(int i = 0; i < nIndex; ++i) + mpBorders[i].nPos += lDiff; + AdjustMargin1(lDiff); + } + else + { + //otherwise the right borders are moved + for(int i = mxColumnItem->Count() - 1; i > nIndex; --i) + mpBorders[i].nPos += lDiff; + SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE ); + } + } + } + else if(mxRulerImpl->bIsTableRows) + { + //moving rows: if a row is resized all following rows + //have to be moved by the same amount. + //This includes the left border when the table is not limited + //to a lower frame border. + int nLimit; + if(GetDragType()==RulerType::Border) + { + nLimit = nIndex + 1; + mpBorders[nIndex].nPos += lDiff; + } + else + { + nLimit=0; + } + //in vertical tables the left borders have to be moved + if(bHorz) + { + for(int i = 0; i < nIndex; ++i) + { + mpBorders[i].nPos += lDiff; + } + AdjustMargin1(lDiff); + } + else + { + //otherwise the right borders are moved + for(int i = mpBorders.size() - 2; i >= nLimit; --i) + { + mpBorders[i].nPos += lDiff; + } + SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE ); + } + } + else + mpBorders[nIndex].nPos += lDiff; + break; + } + case RulerDragSize::N1: + { + lDiff = lPos - mpBorders[nIndex].nPos; + mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos; + mpBorders[nIndex].nPos = lPos; + break; + } + case RulerDragSize::N2: + { + const tools::Long nOld = mpBorders[nIndex].nWidth; + mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos; + lDiff = mpBorders[nIndex].nWidth - nOld; + break; + } + } + if(!bRightIndentsCorrected && + GetActRightColumn() == nIndex && + nDragSize != RulerDragSize::N2 && + !mpIndents.empty() && + !mxRulerImpl->bIsTableRows) + { + UpdateParaContents_Impl(lDiff, UpdateType::MoveRight); + } + else if(!bLeftIndentsCorrected && + GetActLeftColumn() == nIndex && + nDragSize != RulerDragSize::N1 && + !mpIndents.empty()) + { + UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft); + } + SetBorders(mxColumnItem->Count() - 1, mpBorders.data()); +} + +void SvxRuler::DragObjectBorder() +{ + /* Dragging of object edges */ + if(RulerDragSize::Move == GetDragSize()) + { + const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin()); + + const sal_uInt16 nIdx = GetDragAryPos(); + mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition; + SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0)); + DrawLine_Impl(lTabPos, 7, bHorz); + + } +} + +void SvxRuler::ApplyMargins() +{ + /* Applying margins; changed by dragging. */ + const SfxPoolItem* pItem = nullptr; + sal_uInt16 nId = SID_ATTR_LONG_LRSPACE; + + if(bHorz) + { + const tools::Long lOldNull = lLogicNullOffset; + if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset()) + { + lLogicNullOffset = mxRulerImpl->lMaxLeftLogic; + mxLRSpaceItem->SetLeft(lLogicNullOffset); + } + else + { + lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset; + mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft())); + } + + if(bAppSetNullOffset) + { + lAppNullOffset += lLogicNullOffset - lOldNull; + } + + tools::Long nRight; + if(mxRulerImpl->lMaxRightLogic != -1 + && nMaxRight == GetMargin2() + Ruler::GetNullOffset()) + { + nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic; + } + else + { + nRight = std::max(tools::Long(0), + mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() - + (ConvertHPosLogic(GetMargin2()) - lAppNullOffset)); + + nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight()); + } + mxLRSpaceItem->SetRight(nRight); + + pItem = mxLRSpaceItem.get(); + +#ifdef DEBUGLIN + Debug_Impl(pEditWin, *mxLRSpaceItem); +#endif // DEBUGLIN + + } + else + { + const tools::Long lOldNull = lLogicNullOffset; + lLogicNullOffset = + ConvertVPosLogic(GetFrameLeft()) - + lAppNullOffset; + mxULSpaceItem->SetUpper( + PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper())); + if(bAppSetNullOffset) + { + lAppNullOffset += lLogicNullOffset - lOldNull; + } + mxULSpaceItem->SetLower( + PixelVAdjust( + std::max(tools::Long(0), mxPagePosItem->GetHeight() - + mxULSpaceItem->GetUpper() - + (ConvertVPosLogic(GetMargin2()) - + lAppNullOffset)), mxULSpaceItem->GetLower())); + pItem = mxULSpaceItem.get(); + nId = SID_ATTR_LONG_ULSPACE; + +#ifdef DEBUGLIN + Debug_Impl(pEditWin,*mxULSpaceItem); +#endif // DEBUGLIN + + } + pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem }); + if (mxTabStopItem) + UpdateTabs(); +} + +tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const +{ + RulerUnitData aUnitData = GetCurrentRulerUnit(); + double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1; + + tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); + lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit; + return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width(); +} + +void SvxRuler::ApplyIndents() +{ + /* Applying paragraph settings; changed by dragging. */ + + tools::Long nLeftFrameMargin = GetLeftFrameMargin(); + + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + + tools::Long nNewTxtLeft; + tools::Long nNewFirstLineOffset; + tools::Long nNewRight; + + tools::Long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos); + tools::Long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos); + tools::Long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos); + + if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true)))) + { + if(bRTL) + { + tools::Long nRightColumn = GetActRightColumn(true); + tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos); + nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset; + } + else + { + tools::Long nLeftColumn = GetActLeftColumn(true); + tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth); + nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset; + } + } + else + { + if(bRTL) + { + tools::Long nRightBorder = ConvertPosLogic(GetMargin2()); + nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset; + } + else + { + tools::Long nLeftBorder = ConvertPosLogic(GetMargin1()); + nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset; + } + } + + if(bRTL) + nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset; + else + nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset; + + if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true)))) + { + if(bRTL) + { + tools::Long nLeftColumn = GetActLeftColumn(true); + tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth); + nNewRight = nRightMargin - nLeftBorder - lAppNullOffset; + } + else + { + tools::Long nRightColumn = GetActRightColumn(true); + tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos); + nNewRight = nRightBorder - nRightMargin - lAppNullOffset; + } + } + else + { + if(bRTL) + { + tools::Long nLeftBorder = ConvertPosLogic(GetMargin1()); + nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset; + } + else + { + tools::Long nRightBorder = ConvertPosLogic(GetMargin2()); + nNewRight = nRightBorder - nRightMargin - lAppNullOffset; + } + } + + if (mbSnapping) + { + nNewTxtLeft = RoundToCurrentMapMode(nNewTxtLeft); + nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset); + nNewRight = RoundToCurrentMapMode(nNewRight); + } + + mxParaItem->SetTextFirstLineOffset(sal::static_int_cast<short>(nNewFirstLineOffset)); + mxParaItem->SetTextLeft(nNewTxtLeft); + mxParaItem->SetRight(nNewRight); + + sal_uInt16 nParagraphId = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL; + pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD, + { mxParaItem.get() }); + UpdateTabs(); +} + +void SvxRuler::ApplyTabs() +{ + /* Apply tab settings, changed by dragging. */ + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + const sal_uInt16 nCoreIdx = GetDragAryPos(); + if(IsDragDelete()) + { + mxTabStopItem->Remove(nCoreIdx); + } + else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType || + SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) + { + SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which()); + //remove default tab stops + for ( sal_uInt16 i = 0; i < pItem->Count(); ) + { + if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() ) + { + pItem->Remove(i); + continue; + } + ++i; + } + + sal_uInt16 j; + for(j = 0; j < nCoreIdx; ++j) + { + pItem->Insert(mxTabStopItem->At(j)); + } + for(; j < mxTabStopItem->Count(); ++j) + { + SvxTabStop aTabStop = mxTabStopItem->At(j); + aTabStop.GetTabPos() = PixelHAdjust( + ConvertHPosLogic( + mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset, + aTabStop.GetTabPos()); + pItem->Insert(aTabStop); + } + mxTabStopItem.reset(pItem); + } + else if( mxTabStopItem->Count() == 0 ) + return; + else + { + SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx); + if( mxRulerImpl->lMaxRightLogic != -1 && + mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight ) + { + // Set tab pos exactly at the right indent + tools::Long nTmpLeftIndentLogic + = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin()); + if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem) + { + nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetTextLeft(); + } + aTabStop.GetTabPos() + = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic; + } + else + { + if(bRTL) + { + //#i24363# tab stops relative to indent + const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ? + GetLeftIndent() : + ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ); + + tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos); + aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos()); + } + else + { + //#i24363# tab stops relative to indent + const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ? + GetLeftIndent() : + ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ); + + tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent); + aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos()); + } + } + mxTabStopItem->Remove(nCoreIdx); + mxTabStopItem->Insert(aTabStop); + } + sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL; + pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD, + { mxTabStopItem.get() }); + UpdateTabs(); +} + +void SvxRuler::ApplyBorders() +{ + /* Applying (table) column settings; changed by dragging. */ + if(mxColumnItem->IsTable()) + { + tools::Long lValue = GetFrameLeft(); + if(lValue != mxRulerImpl->nColLeftPix) + { + tools::Long nLeft = PixelHAdjust( + ConvertHPosLogic(lValue) - + lAppNullOffset, + mxColumnItem->GetLeft()); + mxColumnItem->SetLeft(nLeft); + } + + lValue = GetMargin2(); + + if(lValue != mxRulerImpl->nColRightPix) + { + tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight(); + tools::Long nRight = PixelHAdjust( + nWidthOrHeight - + mxColumnItem->GetLeft() - + ConvertHPosLogic(lValue) - + lAppNullOffset, + mxColumnItem->GetRight() ); + mxColumnItem->SetRight(nRight); + } + } + + for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i) + { + tools::Long& nEnd = mxColumnItem->At(i).nEnd; + nEnd = PixelHAdjust( + ConvertPosLogic(mpBorders[i].nPos), + mxColumnItem->At(i).nEnd); + tools::Long& nStart = mxColumnItem->At(i + 1).nStart; + nStart = PixelHAdjust( + ConvertSizeLogic(mpBorders[i].nPos + + mpBorders[i].nWidth) - + lAppNullOffset, + mxColumnItem->At(i + 1).nStart); + // It may be that, due to the PixelHAdjust readjustment to old values, + // the width becomes < 0. This we readjust. + if( nEnd > nStart ) + nStart = nEnd; + } + +#ifdef DEBUGLIN + Debug_Impl(pEditWin,*mxColumnItem); +#endif // DEBUGLIN + + SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY, + bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)); + + sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) : + (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL); + + pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD, + { mxColumnItem.get(), &aFlag }); +} + +void SvxRuler::ApplyObject() +{ + /* Applying object settings, changed by dragging. */ + + // to the page margin + tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0; + tools::Long nStartX = PixelAdjust( + ConvertPosLogic(mpObjectBorders[0].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetStartX()); + mxObjectItem->SetStartX(nStartX); + + tools::Long nEndX = PixelAdjust( + ConvertPosLogic(mpObjectBorders[1].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetEndX()); + mxObjectItem->SetEndX(nEndX); + + nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0; + tools::Long nStartY = PixelAdjust( + ConvertPosLogic(mpObjectBorders[2].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetStartY()); + mxObjectItem->SetStartY(nStartY); + + tools::Long nEndY = PixelAdjust( + ConvertPosLogic(mpObjectBorders[3].nPos) + + nMargin - + lAppNullOffset, + mxObjectItem->GetEndY()); + mxObjectItem->SetEndY(nEndY); + + pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT, + SfxCallMode::RECORD, { mxObjectItem.get() }); +} + +void SvxRuler::PrepareProportional_Impl(RulerType eType) +{ + /* + Preparation proportional dragging, and it is calculated based on the + proportional share of the total width in parts per thousand. + */ + mxRulerImpl->nTotalDist = GetMargin2(); + switch(eType) + { + case RulerType::Margin2: + case RulerType::Margin1: + case RulerType::Border: + { + DBG_ASSERT(mxColumnItem, "no ColumnItem"); + + mxRulerImpl->SetPercSize(mxColumnItem->Count()); + + tools::Long lPos; + tools::Long lWidth=0; + sal_uInt16 nStart; + sal_uInt16 nIdx=GetDragAryPos(); + tools::Long lActWidth=0; + tools::Long lActBorderSum; + tools::Long lOrigLPos; + + if(eType != RulerType::Border) + { + lOrigLPos = GetMargin1(); + nStart = 0; + lActBorderSum = 0; + } + else + { + if(mxRulerImpl->bIsTableRows &&!bHorz) + { + lOrigLPos = GetMargin1(); + nStart = 0; + } + else + { + lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth; + nStart = 1; + } + lActBorderSum = mpBorders[nIdx].nWidth; + } + + //in horizontal mode the percentage value has to be + //calculated on a "current change" position base + //because the height of the table changes while dragging + if(mxRulerImpl->bIsTableRows && RulerType::Border == eType) + { + sal_uInt16 nStartBorder; + sal_uInt16 nEndBorder; + if(bHorz) + { + nStartBorder = nIdx + 1; + nEndBorder = mxColumnItem->Count() - 1; + } + else + { + nStartBorder = 0; + nEndBorder = nIdx; + } + + lWidth = mpBorders[nIdx].nPos; + if(bHorz) + lWidth = GetMargin2() - lWidth; + mxRulerImpl->nTotalDist = lWidth; + lPos = mpBorders[nIdx].nPos; + + for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i) + { + if(bHorz) + { + lActWidth += mpBorders[i].nPos - lPos; + lPos = mpBorders[i].nPos + mpBorders[i].nWidth; + } + else + lActWidth = mpBorders[i].nPos; + mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000) + / mxRulerImpl->nTotalDist); + mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum); + lActBorderSum += mpBorders[i].nWidth; + } + } + else + { + lPos = lOrigLPos; + for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii) + { + lWidth += mpBorders[ii].nPos - lPos; + lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth; + } + + lWidth += GetMargin2() - lPos; + mxRulerImpl->nTotalDist = lWidth; + lPos = lOrigLPos; + + for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i) + { + lActWidth += mpBorders[i].nPos - lPos; + lPos = mpBorders[i].nPos + mpBorders[i].nWidth; + mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000) + / mxRulerImpl->nTotalDist); + mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum); + lActBorderSum += mpBorders[i].nWidth; + } + } + } + break; + case RulerType::Tab: + { + const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP; + mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos; + mxRulerImpl->SetPercSize(nTabCount); + for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ; + for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i) + { + const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos; + mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist); + } + break; + } + default: break; + } +} + +void SvxRuler::EvalModifier() +{ + /* + Eval Drag Modifier + Shift: move linear + Control: move proportional + Shift + Control: Table: only current line + Alt: disable snapping + Alt + Shift: coarse snapping + */ + + sal_uInt16 nModifier = GetDragModifier(); + if(mxRulerImpl->bIsTableRows) + { + //rows can only be moved in one way, additionally current column is possible + if(nModifier == KEY_SHIFT) + nModifier = 0; + } + + switch(nModifier) + { + case KEY_SHIFT: + nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR; + break; + case KEY_MOD2 | KEY_SHIFT: + mbCoarseSnapping = true; + break; + case KEY_MOD2: + mbSnapping = false; + break; + case KEY_MOD1: + { + const RulerType eType = GetDragType(); + nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL; + if( RulerType::Tab == eType || + ( ( RulerType::Border == eType || + RulerType::Margin1 == eType || + RulerType::Margin2 == eType ) && + mxColumnItem ) ) + { + PrepareProportional_Impl(eType); + } + } + break; + case KEY_MOD1 | KEY_SHIFT: + if( GetDragType() != RulerType::Margin1 && + GetDragType() != RulerType::Margin2 ) + { + nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY; + } + break; + } +} + +void SvxRuler::Click() +{ + /* Override handler SV; sets Tab per dispatcher call */ + Ruler::Click(); + if( bActive ) + { + pBindings->Update( SID_RULER_LR_MIN_MAX ); + pBindings->Update( SID_ATTR_LONG_ULSPACE ); + pBindings->Update( SID_ATTR_LONG_LRSPACE ); + pBindings->Update( SID_RULER_PAGE_POS ); + pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL); + pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL); + pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL); + pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL); + pBindings->Update( SID_RULER_OBJECT ); + pBindings->Update( SID_RULER_PROTECT ); + pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL ); + } + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + if(!(mxTabStopItem && + (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)) + return; + + bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected(); + if( bContentProtected ) return; + const tools::Long lPos = GetClickPos(); + if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) || + (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent()))) + return; + + //convert position in left-to-right text + tools::Long nTabPos; +//#i24363# tab stops relative to indent + if(bRTL) + nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ? + GetLeftIndent() : + ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) - + lPos; + else + nTabPos = lPos - + ( mxRulerImpl->bIsTabsRelativeToIndent ? + GetLeftIndent() : + ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset )); + + SvxTabStop aTabStop(ConvertHPosLogic(nTabPos), + ToAttrTab_Impl(nDefTabType)); + mxTabStopItem->Insert(aTabStop); + UpdateTabs(); +} + +void SvxRuler::CalcMinMax() +{ + /* + Calculates the limits for dragging; which are in pixels relative to the + page edge + */ + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset); + mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1; + switch(GetDragType()) + { + case RulerType::Margin1: + { // left edge of the surrounding Frame + // DragPos - NOf between left - right + mxRulerImpl->lMaxLeftLogic = GetLeftMin(); + nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic); + + if (!mxColumnItem || mxColumnItem->Count() == 1) + { + if(bRTL) + { + nMaxRight = lNullPix - GetRightIndent() + + std::max(GetFirstLineIndent(), GetLeftIndent()) - + glMinFrame; + } + else + { + nMaxRight = lNullPix + GetRightIndent() - + std::max(GetFirstLineIndent(), GetLeftIndent()) - + glMinFrame; + } + } + else if(mxRulerImpl->bIsTableRows) + { + //top border is not moveable when table rows are displayed + // protection of content means the margin is not moveable + if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected()) + { + nMaxLeft = mpBorders[0].nMinPos + lNullPix; + if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL) + nMaxRight = GetRightIndent() + lNullPix - + (mxColumnItem->Count() - 1 ) * glMinFrame; + else + nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix; + } + else + nMaxLeft = nMaxRight = lNullPix; + } + else + { + if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL) + { + nMaxRight=lNullPix+CalcPropMaxRight(); + } + else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR) + { + nMaxRight = ConvertPosPixel( + GetPageWidth() - ( + (mxColumnItem->IsTable() && mxLRSpaceItem) + ? mxLRSpaceItem->GetRight() : 0)) + - GetMargin2() + GetMargin1(); + } + else + { + nMaxRight = lNullPix - glMinFrame; + if (mxColumnItem->IsFirstAct()) + { + if(bRTL) + { + nMaxRight += std::min( + mpBorders[0].nPos, + std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent()); + } + else + { + nMaxRight += std::min( + mpBorders[0].nPos, GetRightIndent() - + std::max(GetFirstLineIndent(), GetLeftIndent())); + } + } + else if ( mxColumnItem->Count() > 1 ) + { + nMaxRight += mpBorders[0].nPos; + } + else + { + nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent()); + } + // Do not drag the left table edge over the edge of the page + if(mxLRSpaceItem && mxColumnItem->IsTable()) + { + tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft()); + if(nTmp>nMaxLeft) + nMaxLeft=nTmp; + } + } + } + break; + } + case RulerType::Margin2: + { // right edge of the surrounding Frame + mxRulerImpl->lMaxRightLogic + = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth(); + nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic); + + if (!mxColumnItem) + { + if(bRTL) + { + nMaxLeft = GetMargin2() + GetRightIndent() - + std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+ + glMinFrame + lNullPix; + } + else + { + nMaxLeft = GetMargin2() - GetRightIndent() + + std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+ + glMinFrame + lNullPix; + } + } + else if(mxRulerImpl->bIsTableRows) + { + // get the bottom move range from the last border position - only available for rows! + // protection of content means the margin is not moveable + if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected()) + { + nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix; + } + else + { + if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL) + { + nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix; + } + else + { + if(mxColumnItem->Count() > 1) + nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix; + else + nMaxLeft = glMinFrame + lNullPix; + } + if(mxColumnItem->Count() > 1) + nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix; + else + nMaxRight -= GetRightIndent() - lNullPix; + } + } + else + { + nMaxLeft = glMinFrame + lNullPix; + if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column + { + if(bRTL) + { + nMaxLeft = glMinFrame + lNullPix + GetMargin2() + + GetRightIndent() - std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + else + { + nMaxLeft = glMinFrame + lNullPix + GetMargin2() - + GetRightIndent() + std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + } + if( mxColumnItem->Count() >= 2 ) + { + tools::Long nNewMaxLeft = + glMinFrame + lNullPix + + mpBorders[mxColumnItem->Count() - 2].nPos + + mpBorders[mxColumnItem->Count() - 2].nWidth; + nMaxLeft = std::max(nMaxLeft, nNewMaxLeft); + } + + } + break; + } + case RulerType::Border: + { // Table, column (Modifier) + const sal_uInt16 nIdx = GetDragAryPos(); + switch(GetDragSize()) + { + case RulerDragSize::N1 : + { + nMaxRight = mpBorders[nIdx].nPos + + mpBorders[nIdx].nWidth + lNullPix; + + if(0 == nIdx) + nMaxLeft = lNullPix; + else + nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix; + if (mxColumnItem && nIdx == mxColumnItem->GetActColumn()) + { + if(bRTL) + { + nMaxLeft += mpBorders[nIdx].nPos + + GetRightIndent() - std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + else + { + nMaxLeft += mpBorders[nIdx].nPos - + GetRightIndent() + std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + if(0 != nIdx) + nMaxLeft -= mpBorders[nIdx-1].nPos + + mpBorders[nIdx-1].nWidth; + } + nMaxLeft += glMinFrame; + nMaxLeft += nDragOffset; + break; + } + case RulerDragSize::Move: + { + if (mxColumnItem) + { + //nIdx contains the position of the currently moved item + //next visible separator on the left + sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx); + //next visible separator on the right + sal_uInt16 nRightCol=GetActRightColumn(false, nIdx); + //next separator on the left - regardless if visible or not + sal_uInt16 nActLeftCol=GetActLeftColumn(); + //next separator on the right - regardless if visible or not + sal_uInt16 nActRightCol=GetActRightColumn(); + if(mxColumnItem->IsTable()) + { + if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY) + { + //the current row/column should be modified only + //then the next/previous visible border position + //marks the min/max positions + nMaxLeft = nLeftCol == USHRT_MAX ? + 0 : + mpBorders[nLeftCol].nPos; + //rows can always be increased without a limit + if(mxRulerImpl->bIsTableRows) + nMaxRight = mpBorders[nIdx].nMaxPos; + else + nMaxRight = nRightCol == USHRT_MAX ? + GetMargin2(): + mpBorders[nRightCol].nPos; + nMaxLeft += lNullPix; + nMaxRight += lNullPix; + } + else + { + if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows) + nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix; + else + nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix; + if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) || + (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) ) + { + if(mxRulerImpl->bIsTableRows) + { + if(bHorz) + nMaxRight = GetRightIndent() + lNullPix - + (mxColumnItem->Count() - nIdx - 1) * glMinFrame; + else + nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix; + } + else + nMaxRight=lNullPix+CalcPropMaxRight(nIdx); + } + else + nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix; + } + nMaxLeft += glMinFrame; + nMaxRight -= glMinFrame; + + } + else + { + if(nLeftCol==USHRT_MAX) + nMaxLeft=lNullPix; + else + nMaxLeft = mpBorders[nLeftCol].nPos + + mpBorders[nLeftCol].nWidth + lNullPix; + + if(nActRightCol == nIdx) + { + if(bRTL) + { + nMaxLeft += mpBorders[nIdx].nPos + + GetRightIndent() - std::max(GetFirstLineIndent(), + GetLeftIndent()); + if(nActLeftCol!=USHRT_MAX) + nMaxLeft -= mpBorders[nActLeftCol].nPos + + mpBorders[nActLeftCol].nWidth; + } + else + { + nMaxLeft += mpBorders[nIdx].nPos - + GetRightIndent() + std::max(GetFirstLineIndent(), + GetLeftIndent()); + if(nActLeftCol!=USHRT_MAX) + nMaxLeft -= mpBorders[nActLeftCol].nPos + + mpBorders[nActLeftCol].nWidth; + } + } + nMaxLeft += glMinFrame; + nMaxLeft += nDragOffset; + + // nMaxRight + // linear / proportional move + if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) || + (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) ) + { + nMaxRight=lNullPix+CalcPropMaxRight(nIdx); + } + else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) + { + nMaxRight = lNullPix + GetMargin2() - GetMargin1() + + (mpBorders.size() - nIdx - 1) * glMinFrame; + } + else + { + if(nRightCol==USHRT_MAX) + { // last column + nMaxRight = GetMargin2() + lNullPix; + if(IsActLastColumn()) + { + if(bRTL) + { + nMaxRight -= + GetMargin2() + GetRightIndent() - + std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + else + { + nMaxRight -= + GetMargin2() - GetRightIndent() + + std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + nMaxRight += mpBorders[nIdx].nPos + + mpBorders[nIdx].nWidth; + } + } + else + { + nMaxRight = lNullPix + mpBorders[nRightCol].nPos; + sal_uInt16 nNotHiddenRightCol = + GetActRightColumn(true, nIdx); + + if( nActLeftCol == nIdx ) + { + tools::Long nBorder = nNotHiddenRightCol == + USHRT_MAX ? + GetMargin2() : + mpBorders[nNotHiddenRightCol].nPos; + if(bRTL) + { + nMaxRight -= nBorder + GetRightIndent() - + std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + else + { + nMaxRight -= nBorder - GetRightIndent() + + std::max(GetFirstLineIndent(), + GetLeftIndent()); + } + nMaxRight += mpBorders[nIdx].nPos + + mpBorders[nIdx].nWidth; + } + } + nMaxRight -= glMinFrame; + nMaxRight -= mpBorders[nIdx].nWidth; + } + } + } + // ObjectItem + else + { + nMaxLeft = LONG_MIN; + nMaxRight = LONG_MAX; + } + break; + } + case RulerDragSize::N2: + if (mxColumnItem) + { + nMaxLeft = lNullPix + mpBorders[nIdx].nPos; + if(nIdx == mxColumnItem->Count()-2) { // last column + nMaxRight = GetMargin2() + lNullPix; + if(mxColumnItem->IsLastAct()) { + nMaxRight -= + GetMargin2() - GetRightIndent() + + std::max(GetFirstLineIndent(), + GetLeftIndent()); + nMaxRight += mpBorders[nIdx].nPos + + mpBorders[nIdx].nWidth; + } + } + else { + nMaxRight = lNullPix + mpBorders[nIdx+1].nPos; + if(mxColumnItem->GetActColumn()-1 == nIdx) { + nMaxRight -= mpBorders[nIdx+1].nPos - GetRightIndent() + + std::max(GetFirstLineIndent(), + GetLeftIndent()); + nMaxRight += mpBorders[nIdx].nPos + + mpBorders[nIdx].nWidth; + } + } + nMaxRight -= glMinFrame; + nMaxRight -= mpBorders[nIdx].nWidth; + break; + } + } + nMaxRight += nDragOffset; + break; + } + case RulerType::Indent: + { + const sal_uInt16 nIdx = GetDragAryPos(); + switch(nIdx) { + case INDENT_FIRST_LINE - INDENT_GAP: + case INDENT_LEFT_MARGIN - INDENT_GAP: + { + if(bRTL) + { + nMaxLeft = lNullPix + GetRightIndent(); + + if(mxColumnItem && !mxColumnItem->IsFirstAct()) + nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos + + mpBorders[mxColumnItem->GetActColumn()-1].nWidth; + nMaxRight = lNullPix + GetMargin2(); + + // Dragging along + if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx && + !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY)) + { + if(GetLeftIndent() > GetFirstLineIndent()) + nMaxLeft += GetLeftIndent() - GetFirstLineIndent(); + else + nMaxRight -= GetFirstLineIndent() - GetLeftIndent(); + } + } + else + { + nMaxLeft = lNullPix; + + if(mxColumnItem && !mxColumnItem->IsFirstAct()) + nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos + + mpBorders[mxColumnItem->GetActColumn()-1].nWidth; + nMaxRight = lNullPix + GetRightIndent() - glMinFrame; + + // Dragging along + if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx && + !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY)) + { + if(GetLeftIndent() > GetFirstLineIndent()) + nMaxLeft += GetLeftIndent() - GetFirstLineIndent(); + else + nMaxRight -= GetFirstLineIndent() - GetLeftIndent(); + } + } + } + break; + case INDENT_RIGHT_MARGIN - INDENT_GAP: + { + if(bRTL) + { + nMaxLeft = lNullPix; + nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame; + if (mxColumnItem) + { + sal_uInt16 nRightCol=GetActRightColumn( true ); + if(!IsActLastColumn( true )) + nMaxRight += mpBorders[nRightCol].nPos; + else + nMaxRight += GetMargin2(); + } + else + { + nMaxLeft += GetMargin1(); + } + nMaxLeft += glMinFrame; + } + else + { + nMaxLeft = lNullPix + + std::max(GetFirstLineIndent(), GetLeftIndent()); + nMaxRight = lNullPix; + if (mxColumnItem) + { + sal_uInt16 nRightCol=GetActRightColumn( true ); + if(!IsActLastColumn( true )) + nMaxRight += mpBorders[nRightCol].nPos; + else + nMaxRight += GetMargin2(); + } + else + nMaxRight += GetMargin2(); + nMaxLeft += glMinFrame; + } + } + break; + } + break; + } + case RulerType::Tab: // Tabs (Modifier) + /* left = NOf + Max(LAR, EZ) + right = NOf + RAR */ + + if (bRTL) + nMaxLeft = lNullPix + GetRightIndent(); + else + nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()); + + mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset; + nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic); + break; + default: ; //prevent warning + } +} + +bool SvxRuler::StartDrag() +{ + /* + Beginning of a drag operation (SV-handler) evaluates modifier and + calculated values + + [Cross-reference] + + <SvxRuler::EvalModifier()> + <SvxRuler::CalcMinMax()> + <SvxRuler::EndDrag()> + */ + bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected(); + + if(!bValid) + return false; + + mxRulerImpl->lLastLMargin = GetMargin1(); + mxRulerImpl->lLastRMargin = GetMargin2(); + + bool bOk = true; + + lInitialDragPos = GetDragPos(); + switch(GetDragType()) + { + case RulerType::Margin1: // left edge of the surrounding Frame + case RulerType::Margin2: // right edge of the surrounding Frame + if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem)) + { + if (!mxColumnItem) + EvalModifier(); + else + nDragType = SvxRulerDragFlags::OBJECT; + } + else + { + bOk = false; + } + break; + case RulerType::Border: // Table, column (Modifier) + if (mxColumnItem) + { + nDragOffset = 0; + if (!mxColumnItem->IsTable()) + nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos; + EvalModifier(); + } + else + nDragOffset = 0; + break; + case RulerType::Indent: // Paragraph indents (Modifier) + { + if( bContentProtected ) + return false; + if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) { // Left paragraph indent + mpIndents[0] = mpIndents[INDENT_FIRST_LINE]; + EvalModifier(); + } + else + { + nDragType = SvxRulerDragFlags::OBJECT; + } + mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP]; + break; + } + case RulerType::Tab: // Tabs (Modifier) + if( bContentProtected ) + return false; + EvalModifier(); + mpTabs[0] = mpTabs[GetDragAryPos() + 1]; + mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW; + break; + default: + nDragType = SvxRulerDragFlags::NONE; + } + + if(bOk) + CalcMinMax(); + + return bOk; +} + +void SvxRuler::Drag() +{ + /* SV-Draghandler */ + if(IsDragCanceled()) + { + Ruler::Drag(); + return; + } + switch(GetDragType()) { + case RulerType::Margin1: // left edge of the surrounding Frame + DragMargin1(); + mxRulerImpl->lLastLMargin = GetMargin1(); + break; + case RulerType::Margin2: // right edge of the surrounding Frame + DragMargin2(); + mxRulerImpl->lLastRMargin = GetMargin2(); + break; + case RulerType::Indent: // Paragraph indents + DragIndents(); + break; + case RulerType::Border: // Table, columns + if (mxColumnItem) + DragBorders(); + else if (mxObjectItem) + DragObjectBorder(); + break; + case RulerType::Tab: // Tabs + DragTabs(); + break; + default: + break; //prevent warning + } + Ruler::Drag(); +} + +void SvxRuler::EndDrag() +{ + /* + SV-handler; is called when ending the dragging. Triggers the updating of data + on the application, by calling the respective Apply...() methods to send the + data to the application. + */ + const bool bUndo = IsDragCanceled(); + const tools::Long lPos = GetDragPos(); + DrawLine_Impl(lTabPos, 6, bHorz); + lTabPos = -1; + + if(!bUndo) + { + switch(GetDragType()) + { + case RulerType::Margin1: // upper left edge of the surrounding Frame + case RulerType::Margin2: // lower right edge of the surrounding Frame + { + if (!mxColumnItem || !mxColumnItem->IsTable()) + ApplyMargins(); + + if(mxColumnItem && + (mxColumnItem->IsTable() || + (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))) + ApplyBorders(); + + } + break; + case RulerType::Border: // Table, columns + if(lInitialDragPos != lPos || + (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here + { + if (mxColumnItem) + { + ApplyBorders(); + if(bHorz) + UpdateTabs(); + } + else if (mxObjectItem) + ApplyObject(); + } + break; + case RulerType::Indent: // Paragraph indents + if(lInitialDragPos != lPos) + ApplyIndents(); + SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP); + break; + case RulerType::Tab: // Tabs + { + ApplyTabs(); + mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE; + SetTabs(nTabCount, mpTabs.data() + TAB_GAP); + } + break; + default: + break; //prevent warning + } + } + nDragType = SvxRulerDragFlags::NONE; + + mbCoarseSnapping = false; + mbSnapping = true; + + Ruler::EndDrag(); + if(bUndo) + { + for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++) + { + pCtrlItems[i]->ClearCache(); + pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId()); + } + } +} + +void SvxRuler::ExtraDown() +{ + /* Override SV method, sets the new type for the Default tab. */ + + // Switch Tab Type + if(mxTabStopItem && + (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS) + { + ++nDefTabType; + if(RULER_TAB_DEFAULT == nDefTabType) + nDefTabType = RULER_TAB_LEFT; + SetExtraType(RulerExtra::Tab, nDefTabType); + } + Ruler::ExtraDown(); +} + +void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + /* + Report through the bindings that the status update is completed. The ruler + updates its appearance and gets registered again in the bindings. + */ + + // start update + if (bActive && rHint.GetId() == SfxHintId::UpdateDone) + { + Update(); + EndListening(*pBindings); + bValid = true; + bListening = false; + } +} + +void SvxRuler::MenuSelect(std::u16string_view ident) +{ + if (ident.empty()) + return; + /* Handler of the context menus for switching the unit of measurement */ + SetUnit(vcl::EnglishStringToMetric(ident)); +} + +void SvxRuler::TabMenuSelect(std::u16string_view rIdent) +{ + if (rIdent.empty()) + return; + sal_Int32 nId = o3tl::toInt32(rIdent); + /* Handler of the tab menu for setting the type */ + if (mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx) + { + SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx); + aTabStop.GetAdjustment() = ToAttrTab_Impl(nId - 1); + mxTabStopItem->Remove(mxRulerImpl->nIdx); + mxTabStopItem->Insert(aTabStop); + sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL; + pBindings->GetDispatcher()->ExecuteList(nTabStopId, + SfxCallMode::RECORD, { mxTabStopItem.get() }); + UpdateTabs(); + mxRulerImpl->nIdx = 0; + } +} + +const TranslateId RID_SVXSTR_RULER_TAB[] = +{ + RID_SVXSTR_RULER_TAB_LEFT, + RID_SVXSTR_RULER_TAB_RIGHT, + RID_SVXSTR_RULER_TAB_CENTER, + RID_SVXSTR_RULER_TAB_DECIMAL +}; + +void SvxRuler::Command( const CommandEvent& rCommandEvent ) +{ + /* Mouse context menu for switching the unit of measurement */ + if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() ) + { + CancelDrag(); + + tools::Rectangle aRect(rCommandEvent.GetMousePosPixel(), Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/rulermenu.ui")); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu")); + + bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); + if ( !mpTabs.empty() && + RulerType::Tab == + GetRulerType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) && + mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT ) + { + xMenu->clear(); + + const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2); + const Point aPt(aSz.Width() / 2, aSz.Height() / 2); + + for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i ) + { + ScopedVclPtr<VirtualDevice> xDev(pPopupParent->create_virtual_device()); + xDev->SetOutputSize(aSz); + + sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i; + nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT); + + Color aFillColor(xDev->GetSettings().GetStyleSettings().GetShadowColor()); + DrawTab(*xDev, aFillColor, aPt, nStyle); + + OUString sId(OUString::number(i + 1)); + xMenu->insert(-1, sId, SvxResId(RID_SVXSTR_RULER_TAB[i]), + nullptr, xDev.get(), nullptr, TRISTATE_TRUE); + xMenu->set_active(sId, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle); + } + TabMenuSelect(xMenu->popup_at_rect(pPopupParent, aRect)); + } + else + { + FieldUnit eUnit = GetUnit(); + const int nCount = xMenu->n_children(); + + bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC); + for ( sal_uInt16 i = nCount; i; --i ) + { + OUString sIdent = xMenu->get_id(i - 1); + FieldUnit eMenuUnit = vcl::EnglishStringToMetric(sIdent); + xMenu->set_active(sIdent, eMenuUnit == eUnit); + if( bReduceMetric ) + { + if (eMenuUnit == FieldUnit::M || + eMenuUnit == FieldUnit::KM || + eMenuUnit == FieldUnit::FOOT || + eMenuUnit == FieldUnit::MILE) + { + xMenu->remove(sIdent); + } + else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz ) + { + xMenu->remove(sIdent); + } + else if (( eMenuUnit == FieldUnit::LINE ) && bHorz ) + { + xMenu->remove(sIdent); + } + } + } + MenuSelect(xMenu->popup_at_rect(pPopupParent, aRect)); + } + } + else + { + Ruler::Command( rCommandEvent ); + } +} + +sal_uInt16 SvxRuler::GetActRightColumn( + bool bForceDontConsiderHidden, + sal_uInt16 nAct ) const +{ + if( nAct == USHRT_MAX ) + nAct = mxColumnItem->GetActColumn(); + else + nAct++; //To be able to pass on the ActDrag + + bool bConsiderHidden = !bForceDontConsiderHidden && + !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY); + + while( nAct < mxColumnItem->Count() - 1 ) + { + if (mxColumnItem->At(nAct).bVisible || bConsiderHidden) + return nAct; + else + nAct++; + } + return USHRT_MAX; +} + +sal_uInt16 SvxRuler::GetActLeftColumn( + bool bForceDontConsiderHidden, + sal_uInt16 nAct ) const +{ + if(nAct == USHRT_MAX) + nAct = mxColumnItem->GetActColumn(); + + sal_uInt16 nLeftOffset = 1; + + bool bConsiderHidden = !bForceDontConsiderHidden && + !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY); + + while(nAct >= nLeftOffset) + { + if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden) + return nAct - nLeftOffset; + else + nLeftOffset++; + } + return USHRT_MAX; +} + +bool SvxRuler::IsActLastColumn( + bool bForceDontConsiderHidden, + sal_uInt16 nAct) const +{ + return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX; +} + +bool SvxRuler::IsActFirstColumn( + bool bForceDontConsiderHidden, + sal_uInt16 nAct) const +{ + return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX; +} + +tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const +{ + + if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)) + { + // Remove the minimum width for all affected columns + // starting from the right edge + tools::Long _nMaxRight = GetMargin2() - GetMargin1(); + + tools::Long lFences = 0; + tools::Long lMinSpace = USHRT_MAX; + tools::Long lOldPos; + tools::Long lColumns = 0; + + sal_uInt16 nStart; + if(!mxColumnItem->IsTable()) + { + if(nCol == USHRT_MAX) + { + lOldPos = GetMargin1(); + nStart = 0; + } + else + { + lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth; + nStart = nCol + 1; + lFences = mpBorders[nCol].nWidth; + } + + for(size_t i = nStart; i < mpBorders.size() - 1; ++i) + { + tools::Long lWidth = mpBorders[i].nPos - lOldPos; + lColumns += lWidth; + if(lWidth < lMinSpace) + lMinSpace = lWidth; + lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth; + lFences += mpBorders[i].nWidth; + } + tools::Long lWidth = GetMargin2() - lOldPos; + lColumns += lWidth; + if(lWidth < lMinSpace) + lMinSpace = lWidth; + } + else + { + sal_uInt16 nActCol; + if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin + { + lOldPos = GetMargin1(); + } + else + { + lOldPos = mpBorders[nCol].nPos; + } + lColumns = GetMargin2()-lOldPos; + nActCol = nCol; + lFences = 0; + while(nActCol < mpBorders.size() || nActCol == USHRT_MAX) + { + sal_uInt16 nRight; + if(nActCol == USHRT_MAX) + { + nRight = 0; + while (!(*mxColumnItem)[nRight].bVisible) + { + nRight++; + } + } + else + { + nRight = GetActRightColumn(false, nActCol); + } + + tools::Long lWidth; + if(nRight != USHRT_MAX) + { + lWidth = mpBorders[nRight].nPos - lOldPos; + lOldPos = mpBorders[nRight].nPos; + } + else + { + lWidth=GetMargin2() - lOldPos; + } + nActCol = nRight; + if(lWidth < lMinSpace) + lMinSpace = lWidth; + if(nActCol == USHRT_MAX) + break; + } + } + + _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns); + return _nMaxRight; + } + else + { + if(mxColumnItem->IsTable()) + { + sal_uInt16 nVisCols = 0; + for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();) + { + if ((*mxColumnItem)[i].bVisible) + nVisCols++; + i = GetActRightColumn(false, i); + } + return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame; + } + else + { + tools::Long lWidth = 0; + for(size_t i = nCol; i < mpBorders.size() - 1; i++) + { + lWidth += glMinFrame + mpBorders[i].nWidth; + } + return GetMargin2() - GetMargin1() - lWidth; + } + } +} + +// Tab stops relative to indent (#i24363#) +void SvxRuler::SetTabsRelativeToIndent( bool bRel ) +{ + mxRulerImpl->bIsTabsRelativeToIndent = bRel; +} + +void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue) +{ + if (diffValue == 0) + return; + + if (type == RulerChangeType::MARGIN1) + AdjustMargin1(diffValue); + else if (type == RulerChangeType::MARGIN2) + SetMargin2( GetMargin2() - diffValue); + ApplyMargins(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |