Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  splitwin.cxx

  Sprache: C
 

/* -*- 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 <string.h>

#include <o3tl/safeint.hxx>
#include <sal/log.hxx>

#include <vcl/event.hxx>
#include <vcl/wall.hxx>
#include <vcl/help.hxx>
#include <vcl/splitwin.hxx>
#include <vcl/settings.hxx>
#include <vcl/ptrstyle.hxx>

#include <svdata.hxx>
#include <strings.hrc>


#define SPLITWIN_SPLITSIZEEX            4
#define SPLITWIN_SPLITSIZEAUTOHIDE      72
#define SPLITWIN_SPLITSIZEFADE          72

#define SPLIT_HORZ              (sal_uInt16(0x0001))
#define SPLIT_VERT              (sal_uInt16(0x0002))
#define SPLIT_WINDOW            (sal_uInt16(0x0004))
#define SPLIT_NOSPLIT           (sal_uInt16(0x8000))

namespace {

class ImplSplitItem
{
public:
    ImplSplitItem();

    tools::Long                mnSize;
    tools::Long                mnPixSize;
    tools::Long                mnLeft;
    tools::Long                mnTop;
    tools::Long                mnWidth;
    tools::Long                mnHeight;
    tools::Long                mnSplitPos;
    tools::Long                mnSplitSize;
    tools::Long                mnOldSplitPos;
    tools::Long                mnOldSplitSize;
    tools::Long                mnOldWidth;
    tools::Long                mnOldHeight;
    std::unique_ptr<ImplSplitSet> mpSet;
    VclPtr<vcl::Window> mpWindow;
    VclPtr<vcl::Window> mpOrgParent;
    sal_uInt16          mnId;
    SplitWindowItemFlags mnBits;
    bool                mbFixed;
    bool                mbSubSize;
    /// Minimal width or height of the item.  -1 means no restriction.
    tools::Long                mnMinSize;
    /// Maximal width or height of the item.  -1 means no restriction.
    tools::Long                mnMaxSize;
};

}

class ImplSplitSet
{
public:
    ImplSplitSet();

    std::vector< ImplSplitItem > mvItems;
    tools::Long                mnLastSize;
    tools::Long                mnSplitSize;
    sal_uInt16          mnId;
    bool                mbCalcPix;
};

ImplSplitItem::ImplSplitItem()
    : mnSize(0)
    , mnPixSize(0)
    , mnLeft(0)
    , mnTop(0)
    , mnWidth(0)
    , mnHeight(0)
    , mnSplitPos(0)
    , mnSplitSize(0)
    , mnOldSplitPos(0)
    , mnOldSplitSize(0)
    , mnOldWidth(0)
    , mnOldHeight(0)
    , mnId(0)
    , mnBits(SplitWindowItemFlags::NONE)
    , mbFixed(false)
    , mbSubSize(false)
    , mnMinSize(-1)
    , mnMaxSize(-1)
{
}

ImplSplitSet::ImplSplitSet() :
    mnLastSize( 0 ),
    mnSplitSize( SPLITWIN_SPLITSIZE ),
    mnId( 0 ),
    mbCalcPix( true )
{
}

/** Check whether the given size is inside the valid range defined by
    [rItem.mnMinSize,rItem.mnMaxSize].  When it is not inside it then return
    the upper or lower bound, respectively. Otherwise return the given size
    unmodified.
    Note that either mnMinSize and/or mnMaxSize can be -1 in which case the
    size has not lower or upper bound.
*/

namespace {
    tools::Long ValidateSize (const tools::Long nSize, const ImplSplitItem & rItem)
    {
        if (rItem.mnMinSize>=0 && nSize<rItem.mnMinSize)
            return rItem.mnMinSize;
        else if (rItem.mnMaxSize>0 && nSize>rItem.mnMaxSize)
            return rItem.mnMaxSize;
        else
            return nSize;
    }
}

static void ImplCalcBorder( WindowAlign eAlign,
                            tools::Long& rLeft, tools::Long& rTop,
                            tools::Long& rRight, tools::Long& rBottom )
{
    switch ( eAlign )
    {
    case WindowAlign::Top:
        rLeft   = 2;
        rTop    = 2;
        rRight  = 2;
        rBottom = 0;
        break;
    case WindowAlign::Left:
        rLeft   = 0;
        rTop    = 2;
        rRight  = 2;
        rBottom = 2;
        break;
    case WindowAlign::Bottom:
        rLeft   = 2;
        rTop    = 0;
        rRight  = 2;
        rBottom = 2;
        break;
    default:
        rLeft   = 0;
        rTop    = 2;
        rRight  = 2;
        rBottom = 2;
        break;
    }
}

void SplitWindow::ImplDrawBorder(vcl::RenderContext& rRenderContext)
{
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
    tools::Long nDX = mnDX;
    tools::Long nDY = mnDY;

    switch (meAlign)
    {
    case WindowAlign::Bottom:
        break;
    case WindowAlign::Top:
        break;
    case WindowAlign::Left:
        break;
    default:
        rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
        rRenderContext.DrawLine(Point(0, 0), Point( 0, nDY));
        rRenderContext.DrawLine(Point(0, nDY), Point(nDX, nDY));
    }
}

void SplitWindow::ImplDrawBorderLine(vcl::RenderContext& rRenderContext)
{
    if (!mbFadeOut)
        return;

    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
    tools::Long nDX = mnDX;
    tools::Long  nDY = mnDY;

    switch (meAlign)
    {
    case WindowAlign::Left:
        rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
        rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, nDY-2 ) );

        rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
        rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN, nDY-3 ) );
        break;
    case WindowAlign::Right:
        break;
    case WindowAlign::Top:
        rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
        rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN-1 ) );

        rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
        rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN ) );
        break;
    case WindowAlign::Bottom:
        rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
        rRenderContext.DrawLine( Point( 0, 5 ), Point( nDX-1, 5 ) );

        rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
        rRenderContext.DrawLine( Point( 0, SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, SPLITWIN_SPLITSIZEEXLN ) );
        break;
    }
}

static ImplSplitSet* ImplFindSet( ImplSplitSet* pSet, sal_uInt16 nId )
{
    if ( pSet->mnId == nId )
        return pSet;

    std::vector< ImplSplitItem >&     rItems = pSet->mvItems;

    for ( const auto& rItem : rItems )
    {
        if ( rItem.mnId == nId )
            return rItem.mpSet.get();
    }

    for ( auto& rItem : rItems )
    {
        if ( rItem.mpSet )
        {
            ImplSplitSet* pFindSet = ImplFindSet( rItem.mpSet.get(), nId );
            if ( pFindSet )
                return pFindSet;
        }
    }

    return nullptr;
}

static ImplSplitSet* ImplFindItem( ImplSplitSet* pSet, sal_uInt16 nId, sal_uInt16& rPos )
{
    size_t              nItems = pSet->mvItems.size();
    std::vector< ImplSplitItem >&     rItems = pSet->mvItems;

    for ( size_t i = 0; i < nItems; i++ )
    {
        if ( rItems[i].mnId == nId )
        {
            rPos = i;
            return pSet;
        }
    }

    for ( auto& rItem : rItems )
    {
        if ( rItem.mpSet )
        {
            ImplSplitSet* pFindSet = ImplFindItem( rItem.mpSet.get(), nId, rPos );
            if ( pFindSet )
                return pFindSet;
        }
    }

    return nullptr;
}

static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, vcl::Window* pWindow )
{
    std::vector< ImplSplitItem >&     rItems = pSet->mvItems;

    for ( auto& rItem : rItems )
    {
        if ( rItem.mpWindow == pWindow )
            return rItem.mnId;
        else
        {
            if ( rItem.mpSet )
            {
                sal_uInt16 nId = ImplFindItem( rItem.mpSet.get(), pWindow );
                if ( nId )
                    return nId;
            }
        }
    }

    return 0;
}

