summaryrefslogtreecommitdiffstats
path: root/vcl/source/window/splitwin.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/window/splitwin.cxx')
-rw-r--r--vcl/source/window/splitwin.cxx2717
1 files changed, 2717 insertions, 0 deletions
diff --git a/vcl/source/window/splitwin.cxx b/vcl/source/window/splitwin.cxx
new file mode 100644
index 0000000000..f2bba6b2ce
--- /dev/null
+++ b/vcl/source/window/splitwin.cxx
@@ -0,0 +1,2717 @@
+/* -*- 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 );
+}
+
+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:
+ aSize.AdjustHeight(nDelta );
+ break;
+ case WindowAlign::Bottom:
+ aSize.AdjustHeight(nDelta );
+ break;
+ case WindowAlign::Left:
+ aSize.AdjustWidth(nDelta );
+ break;
+ case WindowAlign::Right:
+ 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, false, false, false);
+
+ 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.clear();
+ pOrgParent.clear();
+}
+
+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: */