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

--> maximum size reached

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

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.14 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


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