static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, const Point& rPos,
                            bool bRows, bool bDown = true )
{
    std::vector< ImplSplitItem >&     rItems = pSet->mvItems;

    for ( auto& rItem : rItems )
    {
        if ( rItem.mnWidth && rItem.mnHeight )
        {
            Point       aPoint( rItem.mnLeft, rItem.mnTop );
            Size        aSize( rItem.mnWidth, rItem.mnHeight );
            tools::Rectangle   aRect( aPoint, aSize );
            if ( bRows )
            {
                if ( bDown )
                    aRect.AdjustBottom(pSet->mnSplitSize );
                else
                    aRect.AdjustTop( -(pSet->mnSplitSize) );
            }
            else
            {
                if ( bDown )
                    aRect.AdjustRight(pSet->mnSplitSize );
                else
                    aRect.AdjustLeft( -(pSet->mnSplitSize) );
            }

            if ( aRect.Contains( rPos ) )
            {
                if ( rItem.mpSet && !rItem.mpSet->mvItems.empty() )
                {
                    return ImplFindItem( rItem.mpSet.get(), rPos,
                                        !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
                }
                else
                    return rItem.mnId;
            }
        }
    }

    return 0;
}

static void ImplCalcSet( ImplSplitSet* pSet,
                         tools::Long nSetLeft, tools::Long nSetTop,
                         tools::Long nSetWidth, tools::Long nSetHeight,
                         bool bRows, bool bDown = true )
{
    if ( pSet->mvItems.empty() )
        return;

    sal_uInt16          nMins;
    sal_uInt16          nCalcItems;
    size_t              nItems = pSet->mvItems.size();
    sal_uInt16          nAbsItems;
    tools::Long                nCalcSize;
    tools::Long                nPos;
    tools::Long                nMaxPos;
    std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
    bool                bEmpty;

    // calculate sizes
    if ( bRows )
        nCalcSize = nSetHeight;
    else
        nCalcSize = nSetWidth;
    nCalcSize -= (rItems.size()-1)*pSet->mnSplitSize;
    if ( pSet->mbCalcPix || (pSet->mnLastSize != nCalcSize) )
    {
        tools::Long nPercentFactor = 10;
        tools::Long nRelCount      = 0;
        tools::Long nPercent       = 0;
        tools::Long nRelPercent    = 0;
        tools::Long nAbsSize       = 0;
        tools::Long nCurSize       = 0;
        for ( const auto& rItem : rItems )
        {
            if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
                nRelCount += rItem.mnSize;
            else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
                nPercent += rItem.mnSize;
            else
                nAbsSize += rItem.mnSize;
        }
        // map relative values to percentages (percentage here one tenth of a percent)
        nPercent *= nPercentFactor;
        if ( nRelCount )
        {
            tools::Long nRelPercentBase = 1000;
            while ( (nRelCount > nRelPercentBase) && (nPercentFactor < 100000) )
            {
                nRelPercentBase *= 10;
                nPercentFactor *= 10;
            }
            if ( nPercent < nRelPercentBase )
            {
                nRelPercent = (nRelPercentBase-nPercent)/nRelCount;
                nPercent += nRelPercent*nRelCount;
            }
            else
                nRelPercent = 0;
        }
        if ( !nPercent )
            nPercent = 1;
        tools::Long nSizeDelta = nCalcSize-nAbsSize;
        for ( auto& rItem : rItems )
        {
            if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
            {
                if ( nSizeDelta <= 0 )
                    rItem.mnPixSize = 0;
                else
                    rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nRelPercent)/nPercent;
            }
            else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
            {
                if ( nSizeDelta <= 0 )
                    rItem.mnPixSize = 0;
                else
                    rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nPercentFactor)/nPercent;
            }
            else
                rItem.mnPixSize = rItem.mnSize;
            nCurSize += rItem.mnPixSize;
        }

        pSet->mbCalcPix  = false;
        pSet->mnLastSize = nCalcSize;

        // adapt window
        nSizeDelta  = nCalcSize-nCurSize;
        if ( nSizeDelta )
        {
            nAbsItems       = 0;
            tools::Long nSizeWinSize    = 0;

            // first resize absolute items relative
            for ( const auto& rItem : rItems )
            {
                if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
                {
                    nAbsItems++;
                    nSizeWinSize += rItem.mnPixSize;
                }
            }
            // do not compensate rounding errors here
            if ( (nAbsItems < o3tl::make_unsigned(std::abs( nSizeDelta ))) && nSizeWinSize )
            {
                tools::Long nNewSizeWinSize = 0;

                for ( auto& rItem : rItems )
                {
                    if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
                    {
                        rItem.mnPixSize += (nSizeDelta*rItem.mnPixSize)/nSizeWinSize;
                        nNewSizeWinSize += rItem.mnPixSize;
                    }
                }

                nSizeDelta -= nNewSizeWinSize-nSizeWinSize;
            }

            // compensate rounding errors now
            sal_uInt16 j = 0;
            nMins       = 0;
            while ( nSizeDelta && (nItems != nMins) )
            {
                // determine which items we can calculate
                nCalcItems = 0;
                while ( !nCalcItems )
                {
                    for ( auto& rItem : rItems )
                    {
                        rItem.mbSubSize = false;

                        if ( j >= 2 )
                            rItem.mbSubSize = true;
                        else
                        {
                            if ( (nSizeDelta > 0) || rItem.mnPixSize )
                            {
                                if ( j >= 1 )
                                    rItem.mbSubSize = true;
                                else
                                {
                                    if ( (j == 0) && (rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
                                        rItem.mbSubSize = true;
                                }
                            }
                        }

                        if ( rItem.mbSubSize )
                            nCalcItems++;
                    }

                    j++;
                }

                // subtract size of individual items
                tools::Long nErrorSum       = nSizeDelta % nCalcItems;
                tools::Long nCurSizeDelta   = nSizeDelta / nCalcItems;
                nMins           = 0;
                for ( auto& rItem : rItems )
                {
                    if ( rItem.mbSubSize )
                    {
                        tools::Long* pSize = &(rItem.mnPixSize);
                        tools::Long  nTempErr;

                        if ( nErrorSum )
                        {
                            if ( nErrorSum < 0 )
                                nTempErr = -1;
                            else
                                nTempErr = 1;
                        }
                        else
                            nTempErr = 0;

                        if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 )
                        {
                            tools::Long nTemp = *pSize;
                            if ( nTemp )
                            {
                                *pSize -= nTemp;
                                nSizeDelta += nTemp;
                            }
                            nMins++;
                        }
                        else
                        {
                            *pSize += nCurSizeDelta;
                            nSizeDelta -= nCurSizeDelta;
                            if ( nTempErr && (*pSize || (nTempErr > 0)) )
                            {
                                *pSize += nTempErr;
                                nSizeDelta -= nTempErr;
                                nErrorSum -= nTempErr;
                            }
                        }
                    }
                }
            }
        }
    }

    // calculate maximum size
    if ( bRows )
    {
        nPos = nSetTop;
        if ( !bDown )
            nMaxPos = nSetTop-nSetHeight;
        else
            nMaxPos = nSetTop+nSetHeight;
    }
    else
    {
        nPos = nSetLeft;
        if ( !bDown )
            nMaxPos = nSetLeft-nSetWidth;
        else
            nMaxPos = nSetLeft+nSetWidth;
    }

    // order windows and adapt values
    for ( size_t i = 0; i < nItems; i++ )
    {
        rItems[i].mnOldSplitPos    = rItems[i].mnSplitPos;
        rItems[i].mnOldSplitSize   = rItems[i].mnSplitSize;
        rItems[i].mnOldWidth       = rItems[i].mnWidth;
        rItems[i].mnOldHeight      = rItems[i].mnHeight;

        bEmpty = false;
        if ( bDown )
        {
            if ( nPos+rItems[i].mnPixSize > nMaxPos )
                bEmpty = true;
        }
        else
        {
            nPos -= rItems[i].mnPixSize;
            if ( nPos < nMaxPos )
                bEmpty = true;
        }

        if ( bEmpty )
        {
            rItems[i].mnWidth     = 0;
            rItems[i].mnHeight    = 0;
            rItems[i].mnSplitSize = 0;
        }
        else
        {
            if ( bRows )
            {
                rItems[i].mnLeft   = nSetLeft;
                rItems[i].mnTop    = nPos;
                rItems[i].mnWidth  = nSetWidth;
                rItems[i].mnHeight = rItems[i].mnPixSize;
            }
            else
            {
                rItems[i].mnLeft   = nPos;
                rItems[i].mnTop    = nSetTop;
                rItems[i].mnWidth  = rItems[i].mnPixSize;
                rItems[i].mnHeight = nSetHeight;
            }

            if ( i > nItems-1 )
                rItems[i].mnSplitSize = 0;
            else
            {
                rItems[i].mnSplitSize = pSet->mnSplitSize;
                if ( bDown )
                {
                    rItems[i].mnSplitPos  = nPos+rItems[i].mnPixSize;
                    if ( rItems[i].mnSplitPos+rItems[i].mnSplitSize > nMaxPos )
                        rItems[i].mnSplitSize = nMaxPos-rItems[i].mnSplitPos;
                }
                else
                {
                    rItems[i].mnSplitPos = nPos-pSet->mnSplitSize;
                    if ( rItems[i].mnSplitPos < nMaxPos )
                        rItems[i].mnSplitSize = rItems[i].mnSplitPos+pSet->mnSplitSize-nMaxPos;
                }
            }
        }

        if ( !bDown )
            nPos -= pSet->mnSplitSize;
        else
            nPos += rItems[i].mnPixSize+pSet->mnSplitSize;
    }

    // calculate Sub-Set's
    for ( auto& rItem : rItems )
    {
        if ( rItem.mpSet && rItem.mnWidth && rItem.mnHeight )
        {
            ImplCalcSet( rItem.mpSet.get(),
                         rItem.mnLeft, rItem.mnTop,
                         rItem.mnWidth, rItem.mnHeight,
                         !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
        }
    }

    // set fixed
    for ( auto& rItem : rItems )
    {
        rItem.mbFixed = false;
        if ( rItem.mnBits & SplitWindowItemFlags::Fixed )
            rItem.mbFixed = true;
        else
        {
            // this item is also fixed if Child-Set is available,
            // if a child is fixed
            if ( rItem.mpSet )
            {
                for ( auto const & j: rItem.mpSet->mvItems )
                {
                    if ( j.mbFixed )
                    {
                        rItem.mbFixed = true;
                        break;
                    }
                }
            }
        }
    }
}

void SplitWindow::ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, bool bHide,
                                bool bRows )
{
    std::vector< ImplSplitItem >&     rItems = pSet->mvItems;

    if ( pWindow->IsReallyVisible() && pWindow->IsUpdateMode() && pWindow->mbInvalidate )
    {
        for ( const auto& rItem : rItems )
        {
            if ( rItem.mnSplitSize )
            {
                // invalidate all, if applicable or only a small part
                if ( (rItem.mnOldSplitPos  != rItem.mnSplitPos)  ||
                     (rItem.mnOldSplitSize != rItem.mnSplitSize) ||
                     (rItem.mnOldWidth     != rItem.mnWidth)     ||
                     (rItem.mnOldHeight    != rItem.mnHeight) )
                {
                    tools::Rectangle aRect;

                    // invalidate old rectangle
                    if ( bRows )
                    {
                        aRect.SetLeft( rItem.mnLeft );
                        aRect.SetRight( rItem.mnLeft+rItem.mnOldWidth-1 );
                        aRect.SetTop( rItem.mnOldSplitPos );
                        aRect.SetBottom( aRect.Top() + rItem.mnOldSplitSize );
                    }
                    else
                    {
                        aRect.SetTop( rItem.mnTop );
                        aRect.SetBottom( rItem.mnTop+rItem.mnOldHeight-1 );
                        aRect.SetLeft( rItem.mnOldSplitPos );
                        aRect.SetRight( aRect.Left() + rItem.mnOldSplitSize );
                    }
                    pWindow->Invalidate( aRect );
                    // invalidate new rectangle
                    if ( bRows )
                    {
                        aRect.SetLeft( rItem.mnLeft );
                        aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
                        aRect.SetTop( rItem.mnSplitPos );
                        aRect.SetBottom( aRect.Top() + rItem.mnSplitSize );
                    }
                    else
                    {
                        aRect.SetTop( rItem.mnTop );
                        aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
                        aRect.SetLeft( rItem.mnSplitPos );
                        aRect.SetRight( aRect.Left() + rItem.mnSplitSize );
                    }
                    pWindow->Invalidate( aRect );

                    // invalidate complete set, as these areas
                    // are not cluttered by windows
                    if ( rItem.mpSet && rItem.mpSet->mvItems.empty() )
                    {
                        aRect.SetLeft( rItem.mnLeft );
                        aRect.SetTop( rItem.mnTop );
                        aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
                        aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
                        pWindow->Invalidate( aRect );
                    }
                }
            }
        }
    }

    // position windows
    for ( auto& rItem : rItems )
    {
        if ( rItem.mpSet )
        {
            bool bTempHide = bHide;
            if ( !rItem.mnWidth || !rItem.mnHeight )
                bTempHide = true;
            ImplCalcSet2( pWindow, rItem.mpSet.get(), bTempHide,
                          !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
        }
        else
        {
            if ( rItem.mnWidth && rItem.mnHeight && !bHide )
            {
                Point aPos( rItem.mnLeft, rItem.mnTop );
                Size  aSize( rItem.mnWidth, rItem.mnHeight );
                rItem.mpWindow->SetPosSizePixel( aPos, aSize );
            }
            else
                rItem.mpWindow->Hide();
        }
    }

    // show windows and reset flag
    for ( auto& rItem : rItems )
    {
        if ( rItem.mpWindow && rItem.mnWidth && rItem.mnHeight && !bHide )
            rItem.mpWindow->Show();
    }
}

static void ImplCalcLogSize( std::vector< ImplSplitItem > & rItems, size_t nItems )
{
    // update original sizes
    size_t  i;
    tools::Long    nRelSize = 0;
    tools::Long    nPerSize = 0;

    for ( i = 0; i < nItems; i++ )
    {
        if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
            nRelSize += rItems[i].mnPixSize;
        else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
            nPerSize += rItems[i].mnPixSize;
    }
    nPerSize += nRelSize;
    for ( i = 0; i < nItems; i++ )
    {
        if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
        {
            if ( nRelSize )
                rItems[i].mnSize = (rItems[i].mnPixSize+(nRelSize/2))/nRelSize;
            else
                rItems[i].mnSize = 1;
        }
        else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
        {
            if ( nPerSize )
                rItems[i].mnSize = (rItems[i].mnPixSize*100)/nPerSize;
            else
                rItems[i].mnSize = 1;
        }
        else
            rItems[i].mnSize = rItems[i].mnPixSize;
    }
}

static void ImplDrawSplit(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet, bool bRows, bool bDown)
{
    if (pSet->mvItems.empty())
        return;

    size_t     nItems = pSet->mvItems.size();
    tools::Long       nPos;
    tools::Long       nTop;
    tools::Long       nBottom;
    std::vector< ImplSplitItem >& rItems = pSet->mvItems;
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();

    for (size_t i = 0; i < nItems-1; i++)
    {
        if (rItems[i].mnSplitSize)
        {
            nPos = rItems[i].mnSplitPos;

            tools::Long nItemSplitSize = rItems[i].mnSplitSize;
            tools::Long nSplitSize = pSet->mnSplitSize;
            if (bRows)
            {
                nTop    = rItems[i].mnLeft;
                nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;

                if (bDown || (nItemSplitSize >= nSplitSize))
                {
                    rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
                    rRenderContext.DrawLine(Point(nTop, nPos + 1), Point(nBottom, nPos + 1));
                }
                nPos += nSplitSize-2;
                if ((!bDown && (nItemSplitSize >= 2)) ||
                    (bDown  && (nItemSplitSize >= nSplitSize - 1)))
                {
                    rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
                    rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
                }
                nPos++;
                if (!bDown || (nItemSplitSize >= nSplitSize))
                {
                    rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
                    rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
                }
            }
            else
            {
                nTop    = rItems[i].mnTop;
                nBottom = rItems[i].mnTop+pSet->mvItems[i].mnHeight-1;

                if (bDown || (nItemSplitSize >= nSplitSize))
                {
                    rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
                    rRenderContext.DrawLine(Point(nPos + 1, nTop), Point(nPos+1, nBottom));
                }
                nPos += pSet->mnSplitSize - 2;
                if ((!bDown && (nItemSplitSize >= 2)) ||
                    (bDown  && (nItemSplitSize >= nSplitSize - 1)))
                {
                    rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
                    rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
                }
                nPos++;
                if (!bDown || (nItemSplitSize >= nSplitSize))
                {
                    rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
                    rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
                }
            }
        }
    }

    for ( auto& rItem : rItems )
    {
        if (rItem.mpSet && rItem.mnWidth && rItem.mnHeight)
        {
            ImplDrawSplit(rRenderContext, rItem.mpSet.get(), !(rItem.mnBits & SplitWindowItemFlags::ColSet), true/*bDown*/);
        }
    }
}

sal_uInt16 SplitWindow::ImplTestSplit( ImplSplitSet* pSet, const Point& rPos,
                                   tools::Long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos,
                                   bool bRows )
{
    if ( pSet->mvItems.empty() )
        return 0;

    sal_uInt16      nSplitTest;
    size_t          nItems = pSet->mvItems.size();
    tools::Long            nMPos1;
    tools::Long            nMPos2;
    tools::Long            nPos;
    tools::Long            nTop;
    tools::Long            nBottom;
    std::vector< ImplSplitItem >& rItems = pSet->mvItems;

    if ( bRows )
    {
        nMPos1 = rPos.X();
        nMPos2 = rPos.Y();
    }
    else
    {
        nMPos1 = rPos.Y();
        nMPos2 = rPos.X();
    }

    for ( size_t i = 0; i < nItems-1; i++ )
    {
        if ( rItems[i].mnSplitSize )
        {
            if ( bRows )
            {
                nTop    = rItems[i].mnLeft;
                nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
            }
            else
            {
                nTop    = rItems[i].mnTop;
                nBottom = rItems[i].mnTop+rItems[i].mnHeight-1;
            }
            nPos = rItems[i].mnSplitPos;

            if ( (nMPos1 >= nTop) && (nMPos1 <= nBottom) &&
                 (nMPos2 >= nPos) && (nMPos2 <= nPos+rItems[i].mnSplitSize) )
            {
                if ( !rItems[i].mbFixed && !rItems[i+1].mbFixed )
                {
                    rMouseOff = nMPos2-nPos;
                    *ppFoundSet = pSet;
                    rFoundPos = i;
                    if ( bRows )
                        return SPLIT_VERT;
                    else
                        return SPLIT_HORZ;
                }
                else
                    return SPLIT_NOSPLIT;
            }
        }
    }

    for ( auto& rItem : rItems )
    {
        if ( rItem.mpSet )
        {
            nSplitTest = ImplTestSplit( rItem.mpSet.get(), rPos,
                                       rMouseOff, ppFoundSet, rFoundPos,
                                       !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
            if ( nSplitTest )
                return nSplitTest;
        }
    }

    return 0;
}

sal_uInt16 SplitWindow::ImplTestSplit( const SplitWindow* pWindow, const Point& rPos,
                                   tools::Long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos )
{
    // Resizable SplitWindow should be treated different
    if ( pWindow->mnWinStyle & WB_SIZEABLE )
    {
        tools::Long    nTPos;
        tools::Long    nPos;
        tools::Long    nBorder;

        if ( pWindow->mbHorz )
        {
            if ( pWindow->mbBottomRight )
            {
                nBorder = pWindow->mnBottomBorder;
                nPos = 0;
            }
            else
            {
                nBorder = pWindow->mnTopBorder;
                nPos = pWindow->mnDY-nBorder;
            }
            nTPos = rPos.Y();
        }
        else
        {
            if ( pWindow->mbBottomRight )
            {
                nBorder = pWindow->mnRightBorder;
                nPos = 0;
            }
            else
            {
                nBorder = pWindow->mnLeftBorder;
                nPos = pWindow->mnDX-nBorder;
            }
            nTPos = rPos.X();
        }
        tools::Long nSplitSize = pWindow->mpMainSet->mnSplitSize-2;
        if (pWindow->mbFadeOut)
            nSplitSize += SPLITWIN_SPLITSIZEEXLN;
        if ( !pWindow->mbBottomRight )
            nPos -= nSplitSize;
        if ( (nTPos >= nPos) && (nTPos <= nPos+nSplitSize+nBorder) )
        {
            rMouseOff = nTPos-nPos;
            *ppFoundSet = pWindow->mpMainSet.get();
            if ( !pWindow->mpMainSet->mvItems.empty() )
                rFoundPos = pWindow->mpMainSet->mvItems.size() - 1;
            else
                rFoundPos = 0;
            if ( pWindow->mbHorz )
                return SPLIT_VERT | SPLIT_WINDOW;
            else
                return SPLIT_HORZ | SPLIT_WINDOW;
        }
    }

    return ImplTestSplit( pWindow->mpMainSet.get(), rPos, rMouseOff, ppFoundSet, rFoundPos,
                         pWindow->mbHorz );
}

void SplitWindow::ImplDrawSplitTracking(const Point& rPos)
{
    tools::Rectangle aRect;

    if (mnSplitTest & SPLIT_HORZ)
    {
        aRect.SetTop( maDragRect.Top() );
        aRect.SetBottom( maDragRect.Bottom() );
        aRect.SetLeft( rPos.X() );
        aRect.SetRight( aRect.Left() + mpSplitSet->mnSplitSize - 1 );
        if (!(mnWinStyle & WB_NOSPLITDRAW))
            aRect.AdjustRight( -1 );
        if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
        {
            aRect.AdjustLeft(SPLITWIN_SPLITSIZEEXLN );
            aRect.AdjustRight(SPLITWIN_SPLITSIZEEXLN );
        }
    }
    else
    {
        aRect.SetLeft( maDragRect.Left() );
        aRect.SetRight( maDragRect.Right() );
        aRect.SetTop( rPos.Y() );
        aRect.SetBottom( aRect.Top() + mpSplitSet->mnSplitSize - 1 );
        if (!(mnWinStyle & WB_NOSPLITDRAW))
            aRect.AdjustBottom( -1 );
        if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
        {
            aRect.AdjustTop(SPLITWIN_SPLITSIZEEXLN );
            aRect.AdjustBottom(SPLITWIN_SPLITSIZEEXLN );
        }
    }
    ShowTracking(aRect, ShowTrackFlags::Split);
}

void SplitWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
    mpMainSet.reset(new ImplSplitSet());
    mpBaseSet               = mpMainSet.get();
    mpSplitSet              = nullptr;
    mpLastSizes             = nullptr;
    mnDX                    = 0;
    mnDY                    = 0;
    mnLeftBorder            = 0;
    mnTopBorder             = 0;
    mnRightBorder           = 0;
    mnBottomBorder          = 0;
    mnMaxSize               = 0;
    mnMouseOff              = 0;
    meAlign                 = WindowAlign::Top;
    mnWinStyle              = nStyle;
    mnSplitTest             = 0;
    mnSplitPos              = 0;
    mnMouseModifier         = 0;
    mnMStartPos             = 0;
    mnMSplitPos             = 0;
    mbDragFull              = false;
    mbHorz                  = true;
    mbBottomRight           = false;
    mbCalc                  = false;
    mbRecalc                = true;
    mbInvalidate            = true;
    mbFadeIn                = false;
    mbFadeOut               = false;
    mbFadeInDown            = false;
    mbFadeOutDown           = false;
    mbFadeInPressed         = false;
    mbFadeOutPressed        = false;
    mbFadeNoButtonMode      = false;

    if ( nStyle & WB_NOSPLITDRAW )
    {
        mpMainSet->mnSplitSize -= 2;
        mbInvalidate = false;
    }

    if ( nStyle & WB_BORDER )
    {
        ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
                        mnRightBorder, mnBottomBorder );
    }
    else
    {
        mnLeftBorder   = 0;
        mnTopBorder    = 0;
        mnRightBorder  = 0;
        mnBottomBorder = 0;
    }

    DockingWindow::ImplInit( pParent, (nStyle | WB_CLIPCHILDREN) & ~(WB_BORDER | WB_SIZEABLE) );

    ImplInitSettings();
}

