/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #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 mpSet; VclPtr mpWindow; VclPtr 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 && nSize0 && 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::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::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 pWindow = pItem->mpWindow; VclPtr 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(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: */