Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/svx/source/dialog/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 127 kB image not shown  

Quelle  svxruler.cxx   Sprache: C

 
/* -*- 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 <sfx2/viewsh.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 <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <tools/json_writer.hxx>
#include <tools/UnitConversion.hxx>
#include <comphelper/lok.hxx>
#include "rlrcitem.hxx"
#include <com/sun/star/frame/XFrame.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <sfx2/viewfrm.hxx>
#include <memory>

using namespace css;

#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.reset();
    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(u""_ustr);
        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->ResolveTextLeft({});
            else if (nIndex == INDENT_FIRST_LINE)
                nIndentValue = mxParaItem->ResolveTextFirstLineOffset({});
            else if (nIndex == INDENT_RIGHT_MARGIN)
                nIndentValue = mxParaItem->ResolveRight({});

            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(u""_ustr);
            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->ResolveTextLeft({}) + lAppNullOffset;
            leftFirstLine = leftMargin - mxParaItem->ResolveTextFirstLineOffset({});
            rightMargin = nLeftFrameMargin + mxParaItem->ResolveRight({}) + lAppNullOffset;
        }
        else
        {
            leftMargin = nLeftFrameMargin + mxParaItem->ResolveTextLeft({}) + lAppNullOffset;
            leftFirstLine = leftMargin + mxParaItem->ResolveTextFirstLineOffset({});
            rightMargin = nRightFrameMargin - mxParaItem->ResolveRight({}) + 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::Defaultreturn 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->ResolveTextLeft({});

        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->ResolveRight({}));

        tools::Long lCurrentDefTabDist = lDefTabDist;
        if(mxTabStopItem->GetDefaultDistance())
            lCurrentDefTabDist = mxTabStopItem->GetDefaultDistance();
        tools::Long nDefTabDist = ConvertHPosPixel(lCurrentDefTabDist);

        const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent || nDefTabDist == 0
                    ? 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::CreateJsonNotification(tools::JsonWriter& rJsonWriter)
{
    tools::Long nMargin1 = 0;
    tools::Long nMargin2 = 0;
    tools::Long nNullOffset = 0;
    tools::Long nPageOffset = 0;
    tools::Long nPageWidthHeight = 0;

    bool bWriter = false;

    // Determine if we are a Ruler for Writer or not
    if (SfxViewFrame* pFrame = SfxViewFrame::Current())
    {
        uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame().GetFrameInterface();
        uno::Reference<frame::XModel> xModel = xFrame->getController()->getModel();
        uno::Reference<lang::XServiceInfo> xSI(xModel, uno::UNO_QUERY);
        if (xSI.is())
        {
            bWriter = xSI->supportsService("com.sun.star.text.TextDocument")
            || xSI->supportsService("com.sun.star.text.WebDocument")
                || xSI->supportsService("com.sun.star.text.GlobalDocument");
        }
    }

    if (bWriter)
    {
        // In Writer the ruler values need to be converted first from pixel to twips (default logical unit) and then to 100thmm
        nMargin1 = convertTwipToMm100(ConvertPosLogic(GetMargin1()));
        nMargin2 = convertTwipToMm100(ConvertPosLogic(GetMargin2()));
        nNullOffset = convertTwipToMm100(ConvertPosLogic(GetNullOffset()));
        nPageOffset = convertTwipToMm100(ConvertPosLogic(GetPageOffset()));
        nPageWidthHeight = convertTwipToMm100(GetPageWidth());
    }
    else
    {
        // Only convert from pixel to default logical unit, which is 100thmm for Impress
        nMargin1 = ConvertPosLogic(GetMargin1());
        nMargin2 = ConvertPosLogic(GetMargin2());
        nPageOffset = ConvertPosLogic(GetPageOffset());

        // In LOKit API we expect the ruler 0,0 coordinate is where the document starts.
        // In Impress and Draw the ruler 0,0 is where the canvas starts, not where the document starts.
        // The margin to the document is 1 document width (on the left and right) and 0.5 document height
        // (on the top and bottom).
        // So the canvas width = 3 * document width, canvas height = 2 * document height
        if (isHorizontal())
        {
            nPageWidthHeight = GetPageWidth() / 3;
            nNullOffset = ConvertPosLogic(GetNullOffset()) - nPageWidthHeight;
        }
        else
        {
            nPageWidthHeight = GetPageWidth() / 2;
            nNullOffset = ConvertPosLogic(GetNullOffset()) - (nPageWidthHeight / 2);
        }
    }

    rJsonWriter.put("margin1", nMargin1);
    rJsonWriter.put("margin2", nMargin2);
    rJsonWriter.put("leftOffset", nNullOffset);
    rJsonWriter.put("pageOffset", nPageOffset);
    rJsonWriter.put("pageWidth", nPageWidthHeight);

    {
        auto tabsNode = rJsonWriter.startNode("tabs");

        // The RulerTab array elements that GetTabs() returns have their nPos field in twips. So these
        // too are actual mm100.
        for (auto const& tab : GetTabs())
        {
            auto tabNode = rJsonWriter.startNode("");
            rJsonWriter.put("position", convertTwipToMm100(tab.nPos));
            rJsonWriter.put("style", tab.nStyle);
        }
    }

    RulerUnitData aUnitData = GetCurrentRulerUnit();
    rJsonWriter.put("unit", aUnitData.aUnitStr);
}

void SvxRuler::NotifyKit()
{
    if (!comphelper::LibreOfficeKit::isActive())
        return;
    SfxViewShell* pViewShell = SfxViewShell::Current();
    if (!pViewShell)
        return;

    tools::JsonWriter aJsonWriter;
    CreateJsonNotification(aJsonWriter);
    OString pJsonData = aJsonWriter.finishAndGetAsOString();
    LibreOfficeKitCallbackType eType = isHorizontal() ? LOK_CALLBACK_RULER_UPDATE : LOK_CALLBACK_VERTICAL_RULER_UPDATE;
    pViewShell->libreOfficeKitViewCallback(eType, pJsonData);
}

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();

    NotifyKit();
}

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->ResolveRight({})
                      : 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->ResolveLeft({});

    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->ResolveRight({});

    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(truefalse);
    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
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=95 G=93

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.