void SplitWindow::ImplInitSettings()
{
    const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();

    Color aColor;
    if ( IsControlBackground() )
        aColor = GetControlBackground();
    else if ( Window::GetStyle() & WB_3DLOOK )
        aColor = rStyleSettings.GetFaceColor();
    else
        aColor = rStyleSettings.GetWindowColor();
    SetBackground( aColor );
}

SplitWindow::SplitWindow( vcl::Window* pParent, WinBits nStyle ) :
    DockingWindow( WindowType::SPLITWINDOW, "vcl::SplitWindow maLayoutIdle" )
{
    ImplInit( pParent, nStyle );
    // ensure there is sufficient border reserved to fit the splitter into
    set_border_width(SPLITWIN_SPLITSIZE);
}

SplitWindow::~SplitWindow()
{
    disposeOnce();
}

void SplitWindow::dispose()
{
    // delete Sets
    mpMainSet.reset();
    DockingWindow::dispose();
}

void SplitWindow::ImplSetWindowSize( tools::Long nDelta )
{
    if ( !nDelta )
        return;

    Size aSize = GetSizePixel();
    switch ( meAlign )
    {
    case WindowAlign::Top:
        aSize.AdjustHeight(nDelta );
        SetSizePixel( aSize );
        break;
    case WindowAlign::Bottom:
    {
        maDragRect.AdjustTop(nDelta );
        Point aPos = GetPosPixel();
        aPos.AdjustY( -nDelta );
        aSize.AdjustHeight(nDelta );
        SetPosSizePixel( aPos, aSize );
        break;
    }
    case WindowAlign::Left:
        aSize.AdjustWidth(nDelta );
        SetSizePixel( aSize );
        break;
    case WindowAlign::Right:
    default:
    {
        maDragRect.AdjustLeft(nDelta );
        Point aPos = GetPosPixel();
        aPos.AdjustX( -nDelta );
        aSize.AdjustWidth(nDelta );
        SetPosSizePixel( aPos, aSize );
        break;
    }
    }

    SplitResize();
}

