/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rlrcitem.hxx" #include #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 pPercBuf; std::unique_ptr pBlockBuf; sal_uInt16 nPercSize; long nTotalDist; long lOldWinPos; long lMaxLeftLogic; long lMaxRightLogic; long lLastLMargin; long lLastRMargin; std::unique_ptr aProtectItem; std::unique_ptr pTextRTLItem; sal_uInt16 nControlerItems; 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(SID_RULER_PROTECT)), nControlerItems(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 static constexpr 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->nControlerItems=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(); } long SvxRuler::MakePositionSticky(long aPosition, long aPointOfReference, bool aSnapToFrameMargin) const { long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference); long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin()); long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin()); double aTick = GetCurrentRulerUnit().nTick1; if (mbCoarseSnapping) aTick = GetCurrentRulerUnit().nTick2; 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 long aTranslatedPosition = aPosition - aPointOfReferencePixel; // Convert position to current selected map mode 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; } long SvxRuler::ConvertHPosPixel(long nVal) const { return pEditWin->LogicToPixel(Size(nVal, 0)).Width(); } long SvxRuler::ConvertVPosPixel(long nVal) const { return pEditWin->LogicToPixel(Size(0, nVal)).Height(); } long SvxRuler::ConvertHSizePixel(long nVal) const { return pEditWin->LogicToPixel(Size(nVal, 0)).Width(); } long SvxRuler::ConvertVSizePixel(long nVal) const { return pEditWin->LogicToPixel(Size(0, nVal)).Height(); } long SvxRuler::ConvertPosPixel(long nVal) const { return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal); } long SvxRuler::ConvertSizePixel(long nVal) const { return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal); } inline long SvxRuler::ConvertHPosLogic(long nVal) const { return pEditWin->PixelToLogic(Size(nVal, 0)).Width(); } inline long SvxRuler::ConvertVPosLogic(long nVal) const { return pEditWin->PixelToLogic(Size(0, nVal)).Height(); } inline long SvxRuler::ConvertHSizeLogic(long nVal) const { return pEditWin->PixelToLogic(Size(nVal, 0)).Width(); } inline long SvxRuler::ConvertVSizeLogic(long nVal) const { return pEditWin->PixelToLogic(Size(0, nVal)).Height(); } inline long SvxRuler::ConvertPosLogic(long nVal) const { return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal); } inline long SvxRuler::ConvertSizeLogic(long nVal) const { return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal); } long SvxRuler::PixelHAdjust(long nVal, long nValOld) const { if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld)) return nVal; else return nValOld; } long SvxRuler::PixelVAdjust(long nVal, long nValOld) const { if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld)) return nVal; else return nValOld; } long SvxRuler::PixelAdjust(long nVal, 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 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); } long lRight = 0; // evaluate the table right edge of the table if(mxColumnItem && mxColumnItem->IsTable()) lRight = mxColumnItem->GetRight(); else lRight = mxLRSpaceItem->GetRight(); long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset; long aWidthPixel = ConvertHPosPixel(aWidth); SetMargin2(aWidthPixel, nMarginStyle); } else if(mxULSpaceItem && mxPagePosItem) { // relative the upper edge of the surrounding frame const 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); } long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower(); long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset; long nMargin2Pixel = ConvertVPosPixel(nMargin2); SetMargin2(nMargin2Pixel, nMarginStyle); } else { // turns off the view SetMargin1(); SetMargin2(); } if (mxColumnItem) { mxRulerImpl->nColLeftPix = static_cast(ConvertSizePixel(mxColumnItem->GetLeft())); mxRulerImpl->nColRightPix = static_cast(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; long nIndex = aSelection.nAryPos + INDENT_GAP; 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: { 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: { 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) { 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 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 long nLeftFrameMargin = GetLeftFrameMargin(); long nRightFrameMargin = GetRightFrameMargin(); SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin)); SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin)); long leftMargin; long leftFirstLine; 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::UpdateParaBorder() { /* Border distance */ if(bActive) { 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(); } 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(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; 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 long nLeftFrameMargin = GetLeftFrameMargin(); const long nRightFrameMargin = GetRightFrameMargin(); //#i24363# tab stops relative to indent const long nParaItemTxtLeft = mxParaItem->GetTextLeft(); const long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft; const long lRightMargin = nRightFrameMargin - nParaItemTxtLeft; const long lLastTab = mxTabStopItem->Count() ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos()) : 0; const long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab; const long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight()); long nDefTabDist = ConvertHPosPixel(lDefTabDist); if( !nDefTabDist ) nDefTabDist = 1; const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent ? 0 : static_cast( (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 long lParaIndentPix = ConvertSizePixel(lParaIndent); long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin) + lAppNullOffset; if (bRTL) { lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic; } long lLastTabOffsetLogic = 0; for(j = 0; j < mxTabStopItem->Count(); ++j) { const SvxTabStop* pTab = &mxTabStopItem->At(j); lLastTabOffsetLogic = pTab->GetTabPos(); 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 % lDefTabDist; // fill the rest with default Tabs for (j = 0; j < nDefTabBuf; ++j) { //simply add the default distance to the last position lLastTabOffsetLogic += lDefTabDist; 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) { 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(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(); } long SvxRuler::GetPageWidth() const { if (!mxPagePosItem) return 0; return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight(); } inline long SvxRuler::GetFrameLeft() const { /* Get Left margin in Pixels */ return bAppSetNullOffset ? GetMargin1() + ConvertSizePixel(lLogicNullOffset) : Ruler::GetNullOffset(); } long SvxRuler::GetFirstLineIndent() const { /* Get First-line indent in pixels */ return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1(); } long SvxRuler::GetLeftIndent() const { /* Get Left paragraph margin in Pixels */ return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1(); } long SvxRuler::GetRightIndent() const { /* Get Right paragraph margin in Pixels */ return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2(); } 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. 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!"); long nLeft = 0; if (mxColumnItem && mxColumnItem->Count() && mxColumnItem->IsConsistent()) { nLeft = mxColumnItem->GetActiveColumnDescription().nStart; } return nLeft; } inline 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 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; } long SvxRuler::GetRightFrameMargin() const { /* Get right frame margin (in logical units) */ if (mxColumnItem) { if (!IsActLastColumn(true)) { return mxColumnItem->At(GetActRightColumn(true)).nEnd; } } 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) 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() ) 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 long lNullPix = Ruler::GetNullOffset(); 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 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 */ 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(long lInputDiff) { const long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset(); const long lDragPos = lInputDiff; bool bProtectColumns = mxRulerImpl->aProtectItem->IsSizeProtected() || mxRulerImpl->aProtectItem->IsPosProtected(); const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable; if(!bAppSetNullOffset) { 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 { 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 */ long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG); aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false); 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 */ 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 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(long& lTabPosition, int nNew, bool bHorizontal) { /* Output routine for the ledger line when moving tabs, tables and other columns */ if(bHorizontal) { const long nHeight = pEditWin->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 ) { 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 long nWidth = pEditWin->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) { 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 */ long aDragPosition = GetCorrectedDragPos(true, false); aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin()); sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP; 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; 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;inControlerItems;i++) pCtrlItems[i]->ReBind(); else for(sal_uInt16 j=0;jnControlerItems;j++) pCtrlItems[j]->UnBind(); pBindings->LeaveRegistrations(); } bActive = bOn; } void SvxRuler::UpdateParaContents_Impl( 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(); long lDiff = 0; // the drag position has to be corrected to be able to prevent borders from passing each other 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) { long nRight = GetMargin2() - glMinFrame; // Right limiters for(int i = mpBorders.size() - 2; i >= nIndex; --i) { 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; 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) { 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 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 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 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; } long nRight; if(mxRulerImpl->lMaxRightLogic != -1 && nMaxRight == GetMargin2() + Ruler::GetNullOffset()) { nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic; } else { nRight = std::max(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 long lOldNull = lLogicNullOffset; lLogicNullOffset = ConvertVPosLogic(GetFrameLeft()) - lAppNullOffset; mxULSpaceItem->SetUpper( PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper())); if(bAppSetNullOffset) { lAppNullOffset += lLogicNullOffset - lOldNull; } mxULSpaceItem->SetLower( PixelVAdjust( std::max(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(); } long SvxRuler::RoundToCurrentMapMode(long lValue) const { RulerUnitData aUnitData = GetCurrentRulerUnit(); double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1; long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width(); lNewValue = (rtl::math::round(lNewValue / static_cast(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. */ long nLeftFrameMargin = GetLeftFrameMargin(); bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); long nNewTxtLeft; long nNewFirstLineOffset; long nNewRight; long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos); long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos); long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos); if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true)))) { if(bRTL) { long nRightColumn = GetActRightColumn(true); long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos); nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset; } else { long nLeftColumn = GetActLeftColumn(true); long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth); nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset; } } else { if(bRTL) { long nRightBorder = ConvertPosLogic(GetMargin2()); nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset; } else { 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) { long nLeftColumn = GetActLeftColumn(true); long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth); nNewRight = nRightMargin - nLeftBorder - lAppNullOffset; } else { long nRightColumn = GetActRightColumn(true); long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos); nNewRight = nRightBorder - nRightMargin - lAppNullOffset; } } else { if(bRTL) { long nLeftBorder = ConvertPosLogic(GetMargin1()); nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset; } else { 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(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 long nTmpLeftIndentLogic = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin()); if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem) { nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetLeft(); } aTabStop.GetTabPos() = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic; } else { if(bRTL) { //#i24363# tab stops relative to indent const long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ? GetLeftIndent() : ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ); long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos); aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos()); } else { //#i24363# tab stops relative to indent const long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ? GetLeftIndent() : ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ); 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()) { long lValue = GetFrameLeft(); if(lValue != mxRulerImpl->nColLeftPix) { long nLeft = PixelHAdjust( ConvertHPosLogic(lValue) - lAppNullOffset, mxColumnItem->GetLeft()); mxColumnItem->SetLeft(nLeft); } lValue = GetMargin2(); if(lValue != mxRulerImpl->nColRightPix) { long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight(); long nRight = PixelHAdjust( nWidthOrHeight - mxColumnItem->GetLeft() - ConvertHPosLogic(lValue) - lAppNullOffset, mxColumnItem->GetRight() ); mxColumnItem->SetRight(nRight); } } for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i) { long& nEnd = mxColumnItem->At(i).nEnd; nEnd = PixelHAdjust( ConvertPosLogic(mpBorders[i].nPos), mxColumnItem->At(i).nEnd); 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 long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0; long nStartX = PixelAdjust( ConvertPosLogic(mpObjectBorders[0].nPos) + nMargin - lAppNullOffset, mxObjectItem->GetStartX()); mxObjectItem->SetStartX(nStartX); long nEndX = PixelAdjust( ConvertPosLogic(mpObjectBorders[1].nPos) + nMargin - lAppNullOffset, mxObjectItem->GetEndX()); mxObjectItem->SetEndX(nEndX); nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0; long nStartY = PixelAdjust( ConvertPosLogic(mpObjectBorders[2].nPos) + nMargin - lAppNullOffset, mxObjectItem->GetStartY()); mxObjectItem->SetStartY(nStartY); 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()); long lPos; long lWidth=0; sal_uInt16 nStart; sal_uInt16 nIdx=GetDragAryPos(); long lActWidth=0; long lActBorderSum; 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((lActWidth * 1000) / mxRulerImpl->nTotalDist); mxRulerImpl->pBlockBuf[i] = static_cast(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((lActWidth * 1000) / mxRulerImpl->nTotalDist); mxRulerImpl->pBlockBuf[i] = static_cast(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 long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos; mxRulerImpl->pPercBuf[i] = static_cast((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) { bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected(); if( bContentProtected ) return; const long lPos = GetClickPos(); if((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) || (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())) { //convert position in left-to-right text 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 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()) { 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 ) { 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(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 ) { 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: { 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] */ 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 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->nControlerItems; 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; } } IMPL_LINK( SvxRuler, MenuSelect, Menu *, pMenu, bool ) { /* Handler of the context menus for switching the unit of measurement */ SetUnit(vcl::StringToMetric(OUString::fromUtf8(pMenu->GetCurItemIdent()))); return false; } IMPL_LINK( SvxRuler, TabMenuSelect, Menu *, pMenu, bool ) { /* 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(pMenu->GetCurItemId() - 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; } return false; } static const char* 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(); bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue(); if ( !mpTabs.empty() && RulerType::Tab == GetType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) && mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT ) { ScopedVclPtrInstance aMenu; aMenu->SetSelectHdl(LINK(this, SvxRuler, TabMenuSelect)); ScopedVclPtrInstance< VirtualDevice > pDev; const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2); pDev->SetOutputSize(aSz); pDev->SetBackground(Wallpaper(COL_WHITE)); Color aFillColor(pDev->GetSettings().GetStyleSettings().GetShadowColor()); const Point aPt(aSz.Width() / 2, aSz.Height() / 2); for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i ) { sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i; nStyle |= static_cast(bHorz ? WB_HORZ : WB_VERT); DrawTab(*pDev, aFillColor, aPt, nStyle); BitmapEx aItemBitmapEx(pDev->GetBitmapEx(Point(), aSz)); aItemBitmapEx.Replace(COL_WHITE, COL_TRANSPARENT); aMenu->InsertItem(i + 1, SvxResId(RID_SVXSTR_RULER_TAB[i]), Image(aItemBitmapEx)); aMenu->CheckItem(i + 1, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle); pDev->SetOutputSize(aSz); // delete device } aMenu->Execute( this, rCommandEvent.GetMousePosPixel() ); } else { VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/rulermenu.ui", ""); VclPtr aMenu(aBuilder.get_menu("menu")); aMenu->SetSelectHdl(LINK(this, SvxRuler, MenuSelect)); FieldUnit eUnit = GetUnit(); const sal_uInt16 nCount = aMenu->GetItemCount(); bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC); for ( sal_uInt16 i = nCount; i; --i ) { sal_uInt16 nId = aMenu->GetItemId(i - 1); OString sIdent = aMenu->GetItemIdent(nId); FieldUnit eMenuUnit = vcl::StringToMetric(OUString::fromUtf8(sIdent)); aMenu->CheckItem(nId, eMenuUnit == eUnit); if( bReduceMetric ) { if (eMenuUnit == FieldUnit::M || eMenuUnit == FieldUnit::KM || eMenuUnit == FieldUnit::FOOT || eMenuUnit == FieldUnit::MILE) { aMenu->RemoveItem(i - 1); } else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz ) { aMenu->RemoveItem(i - 1); } else if (( eMenuUnit == FieldUnit::LINE ) && bHorz ) { aMenu->RemoveItem(i - 1); } } } aMenu->Execute( this, rCommandEvent.GetMousePosPixel() ); } } 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; } 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 long _nMaxRight = GetMargin2() - GetMargin1(); long lFences = 0; long lMinSpace = USHRT_MAX; long lOldPos; 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) { long lWidth = mpBorders[i].nPos - lOldPos; lColumns += lWidth; if(lWidth < lMinSpace) lMinSpace = lWidth; lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth; lFences += mpBorders[i].nWidth; } 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); } 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(lFences + glMinFrame / static_cast(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 { 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, long diffValue) { if (diffValue == 0) return; if (type == RulerChangeType::MARGIN1) AdjustMargin1(diffValue); else if (type == RulerChangeType::MARGIN2) SetMargin2( GetMargin2() - diffValue); ApplyMargins(); }