Size SplitWindow::CalcLayoutSizePixel( const Size& aNewSize )
{
    Size aSize( aNewSize );
    tools::Long nSplitSize = mpMainSet->mnSplitSize-2;

    if (mbFadeOut)
        nSplitSize += SPLITWIN_SPLITSIZEEXLN;

    // if the window is sizeable and if it does not contain a relative window,
    // the size is determined according to MainSet
    if ( mnWinStyle & WB_SIZEABLE )
    {
        tools::Long    nCalcSize = 0;
        std::vector< ImplSplitItem* >::size_type i;

        for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
        {
            if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
                break;
            else
                nCalcSize += mpMainSet->mvItems[i].mnSize;
        }

        if ( i == mpMainSet->mvItems.size() )
        {
            tools::Long    nDelta = 0;
            tools::Long    nCurSize;

            if ( mbHorz )
                nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder;
            else
                nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder;
            nCurSize -= nSplitSize;
            nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;

            nDelta = nCalcSize-nCurSize;
            if ( !nDelta )
                return aSize;

            switch ( meAlign )
            {
            case WindowAlign::Top:
            case WindowAlign::Bottom:
                aSize.AdjustHeight(nDelta );
                break;
            case WindowAlign::Right:
            case WindowAlign::Left:
            default:
                aSize.AdjustWidth(nDelta );
                break;
            }
        }
    }

    return aSize;
}

void SplitWindow::ImplCalcLayout()
{
    if ( !mbCalc || !mbRecalc || mpMainSet->mvItems.empty() )
        return;

    tools::Long nSplitSize = mpMainSet->mnSplitSize-2;
    if (mbFadeOut)
        nSplitSize += SPLITWIN_SPLITSIZEEXLN;

    // if the window is sizeable and if it does not contain a relative window,
    // the size is determined according to MainSet
    if ( mnWinStyle & WB_SIZEABLE )
    {
        tools::Long    nCalcSize = 0;
        std::vector<ImplSplitItem *>::size_type i;

        for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
        {
            if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
                break;
            else
                nCalcSize += mpMainSet->mvItems[i].mnSize;
        }

        if ( i == mpMainSet->mvItems.size() )
        {
            tools::Long    nCurSize;
            if ( mbHorz )
                nCurSize = mnDY-mnTopBorder-mnBottomBorder;
            else
                nCurSize = mnDX-mnLeftBorder-mnRightBorder;
            nCurSize -= nSplitSize;
            nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;

            mbRecalc = false;
            ImplSetWindowSize( nCalcSize-nCurSize );
            mbRecalc = true;
        }
    }

    if ( (mnDX <= 0) || (mnDY <= 0) )
        return;

    // pre-calculate sizes/position
    tools::Long    nL;
    tools::Long    nT;
    tools::Long    nW;
    tools::Long    nH;

    if ( mbHorz )
    {
        if ( mbBottomRight )
            nT = mnDY-mnBottomBorder;
        else
            nT = mnTopBorder;
        nL = mnLeftBorder;
    }
    else
    {
        if ( mbBottomRight )
            nL = mnDX-mnRightBorder;
        else
            nL = mnLeftBorder;
        nT = mnTopBorder;
    }
    nW = mnDX-mnLeftBorder-mnRightBorder;
    nH = mnDY-mnTopBorder-mnBottomBorder;
    if ( mnWinStyle & WB_SIZEABLE )
    {
        if ( mbHorz )
            nH -= nSplitSize;
        else
            nW -= nSplitSize;
    }

    // calculate sets recursive
    ImplCalcSet( mpMainSet.get(), nL, nT, nW, nH, mbHorz, !mbBottomRight );
    ImplCalcSet2( this, mpMainSet.get(), false, mbHorz );
    mbCalc = false;
}

void SplitWindow::ImplUpdate()
{
    mbCalc = true;

    if ( IsReallyShown() && IsUpdateMode() && mbRecalc )
    {
        if ( !mpMainSet->mvItems.empty() )
            ImplCalcLayout();
        else
            Invalidate();
    }
}

void SplitWindow::ImplSplitMousePos( Point& rMousePos )
{
    if ( mnSplitTest & SPLIT_HORZ )
    {
        rMousePos.AdjustX( -mnMouseOff );
        if ( rMousePos.X() < maDragRect.Left() )
            rMousePos.setX( maDragRect.Left() );
        else if ( rMousePos.X()+mpSplitSet->mnSplitSize+1 > maDragRect.Right() )
            rMousePos.setX( maDragRect.Right()-mpSplitSet->mnSplitSize+1 );
        // store in screen coordinates due to FullDrag
        mnMSplitPos = OutputToScreenPixel( rMousePos ).X();
    }
    else
    {
        rMousePos.AdjustY( -mnMouseOff );
        if ( rMousePos.Y() < maDragRect.Top() )
            rMousePos.setY( maDragRect.Top() );
        else if ( rMousePos.Y()+mpSplitSet->mnSplitSize+1 > maDragRect.Bottom() )
            rMousePos.setY( maDragRect.Bottom()-mpSplitSet->mnSplitSize+1 );
        mnMSplitPos = OutputToScreenPixel( rMousePos ).Y();
    }
}

void SplitWindow::ImplGetButtonRect( tools::Rectangle& rRect, bool bTest ) const
{
    tools::Long nSplitSize = mpMainSet->mnSplitSize-1;
    if (mbFadeOut || mbFadeIn)
        nSplitSize += SPLITWIN_SPLITSIZEEX;

    tools::Long nButtonSize = 0;
    if ( mbFadeIn )
        nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
    if ( mbFadeOut )
        nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
    tools::Long nCenterEx = 0;
    if ( mbHorz )
        nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2;
    else
        nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2;
    tools::Long nEx = 0;
    if ( nCenterEx > 0 )
        nEx += nCenterEx;

    switch ( meAlign )
    {
    case WindowAlign::Top:
        rRect.SetLeft( mnLeftBorder+nEx );
        rRect.SetTop( mnDY-mnBottomBorder-nSplitSize );
        rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
        rRect.SetBottom( mnDY-mnBottomBorder-1 );
        if ( bTest )
        {
            rRect.AdjustTop( -mnTopBorder );
            rRect.AdjustBottom(mnBottomBorder );
        }
        break;
    case WindowAlign::Bottom:
        rRect.SetLeft( mnLeftBorder+nEx );
        rRect.SetTop( mnTopBorder );
        rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
        rRect.SetBottom( mnTopBorder+nSplitSize-1 );
        if ( bTest )
        {
            rRect.AdjustTop( -mnTopBorder );
            rRect.AdjustBottom(mnBottomBorder );
        }
        break;
    case WindowAlign::Left:
        rRect.SetLeft( mnDX-mnRightBorder-nSplitSize );
        rRect.SetTop( mnTopBorder+nEx );
        rRect.SetRight( mnDX-mnRightBorder-1 );
        rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
        if ( bTest )
        {
            rRect.AdjustLeft( -mnLeftBorder );
            rRect.AdjustRight(mnRightBorder );
        }
        break;
    case WindowAlign::Right:
        rRect.SetLeft( mnLeftBorder );
        rRect.SetTop( mnTopBorder+nEx );
        rRect.SetRight( mnLeftBorder+nSplitSize-1 );
        rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
        if ( bTest )
        {
            rRect.AdjustLeft( -mnLeftBorder );
            rRect.AdjustRight(mnRightBorder );
        }
        break;
    }
}

void SplitWindow::ImplGetFadeInRect( tools::Rectangle& rRect, bool bTest ) const
{
    tools::Rectangle aRect;

    if ( mbFadeIn )
        ImplGetButtonRect( aRect, bTest );

    rRect = aRect;
}

void SplitWindow::ImplGetFadeOutRect( tools::Rectangle& rRect ) const
{
    tools::Rectangle aRect;

    if ( mbFadeOut )
        ImplGetButtonRect( aRect, false );

    rRect = aRect;
}

void SplitWindow::ImplDrawGrip(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, bool bHorizontal, bool bLeft)
{
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();

    Color aColor;

    if (rRect.Contains(GetPointerPosPixel()))
    {
        vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, rRect, 2, falsefalsefalse);

        aColor = rStyleSettings.GetDarkShadowColor();
    }
    else
    {
        rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
        rRenderContext.SetFillColor(rStyleSettings.GetDarkShadowColor());

        rRenderContext.DrawRect(rRect);

        aColor = rStyleSettings.GetFaceColor();
    }

    AntialiasingFlags nAA = rRenderContext.GetAntialiasing();
    rRenderContext.SetAntialiasing(nAA | AntialiasingFlags::PixelSnapHairline | AntialiasingFlags::Enable);

    tools::Long nWidth = rRect.getOpenWidth();
    tools::Long nWidthHalf = nWidth / 2;
    tools::Long nHeight = rRect.getOpenHeight();
    tools::Long nHeightHalf = nHeight / 2;

    tools::Long nLeft = rRect.Left();
    tools::Long nRight = rRect.Right();
    tools::Long nTop = rRect.Top();
    tools::Long nBottom = rRect.Bottom();
    tools::Long nMargin = 1;

    rRenderContext.SetLineColor(aColor);
    rRenderContext.SetFillColor(aColor);

    tools::Polygon aPoly(3);

    if (bHorizontal)
    {
        tools::Long nCenter = nLeft + nWidthHalf;

        if (bLeft)
        {
            aPoly.SetPoint(Point(nCenter,               nTop    + nMargin), 0);
            aPoly.SetPoint(Point(nCenter - nHeightHalf, nBottom - nMargin), 1);
            aPoly.SetPoint(Point(nCenter - nHeightHalf, nBottom - nMargin), 2);
        }
        else
        {
            aPoly.SetPoint(Point(nCenter,               nBottom - nMargin), 0);
            aPoly.SetPoint(Point(nCenter - nHeightHalf, nTop    + nMargin), 1);
            aPoly.SetPoint(Point(nCenter + nHeightHalf, nTop    + nMargin), 2);
        }
        rRenderContext.DrawPolygon(aPoly);
    }
    else
    {
        tools::Long nCenter = nTop + nHeightHalf;

        if (bLeft)
        {
            aPoly.SetPoint(Point(nLeft  + nMargin, nCenter), 0);
            aPoly.SetPoint(Point(nRight - nMargin, nCenter - nWidthHalf), 1);
            aPoly.SetPoint(Point(nRight - nMargin, nCenter + nWidthHalf), 2);
        }
        else
        {
            aPoly.SetPoint(Point(nRight - nMargin, nCenter), 0);
            aPoly.SetPoint(Point(nLeft  + nMargin, nCenter - nWidthHalf), 1);
            aPoly.SetPoint(Point(nLeft  + nMargin, nCenter + nWidthHalf), 2);
        }
        rRenderContext.DrawPolygon(aPoly);
    }

    rRenderContext.SetAntialiasing(nAA);
}

void SplitWindow::ImplDrawFadeIn(vcl::RenderContext& rRenderContext)
{
    if (!mbFadeIn)
        return;

    tools::Rectangle aTempRect;
    ImplGetFadeInRect(aTempRect);

    bool bLeft = true;
    switch (meAlign)
    {
    case WindowAlign::Top:
    case WindowAlign::Left:
        bLeft = false;
        break;
    case WindowAlign::Bottom:
    case WindowAlign::Right:
    default:
        bLeft = true;
        break;
    }

    ImplDrawGrip(rRenderContext, aTempRect, (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom), bLeft);
}

void SplitWindow::ImplDrawFadeOut(vcl::RenderContext& rRenderContext)
{
    if (!mbFadeOut)
        return;

    tools::Rectangle aTempRect;
    ImplGetFadeOutRect(aTempRect);

    bool bLeft = true;
    switch (meAlign)
    {
    case WindowAlign::Bottom:
    case WindowAlign::Right:
        bLeft = false;
        break;
    case WindowAlign::Top:
    case WindowAlign::Left:
    default:
        bLeft = true;
        break;
    }

    ImplDrawGrip(rRenderContext, aTempRect, (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom), bLeft);
}

void SplitWindow::ImplStartSplit( const MouseEvent& rMEvt )
{
    Point aMousePosPixel = rMEvt.GetPosPixel();
    mnSplitTest = ImplTestSplit( this, aMousePosPixel, mnMouseOff, &mpSplitSet, mnSplitPos );

    if ( !mnSplitTest || (mnSplitTest & SPLIT_NOSPLIT) )
        return;

    ImplSplitItem*  pSplitItem;
    tools::Long            nCurMaxSize;
    bool            bPropSmaller;

    mnMouseModifier = rMEvt.GetModifier();
    bPropSmaller = (mnMouseModifier & KEY_SHIFT) && (o3tl::make_unsigned(mnSplitPos+1) < mpSplitSet->mvItems.size());

    // here we can set the maximum size
    StartSplit();

    if ( mnMaxSize )
        nCurMaxSize = mnMaxSize;
    else
    {
        Size aSize = GetParent()->GetOutputSizePixel();
        if ( mbHorz )
            nCurMaxSize = aSize.Height();
        else
            nCurMaxSize = aSize.Width();
    }

    if ( !mpSplitSet->mvItems.empty() )
    {
        bool bDown = true;
        if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
            bDown = false;

        pSplitItem          = &mpSplitSet->mvItems[mnSplitPos];
        maDragRect.SetLeft( pSplitItem->mnLeft );
        maDragRect.SetTop( pSplitItem->mnTop );
        maDragRect.SetRight( pSplitItem->mnLeft+pSplitItem->mnWidth-1 );
        maDragRect.SetBottom( pSplitItem->mnTop+pSplitItem->mnHeight-1 );

        if ( mnSplitTest & SPLIT_HORZ )
        {
            if ( bDown )
                maDragRect.AdjustRight(mpSplitSet->mnSplitSize );
            else
                maDragRect.AdjustLeft( -(mpSplitSet->mnSplitSize) );
        }
        else
        {
            if ( bDown )
                maDragRect.AdjustBottom(mpSplitSet->mnSplitSize );
            else
                maDragRect.AdjustTop( -(mpSplitSet->mnSplitSize) );
        }

        if ( mnSplitPos )
        {
            tools::Long nTemp = mnSplitPos;
            while ( nTemp )
            {
                pSplitItem = &mpSplitSet->mvItems[nTemp-1];
                if ( pSplitItem->mbFixed )
                    break;
                else
                {
                    if ( mnSplitTest & SPLIT_HORZ )
                    {
                        if ( bDown )
                            maDragRect.AdjustLeft( -(pSplitItem->mnPixSize) );
                        else
                            maDragRect.AdjustRight(pSplitItem->mnPixSize );
                    }
                    else
                    {
                        if ( bDown )
                            maDragRect.AdjustTop( -(pSplitItem->mnPixSize) );
                        else
                            maDragRect.AdjustBottom(pSplitItem->mnPixSize );
                    }
                }
                nTemp--;
            }
        }

        if ( (mpSplitSet == mpMainSet.get()) && (mnWinStyle & WB_SIZEABLE) && !bPropSmaller )
        {
            if ( bDown )
            {
                if ( mbHorz )
                    maDragRect.AdjustBottom(nCurMaxSize-mnDY-mnTopBorder );
                else
                    maDragRect.AdjustRight(nCurMaxSize-mnDX-mnLeftBorder );
            }
            else
            {
                if ( mbHorz )
                    maDragRect.AdjustTop( -(nCurMaxSize-mnDY-mnBottomBorder) );
                else
                    maDragRect.AdjustLeft( -(nCurMaxSize-mnDX-mnRightBorder) );
            }
        }
        else
        {
            std::vector<ImplSplitItem *>::size_type nTemp = mnSplitPos+1;
            while ( nTemp < mpSplitSet->mvItems.size() )
            {
                pSplitItem = &mpSplitSet->mvItems[nTemp];
                if ( pSplitItem->mbFixed )
                    break;
                else
                {
                    if ( mnSplitTest & SPLIT_HORZ )
                    {
                        if ( bDown )
                            maDragRect.AdjustRight(pSplitItem->mnPixSize );
                        else
                            maDragRect.AdjustLeft( -(pSplitItem->mnPixSize) );
                    }
                    else
                    {
                        if ( bDown )
                            maDragRect.AdjustBottom(pSplitItem->mnPixSize );
                        else
                            maDragRect.AdjustTop( -(pSplitItem->mnPixSize) );
                    }
                }
                nTemp++;
            }
        }
    }
    else
    {
        maDragRect.SetLeft( mnLeftBorder );
        maDragRect.SetTop( mnTopBorder );
        maDragRect.SetRight( mnDX-mnRightBorder-1 );
        maDragRect.SetBottom( mnDY-mnBottomBorder-1 );
        if ( mbHorz )
        {
            if ( mbBottomRight )
                maDragRect.AdjustTop( -(nCurMaxSize-mnDY-mnBottomBorder) );
            else
                maDragRect.AdjustBottom(nCurMaxSize-mnDY-mnTopBorder );
        }
        else
        {
            if ( mbBottomRight )
                maDragRect.AdjustLeft( -(nCurMaxSize-mnDX-mnRightBorder) );
            else
                maDragRect.AdjustRight(nCurMaxSize-mnDX-mnLeftBorder );
        }
    }

    StartTracking();

    mbDragFull = bool(GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Split);

    ImplSplitMousePos( aMousePosPixel );

    if (!mbDragFull)
    {
        ImplDrawSplitTracking(aMousePosPixel);
    }
    else
    {
        std::vector< ImplSplitItem >&  rItems = mpSplitSet->mvItems;
        sal_uInt16       nItems = mpSplitSet->mvItems.size();
        mpLastSizes.reset(new tools::Long[nItems*2]);
        for ( sal_uInt16 i = 0; i < nItems; i++ )
        {
            mpLastSizes[i*2]   = rItems[i].mnSize;
            mpLastSizes[i*2+1] = rItems[i].mnPixSize;
        }
    }
    mnMStartPos = mnMSplitPos;

    PointerStyle eStyle = PointerStyle::Arrow;
    if ( mnSplitTest & SPLIT_HORZ )
        eStyle = PointerStyle::HSplit;
    else if ( mnSplitTest & SPLIT_VERT )
        eStyle = PointerStyle::VSplit;

    SetPointer( eStyle );
}

void SplitWindow::StartSplit()
{
}

void SplitWindow::Split()
{
    maSplitHdl.Call( this );
}

void SplitWindow::SplitResize()
{
}

void SplitWindow::FadeIn()
{
}

void SplitWindow::FadeOut()
{
}

void SplitWindow::MouseButtonDown( const MouseEvent& rMEvt )
{
    if ( !rMEvt.IsLeft() || rMEvt.IsMod2() )
    {
        DockingWindow::MouseButtonDown( rMEvt );
        return;
    }

    Point           aMousePosPixel = rMEvt.GetPosPixel();
    tools::Rectangle       aTestRect;

    mbFadeNoButtonMode = false;

    ImplGetFadeOutRect( aTestRect );
    if ( aTestRect.Contains( aMousePosPixel ) )
    {
        mbFadeOutDown = true;
        mbFadeOutPressed = true;
        Invalidate();
    }
    else
    {
        ImplGetFadeInRect( aTestRect, true );
        if ( aTestRect.Contains( aMousePosPixel ) )
        {
            mbFadeInDown = true;
            mbFadeInPressed = true;
            Invalidate();
        }
        else if ( !aTestRect.IsEmpty() && !(mnWinStyle & WB_SIZEABLE) )
        {
            mbFadeNoButtonMode = true;
            FadeIn();
            return;
        }
    }

    if ( mbFadeInDown || mbFadeOutDown )
        StartTracking();
    else
        ImplStartSplit( rMEvt );
}

void SplitWindow::MouseMove( const MouseEvent& rMEvt )
{
    if ( IsTracking() )
        return;

    Point           aPos = rMEvt.GetPosPixel();
    tools::Long            nTemp;
    ImplSplitSet*   pTempSplitSet;
    sal_uInt16          nTempSplitPos;
    sal_uInt16          nSplitTest = ImplTestSplit( this, aPos, nTemp, &pTempSplitSet, nTempSplitPos );
    PointerStyle    eStyle = PointerStyle::Arrow;
    tools::Rectangle       aFadeInRect;
    tools::Rectangle       aFadeOutRect;

    ImplGetFadeInRect( aFadeInRect );
    ImplGetFadeOutRect( aFadeOutRect );
    if ( !aFadeInRect.Contains( aPos ) &&
         !aFadeOutRect.Contains( aPos ) )
    {
        if ( nSplitTest && !(nSplitTest & SPLIT_NOSPLIT) )
        {
            if ( nSplitTest & SPLIT_HORZ )
                eStyle = PointerStyle::HSplit;
            else if ( nSplitTest & SPLIT_VERT )
                eStyle = PointerStyle::VSplit;
        }
    }

    SetPointer( eStyle );
}

void SplitWindow::Tracking( const TrackingEvent& rTEvt )
{
    Point aMousePosPixel = rTEvt.GetMouseEvent().GetPosPixel();

    if ( mbFadeInDown )
    {
        if ( rTEvt.IsTrackingEnded() )
        {
            mbFadeInDown = false;
            if ( mbFadeInPressed )
            {
                mbFadeInPressed = false;
                Invalidate();

                if ( !rTEvt.IsTrackingCanceled() )
                    FadeIn();
            }
        }
        else
        {
            tools::Rectangle aTestRect;
            ImplGetFadeInRect( aTestRect, true );
            bool bNewPressed = aTestRect.Contains( aMousePosPixel );
            if ( bNewPressed != mbFadeInPressed )
            {
                mbFadeInPressed = bNewPressed;
                Invalidate();
            }
        }
    }
    else if ( mbFadeOutDown )
    {
        if ( rTEvt.IsTrackingEnded() )
        {
            mbFadeOutDown = false;
            if ( mbFadeOutPressed )
            {
                mbFadeOutPressed = false;
                Invalidate();

                if ( !rTEvt.IsTrackingCanceled() )
                    FadeOut();
            }
        }
        else
        {
            tools::Rectangle aTestRect;
            ImplGetFadeOutRect( aTestRect );
            bool bNewPressed = aTestRect.Contains( aMousePosPixel );
            if ( !bNewPressed )
            {
                mbFadeOutPressed = bNewPressed;
                Invalidate();

                // We need a mouseevent with a position inside the button for the
                // ImplStartSplit function!
                MouseEvent aOrgMEvt = rTEvt.GetMouseEvent();
                MouseEvent aNewMEvt( aTestRect.Center(), aOrgMEvt.GetClicks(),
                                     aOrgMEvt.GetMode(), aOrgMEvt.GetButtons(),
                                     aOrgMEvt.GetModifier() );

                ImplStartSplit( aNewMEvt );
                mbFadeOutDown = false;
            }
        }
    }
    else
    {
        ImplSplitMousePos( aMousePosPixel );
        bool bSplit = true;
        if ( mbDragFull )
        {
            if ( rTEvt.IsTrackingEnded() )
            {
                if ( rTEvt.IsTrackingCanceled() )
                {
                    std::vector< ImplSplitItem >& rItems = mpSplitSet->mvItems;
                    size_t          nItems = rItems.size();
                    for ( size_t i = 0; i < nItems; i++ )
                    {
                        rItems[i].mnSize     = mpLastSizes[i*2];
                        rItems[i].mnPixSize  = mpLastSizes[i*2+1];
                    }
                    ImplUpdate();
                    Split();
                }
                bSplit = false;
            }
        }
        else
        {
            if ( rTEvt.IsTrackingEnded() )
            {
                HideTracking();
                bSplit = !rTEvt.IsTrackingCanceled();
            }
            else
            {
                ImplDrawSplitTracking(aMousePosPixel);
                bSplit = false;
            }
        }

        if ( bSplit )
        {
            bool    bPropSmaller = (mnMouseModifier & KEY_SHIFT) != 0;
            bool    bPropGreater = (mnMouseModifier & KEY_MOD1) != 0;
            tools::Long    nDelta = mnMSplitPos-mnMStartPos;

            if ( (mnSplitTest & SPLIT_WINDOW) && mpMainSet->mvItems.empty() )
            {
                if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
                    nDelta *= -1;
                ImplSetWindowSize( nDelta );
            }
            else
            {
                tools::Long nNewSize = mpSplitSet->mvItems[mnSplitPos].mnPixSize;
                if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
                    nNewSize -= nDelta;
                else
                    nNewSize += nDelta;
                SplitItem( mpSplitSet->mvItems[mnSplitPos].mnId, nNewSize,
                           bPropSmaller, bPropGreater );
            }

            Split();

            if ( mbDragFull )
            {
                PaintImmediately();
                mnMStartPos = mnMSplitPos;
            }
        }

        if ( rTEvt.IsTrackingEnded() )
        {
            mpLastSizes.reset();
            mpSplitSet      = nullptr;
            mnMouseOff      = 0;
            mnMStartPos     = 0;
            mnMSplitPos     = 0;
            mnMouseModifier = 0;
            mnSplitTest     = 0;
            mnSplitPos      = 0;
        }
    }
}

bool SplitWindow::PreNotify( NotifyEvent& rNEvt )
{
    if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
    {
        const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
        if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
        {
            // trigger redraw if mouse over state has changed
            tools::Rectangle aFadeInRect;
            tools::Rectangle aFadeOutRect;
            ImplGetFadeInRect( aFadeInRect );
            ImplGetFadeOutRect( aFadeOutRect );

            if ( aFadeInRect.Contains( GetPointerPosPixel() ) != aFadeInRect.Contains( GetLastPointerPosPixel() ) )
                Invalidate( aFadeInRect );
            if ( aFadeOutRect.Contains( GetPointerPosPixel() ) != aFadeOutRect.Contains( GetLastPointerPosPixel() ) )
                Invalidate( aFadeOutRect );

            if( pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
            {
                Invalidate( aFadeInRect );
                Invalidate( aFadeOutRect );
            }
        }
    }
    return Window::PreNotify( rNEvt );
}

void SplitWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    if (mnWinStyle & WB_BORDER)
        ImplDrawBorder(rRenderContext);

    ImplDrawBorderLine(rRenderContext);
    ImplDrawFadeOut(rRenderContext);
    ImplDrawFadeIn(rRenderContext);

    // draw splitter
    if (!(mnWinStyle & WB_NOSPLITDRAW))
    {
        ImplDrawSplit(rRenderContext, mpMainSet.get(), mbHorz, !mbBottomRight);
    }
}

void SplitWindow::Resize()
{
    Size aSize = GetOutputSizePixel();
    mnDX = aSize.Width();
    mnDY = aSize.Height();

    ImplUpdate();
    Invalidate();
}

void SplitWindow::RequestHelp( const HelpEvent& rHEvt )
{
    // no keyboard help for splitwin
    if ( rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK) && !rHEvt.KeyboardActivated() )
    {
        Point       aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
        tools::Rectangle   aHelpRect;
        TranslateId pHelpResId;

        ImplGetFadeInRect( aHelpRect, true );
        if ( aHelpRect.Contains( aMousePosPixel ) )
            pHelpResId = SV_HELPTEXT_FADEIN;
        else
        {
            ImplGetFadeOutRect( aHelpRect );
            if ( aHelpRect.Contains( aMousePosPixel ) )
                pHelpResId = SV_HELPTEXT_FADEOUT;
        }

        // get rectangle
        if (pHelpResId)
        {
            Point aPt = OutputToScreenPixel( aHelpRect.TopLeft() );
            aHelpRect.SetLeft( aPt.X() );
            aHelpRect.SetTop( aPt.Y() );
            aPt = OutputToScreenPixel( aHelpRect.BottomRight() );
            aHelpRect.SetRight( aPt.X() );
            aHelpRect.SetBottom( aPt.Y() );

            // get and draw text
            OUString aStr = VclResId(pHelpResId);
            if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
                Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aStr );
            else
                Help::ShowQuickHelp( this, aHelpRect, aStr );
            return;
        }
    }

    DockingWindow::RequestHelp( rHEvt );
}

void SplitWindow::StateChanged( StateChangedType nType )
{
    switch ( nType )
    {
    case StateChangedType::InitShow:
        if ( IsUpdateMode() )
            ImplCalcLayout();
        break;
    case StateChangedType::UpdateMode:
        if ( IsUpdateMode() && IsReallyShown() )
            ImplCalcLayout();
        break;
    case StateChangedType::ControlBackground:
        ImplInitSettings();
        Invalidate();
        break;
    default:;
    }

    DockingWindow::StateChanged( nType );
}

void SplitWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
    if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
         (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
    {
        ImplInitSettings();
        Invalidate();
    }
    else
        DockingWindow::DataChanged( rDCEvt );
}

void SplitWindow::InsertItem( sal_uInt16 nId, vcl::Window* pWindow, tools::Long nSize,
                              sal_uInt16 nPos, sal_uInt16 nIntoSetId,
                              SplitWindowItemFlags nBits )
{
#ifdef DBG_UTIL
    sal_uInt16 nDbgDummy;
    SAL_WARN_IF( ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl""SplitWindow::InsertItem() - Id already exists" );
#endif

    // Size has to be at least 1.
    if ( nSize < 1 )
        nSize = 1;

    ImplSplitSet* pSet       = ImplFindSet( mpMainSet.get(), nIntoSetId );
#ifdef DBG_UTIL
    SAL_WARN_IF( !pSet, "vcl""SplitWindow::InsertItem() - Set not exists" );
#endif
    if(!pSet)
    {
        return;
    }

    // Don't insert further than the end
    if ( nPos > pSet->mvItems.size() )
        nPos = pSet->mvItems.size();

    // Insert in set
    pSet->mvItems.emplace( pSet->mvItems.begin() + nPos );

    // init new item
    ImplSplitItem & aItem = pSet->mvItems[nPos];
    aItem.mnSize   = nSize;
    aItem.mnPixSize = 0;
    aItem.mnId     = nId;
    aItem.mnBits   = nBits;
    aItem.mnMinSize=-1;
    aItem.mnMaxSize=-1;

    if ( pWindow )
    {
        // New VclPtr reference
        aItem.mpWindow         = pWindow;
        aItem.mpOrgParent      = pWindow->GetParent();

        // Attach window to SplitWindow.
        pWindow->Hide();
        pWindow->SetParent( this );
    }
    else
    {
        ImplSplitSet * pNewSet  = new ImplSplitSet();
        pNewSet->mnId           = nId;
        pNewSet->mnSplitSize    = pSet->mnSplitSize;

        aItem.mpSet.reset(pNewSet);
    }

    pSet->mbCalcPix = true;

    ImplUpdate();
}

void SplitWindow::InsertItem( sal_uInt16 nId, tools::Long nSize,
                              sal_uInt16 nPos, sal_uInt16 nIntoSetId,
                              SplitWindowItemFlags nBits )
{
    InsertItem( nId, nullptr, nSize, nPos, nIntoSetId, nBits );
}

void SplitWindow::RemoveItem( sal_uInt16 nId )
{
#ifdef DBG_UTIL
    sal_uInt16 nDbgDummy;
    SAL_WARN_IF( !ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl""SplitWindow::RemoveItem() - Id not found" );
#endif

    // search set
    sal_uInt16     nPos;
    ImplSplitSet*  pSet    = ImplFindItem( mpMainSet.get(), nId, nPos );

    if (!pSet)
        return;

    ImplSplitItem* pItem = &pSet->mvItems[nPos];
    VclPtr<vcl::Window> pWindow = pItem->mpWindow;
    VclPtr<vcl::Window> pOrgParent = pItem->mpOrgParent;

    // delete set if required
    if ( !pWindow )
        pItem->mpSet.reset();

    // remove item
    pSet->mbCalcPix = true;
    pSet->mvItems.erase( pSet->mvItems.begin() + nPos );

    ImplUpdate();

    // to have the least amounts of paints delete window only here
    if ( pWindow )
    {
        // restore window
        pWindow->Hide();
        pWindow->SetParent( pOrgParent );
    }

    // Clear and delete
    pWindow.reset();
    pOrgParent.reset();
}

void SplitWindow::SplitItem( sal_uInt16 nId, tools::Long nNewSize,
                             bool bPropSmall, bool bPropGreat )
{
    sal_uInt16      nPos;
    ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );

    if (!pSet)
        return;

    size_t           nItems = pSet->mvItems.size();
    std::vector< ImplSplitItem >&  rItems = pSet->mvItems;

    // When there is an explicit minimum or maximum size then move nNewSize
    // into that range (when it is not yet already in it.)
    nNewSize = ValidateSize(nNewSize, rItems[nPos]);

    if ( mbCalc )
    {
        rItems[nPos].mnSize = nNewSize;
        return;
    }

    tools::Long nDelta = nNewSize-rItems[nPos].mnPixSize;
    if ( !nDelta )
        return;

    // calculate area, which could be affected by splitting
    sal_uInt16 nMin = 0;
    sal_uInt16 nMax = nItems;
    for (size_t i = 0; i < nItems; ++i)
    {
        if ( rItems[i].mbFixed )
        {
            if ( i < nPos )
                nMin = i+1;
            else
                nMax = i;
        }
    }

    // treat TopSet different if the window is sizeable
    bool bSmall  = true;
    bool bGreat  = true;
    if ( (pSet == mpMainSet.get()) && (mnWinStyle & WB_SIZEABLE) )
    {
        if ( nPos < pSet->mvItems.size()-1 )
        {
            if ( !((bPropSmall && bPropGreat) ||
                   ((nDelta > 0) && bPropSmall) ||
                   ((nDelta < 0) && bPropGreat)) )
            {
                if ( nDelta < 0 )
                    bGreat = false;
                else
                    bSmall = false;
            }
        }
        else
        {
            if ( nDelta < 0 )
                bGreat = false;
            else
                bSmall = false;
        }
    }
    else if ( nPos >= nMax )
    {
        bSmall = false;
        bGreat = false;
    }
    else if ( nPos && (nPos >= pSet->mvItems.size()-1) )
    {
        nPos--;
        nDelta *= -1;
        std::swap( bPropSmall, bPropGreat );
    }

    sal_uInt16          n;
    // now splitt the windows
    if ( nDelta < 0 )
    {
        if ( bGreat )
        {
            if ( bPropGreat )
            {
                tools::Long nTempDelta = nDelta;
                do
                {
                    n = nPos+1;
                    do
                    {
                        if ( nTempDelta )
                        {
                            rItems[n].mnPixSize++;
                            nTempDelta++;
                        }
                        n++;
                    }
                    while ( n < nMax );
                }
                while ( nTempDelta );
            }
            else
                rItems[nPos+1].mnPixSize -= nDelta;
        }

        if ( bSmall )
        {
            if ( bPropSmall )
            {
                do
                {
                    n = nPos+1;
                    do
                    {
                        if ( nDelta && rItems[n-1].mnPixSize )
                        {
                            rItems[n-1].mnPixSize--;
                            nDelta++;
                        }

                        n--;
                    }
                    while ( n > nMin );
                }
                while ( nDelta );
            }
            else
            {
                n = nPos+1;
                do
                {
                    if ( rItems[n-1].mnPixSize+nDelta < 0 )
                    {
                        nDelta += rItems[n-1].mnPixSize;
                        rItems[n-1].mnPixSize = 0;
                    }
                    else
                    {
                        rItems[n-1].mnPixSize += nDelta;
                        break;
                    }
                    n--;
                }
                while ( n > nMin );
            }
        }
    }
    else
    {
        if ( bGreat )
        {
            if ( bPropGreat )
            {
                tools::Long nTempDelta = nDelta;
                do
                {
                    n = nPos+1;
                    do
                    {
                        if ( nTempDelta )
                        {
                            rItems[n-1].mnPixSize++;
                            nTempDelta--;
                        }
                        n--;
                    }
                    while ( n > nMin );
                }
                while ( nTempDelta );
            }
            else
                rItems[nPos].mnPixSize += nDelta;
        }

        if ( bSmall )
        {
            if ( bPropSmall )
            {
                do
                {
                    n = nPos+1;
                    do
                    {
                        if ( nDelta && rItems[n].mnPixSize )
                        {
                            rItems[n].mnPixSize--;
                            nDelta--;
                        }

                        n++;
                    }
                    while ( n < nMax );
                }
                while ( nDelta );
            }
            else
            {
                n = nPos+1;
                do
                {
                    if ( rItems[n].mnPixSize-nDelta < 0 )
                    {
                        nDelta -= rItems[n].mnPixSize;
                        rItems[n].mnPixSize = 0;
                    }
                    else
                    {
                        rItems[n].mnPixSize -= nDelta;
                        break;
                    }
                    n++;
                }
                while ( n < nMax );
            }
        }
    }

    // update original sizes
    ImplCalcLogSize( rItems, nItems );

    ImplUpdate();
}

void SplitWindow::SetItemSize( sal_uInt16 nId, tools::Long nNewSize )
{
    sal_uInt16          nPos;
    ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );
    ImplSplitItem*  pItem;

    if ( !pSet )
        return;

    // check if size is changed
    pItem = &pSet->mvItems[nPos];
    if ( pItem->mnSize != nNewSize )
    {
        // set new size and re-calculate
        pItem->mnSize = nNewSize;
        pSet->mbCalcPix = true;
        ImplUpdate();
    }
}

tools::Long SplitWindow::GetItemSize( sal_uInt16 nId ) const
{
    sal_uInt16          nPos;
    ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );

    if ( pSet )
        return pSet->mvItems[nPos].mnSize;
    else
        return 0;
}

tools::Long SplitWindow::GetItemSize( sal_uInt16 nId, SplitWindowItemFlags nBits ) const
{
    sal_uInt16          nPos;
    ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );

    if ( pSet )
    {
        if ( nBits == pSet->mvItems[nPos].mnBits )
            return pSet->mvItems[nPos].mnSize;
        else
        {
            const_cast<SplitWindow*>(this)->ImplCalcLayout();

            tools::Long                nRelSize = 0;
            tools::Long                nPerSize = 0;
            size_t              nItems;
            SplitWindowItemFlags nTempBits;
            nItems = pSet->mvItems.size();
            std::vector< ImplSplitItem >& rItems = pSet->mvItems;
            for ( size_t i = 0; i < nItems; i++ )
            {
                if ( i == nPos )
                    nTempBits = nBits;
                else
                    nTempBits = rItems[i].mnBits;
                if ( nTempBits & SplitWindowItemFlags::RelativeSize )
                    nRelSize += rItems[i].mnPixSize;
                else if ( nTempBits & SplitWindowItemFlags::PercentSize )
                    nPerSize += rItems[i].mnPixSize;
            }
            nPerSize += nRelSize;
            if ( nBits & SplitWindowItemFlags::RelativeSize )
            {
                if ( nRelSize )
                    return (rItems[nPos].mnPixSize+(nRelSize/2))/nRelSize;
                else
                    return 1;
            }
            else if ( nBits & SplitWindowItemFlags::PercentSize )
            {
                if ( nPerSize )
                    return (rItems[nPos].mnPixSize*100)/nPerSize;
                else
                    return 1;
            }
            else
                return rItems[nPos].mnPixSize;
        }
    }
    else
        return 0;
}

void SplitWindow::SetItemSizeRange (sal_uInt16 nId, const Range& rRange)
{
    sal_uInt16 nPos;
    ImplSplitSet* pSet = ImplFindItem(mpBaseSet, nId, nPos);

    if (pSet != nullptr)
    {
        pSet->mvItems[nPos].mnMinSize = rRange.Min();
        pSet->mvItems[nPos].mnMaxSize = rRange.Max();
    }
}

sal_uInt16 SplitWindow::GetSet( sal_uInt16 nId ) const
{
    sal_uInt16          nPos;
    ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );

    if ( pSet )
        return pSet->mnId;
    else
        return 0;
}

bool SplitWindow::IsItemValid( sal_uInt16 nId ) const
{
    sal_uInt16          nPos;
    ImplSplitSet* pSet = mpBaseSet ? ImplFindItem(mpBaseSet, nId, nPos) : nullptr;

    return pSet != nullptr;
}

sal_uInt16 SplitWindow::GetItemId( vcl::Window* pWindow ) const
{
    return ImplFindItem( mpBaseSet, pWindow );
}

sal_uInt16 SplitWindow::GetItemId( const Point& rPos ) const
{
    return ImplFindItem( mpBaseSet, rPos, mbHorz, !mbBottomRight );
}

sal_uInt16 SplitWindow::GetItemPos( sal_uInt16 nId, sal_uInt16 nSetId ) const
{
    ImplSplitSet*   pSet = ImplFindSet( mpBaseSet, nSetId );
    sal_uInt16          nPos = SPLITWINDOW_ITEM_NOTFOUND;

    if ( pSet )
    {
        for ( size_t i = 0; i < pSet->mvItems.size(); i++ )
        {
            if ( pSet->mvItems[i].mnId == nId )
            {
                nPos = i;
                break;
            }
        }
    }

    return nPos;
}

sal_uInt16 SplitWindow::GetItemId( sal_uInt16 nPos ) const
{
    ImplSplitSet* pSet = ImplFindSet( mpBaseSet, 0/*nSetId*/ );
    if ( pSet && (nPos < pSet->mvItems.size()) )
        return pSet->mvItems[nPos].mnId;
    else
        return 0;
}

sal_uInt16 SplitWindow::GetItemCount( sal_uInt16 nSetId ) const
{
    ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
    if ( pSet )
        return pSet->mvItems.size();
    else
        return 0;
}

void SplitWindow::ImplNewAlign()
{
    switch ( meAlign )
    {
    case WindowAlign::Top:
        mbHorz        = true;
        mbBottomRight = false;
        break;
    case WindowAlign::Bottom:
        mbHorz        = true;
        mbBottomRight = true;
        break;
    case WindowAlign::Left:
        mbHorz        = false;
        mbBottomRight = false;
        break;
    case WindowAlign::Right:
        mbHorz        = false;
        mbBottomRight = true;
        break;
    }

    if ( mnWinStyle & WB_BORDER )
    {
        ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
                        mnRightBorder, mnBottomBorder );
    }

    if ( IsReallyVisible() && IsUpdateMode() )
        Invalidate();
    ImplUpdate();
}

void SplitWindow::SetAlign( WindowAlign eNewAlign )
{
    if ( meAlign != eNewAlign )
    {
        meAlign = eNewAlign;
        ImplNewAlign();
    }
}

void SplitWindow::ShowFadeInHideButton()
{
    mbFadeIn = true;
    ImplUpdate();
}

void SplitWindow::ShowFadeOutButton()
{
    mbFadeOut = true;
    ImplUpdate();
}

tools::Long SplitWindow::GetFadeInSize() const
{
    tools::Long n = 0;

    if ( mbHorz )
        n = mnTopBorder+mnBottomBorder;
    else
        n = mnLeftBorder+mnRightBorder;

    return n+SPLITWIN_SPLITSIZE+SPLITWIN_SPLITSIZEEX-2;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=98 H=89 G=93

¤ Dauer der Verarbeitung: 0.51 Sekunden  (vorverarbeitet am  2026-05-05) ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge