Quelle splitwin.cxx
Sprache: C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <string.h>
#include <o3tl/safeint.hxx>
#include <sal/log.hxx>
#include <vcl/event.hxx>
#include <vcl/wall.hxx>
#include <vcl/help.hxx>
#include <vcl/splitwin.hxx>
#include <vcl/settings.hxx>
#include <vcl/ptrstyle.hxx>
#include <svdata.hxx>
#include <strings.hrc>
#define SPLITWIN_SPLITSIZEEX 4
#define SPLITWIN_SPLITSIZEAUTOHIDE 72
#define SPLITWIN_SPLITSIZEFADE 72
#define SPLIT_HORZ (sal_uInt16(0x0001))
#define SPLIT_VERT (sal_uInt16(0x0002))
#define SPLIT_WINDOW (sal_uInt16(0x0004))
#define SPLIT_NOSPLIT (sal_uInt16(0x8000))
namespace {
class ImplSplitItem
{
public :
ImplSplitItem();
tools::
Long mnSize;
tools::
Long mnPixSize;
tools::
Long mnLeft;
tools::
Long mnTop;
tools::
Long mnWidth;
tools::
Long mnHeight;
tools::
Long mnSplitPos;
tools::
Long mnSplitSize;
tools::
Long mnOldSplitPos;
tools::
Long mnOldSplitSize;
tools::
Long mnOldWidth;
tools::
Long mnOldHeight;
std::unique_ptr<ImplSplitSet> mpSet;
VclPtr<vcl::Window> mpWindow;
VclPtr<vcl::Window> mpOrgParent;
sal_uInt16 mnId;
SplitWindowItemFlags mnBits;
bool mbFixed;
bool mbSubSize;
/// Minimal width or height of the item. -1 means no restriction.
tools::
Long mnMinSize;
/// Maximal width or height of the item. -1 means no restriction.
tools::
Long mnMaxSize;
};
}
class ImplSplitSet
{
public :
ImplSplitSet();
std::vector< ImplSplitItem > mvItems;
tools::
Long mnLastSize;
tools::
Long mnSplitSize;
sal_uInt16 mnId;
bool mbCalcPix;
};
ImplSplitItem::ImplSplitItem()
: mnSize(0)
, mnPixSize(0)
, mnLeft(0)
, mnTop(0)
, mnWidth(0)
, mnHeight(0)
, mnSplitPos(0)
, mnSplitSize(0)
, mnOldSplitPos(0)
, mnOldSplitSize(0)
, mnOldWidth(0)
, mnOldHeight(0)
, mnId(0)
, mnBits(SplitWindowItemFlags::NONE)
, mbFixed(
false )
, mbSubSize(
false )
, mnMinSize(-1)
, mnMaxSize(-1)
{
}
ImplSplitSet::ImplSplitSet() :
mnLastSize( 0 ),
mnSplitSize( SPLITWIN_SPLITSIZE ),
mnId( 0 ),
mbCalcPix(
true )
{
}
/** Check whether the given size is inside the valid range defined by
[rItem.mnMinSize,rItem.mnMaxSize]. When it is not inside it then return
the upper or lower bound, respectively. Otherwise return the given size
unmodified.
Note that either mnMinSize and/or mnMaxSize can be -1 in which case the
size has not lower or upper bound.
*/
namespace {
tools::
Long ValidateSize (
const tools::
Long nSize,
const ImplSplitItem & rItem)
{
if (rItem.mnMinSize>=0 && nSize<rItem.mnMinSize)
return rItem.mnMinSize;
else if (rItem.mnMaxSize>0 && nSize>rItem.mnMaxSize)
return rItem.mnMaxSize;
else
return nSize;
}
}
static void ImplCalcBorder( WindowAlign eAlign,
tools::
Long & rLeft, tools::
Long & rTop,
tools::
Long & rRight, tools::
Long & rBottom )
{
switch ( eAlign )
{
case WindowAlign::Top:
rLeft = 2;
rTop = 2;
rRight = 2;
rBottom = 0;
break ;
case WindowAlign::Left:
rLeft = 0;
rTop = 2;
rRight = 2;
rBottom = 2;
break ;
case WindowAlign::Bottom:
rLeft = 2;
rTop = 0;
rRight = 2;
rBottom = 2;
break ;
default :
rLeft = 0;
rTop = 2;
rRight = 2;
rBottom = 2;
break ;
}
}
void SplitWindow::ImplDrawBorder(vcl::RenderContext& rRenderContext)
{
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSetti
ngs();
tools::Long nDX = mnDX;
tools::Long nDY = mnDY;
switch (meAlign)
{
case WindowAlign::Bottom:
break ;
case WindowAlign::Top:
break ;
case WindowAlign::Left:
break ;
default :
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(0, 0), Point( 0, nDY));
rRenderContext.DrawLine(Point(0, nDY), Point(nDX, nDY));
}
}
void SplitWindow::ImplDrawBorderLine(vcl::RenderContext& rRenderContext)
{
if (!mbFadeOut)
return ;
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
tools::Long nDX = mnDX;
tools::Long nDY = mnDY;
switch (meAlign)
{
case WindowAlign::Left:
rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, nDY-2 ) );
rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN, nDY-3 ) );
break ;
case WindowAlign::Right:
break ;
case WindowAlign::Top:
rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN-1 ) );
rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN ) );
break ;
case WindowAlign::Bottom:
rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
rRenderContext.DrawLine( Point( 0, 5 ), Point( nDX-1, 5 ) );
rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
rRenderContext.DrawLine( Point( 0, SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, SPLITWIN_SPLITSIZEEXLN ) );
break ;
}
}
static ImplSplitSet* ImplFindSet( ImplSplitSet* pSet, sal_uInt16 nId )
{
if ( pSet->mnId == nId )
return pSet;
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
for ( const auto & rItem : rItems )
{
if ( rItem.mnId == nId )
return rItem.mpSet.get();
}
for ( auto & rItem : rItems )
{
if ( rItem.mpSet )
{
ImplSplitSet* pFindSet = ImplFindSet( rItem.mpSet.get(), nId );
if ( pFindSet )
return pFindSet;
}
}
return nullptr;
}
static ImplSplitSet* ImplFindItem( ImplSplitSet* pSet, sal_uInt16 nId, sal_uInt16& rPos )
{
size_t nItems = pSet->mvItems.size();
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
for ( size_t i = 0; i < nItems; i++ )
{
if ( rItems[i].mnId == nId )
{
rPos = i;
return pSet;
}
}
for ( auto & rItem : rItems )
{
if ( rItem.mpSet )
{
ImplSplitSet* pFindSet = ImplFindItem( rItem.mpSet.get(), nId, rPos );
if ( pFindSet )
return pFindSet;
}
}
return nullptr;
}
static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, vcl::Window* pWindow )
{
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
for ( auto & rItem : rItems )
{
if ( rItem.mpWindow == pWindow )
return rItem.mnId;
else
{
if ( rItem.mpSet )
{
sal_uInt16 nId = ImplFindItem( rItem.mpSet.get(), pWindow );
if ( nId )
return nId;
}
}
}
return 0;
}
static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, const Point& rPos,
bool bRows, bool bDown = true )
{
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
for ( auto & rItem : rItems )
{
if ( rItem.mnWidth && rItem.mnHeight )
{
Point aPoint( rItem.mnLeft, rItem.mnTop );
Size aSize( rItem.mnWidth, rItem.mnHeight );
tools::Rectangle aRect( aPoint, aSize );
if ( bRows )
{
if ( bDown )
aRect.AdjustBottom(pSet->mnSplitSize );
else
aRect.AdjustTop( -(pSet->mnSplitSize) );
}
else
{
if ( bDown )
aRect.AdjustRight(pSet->mnSplitSize );
else
aRect.AdjustLeft( -(pSet->mnSplitSize) );
}
if ( aRect.Contains( rPos ) )
{
if ( rItem.mpSet && !rItem.mpSet->mvItems.empty() )
{
return ImplFindItem( rItem.mpSet.get(), rPos,
!(rItem.mnBits & SplitWindowItemFlags::ColSet) );
}
else
return rItem.mnId;
}
}
}
return 0;
}
static void ImplCalcSet( ImplSplitSet* pSet,
tools::Long nSetLeft, tools::Long nSetTop,
tools::Long nSetWidth, tools::Long nSetHeight,
bool bRows, bool bDown = true )
{
if ( pSet->mvItems.empty() )
return ;
sal_uInt16 nMins;
sal_uInt16 nCalcItems;
size_t nItems = pSet->mvItems.size();
sal_uInt16 nAbsItems;
tools::Long nCalcSize;
tools::Long nPos;
tools::Long nMaxPos;
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
bool bEmpty;
// calculate sizes
if ( bRows )
nCalcSize = nSetHeight;
else
nCalcSize = nSetWidth;
nCalcSize -= (rItems.size()-1)*pSet->mnSplitSize;
if ( pSet->mbCalcPix || (pSet->mnLastSize != nCalcSize) )
{
tools::Long nPercentFactor = 10;
tools::Long nRelCount = 0;
tools::Long nPercent = 0;
tools::Long nRelPercent = 0;
tools::Long nAbsSize = 0;
tools::Long nCurSize = 0;
for ( const auto & rItem : rItems )
{
if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
nRelCount += rItem.mnSize;
else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
nPercent += rItem.mnSize;
else
nAbsSize += rItem.mnSize;
}
// map relative values to percentages (percentage here one tenth of a percent)
nPercent *= nPercentFactor;
if ( nRelCount )
{
tools::Long nRelPercentBase = 1000;
while ( (nRelCount > nRelPercentBase) && (nPercentFactor < 100000) )
{
nRelPercentBase *= 10;
nPercentFactor *= 10;
}
if ( nPercent < nRelPercentBase )
{
nRelPercent = (nRelPercentBase-nPercent)/nRelCount;
nPercent += nRelPercent*nRelCount;
}
else
nRelPercent = 0;
}
if ( !nPercent )
nPercent = 1;
tools::Long nSizeDelta = nCalcSize-nAbsSize;
for ( auto & rItem : rItems )
{
if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
{
if ( nSizeDelta <= 0 )
rItem.mnPixSize = 0;
else
rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nRelPercent)/nPercent;
}
else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
{
if ( nSizeDelta <= 0 )
rItem.mnPixSize = 0;
else
rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nPercentFactor)/nPercent;
}
else
rItem.mnPixSize = rItem.mnSize;
nCurSize += rItem.mnPixSize;
}
pSet->mbCalcPix = false ;
pSet->mnLastSize = nCalcSize;
// adapt window
nSizeDelta = nCalcSize-nCurSize;
if ( nSizeDelta )
{
nAbsItems = 0;
tools::Long nSizeWinSize = 0;
// first resize absolute items relative
for ( const auto & rItem : rItems )
{
if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
{
nAbsItems++;
nSizeWinSize += rItem.mnPixSize;
}
}
// do not compensate rounding errors here
if ( (nAbsItems < o3tl::make_unsigned(std::abs( nSizeDelta ))) && nSizeWinSize )
{
tools::Long nNewSizeWinSize = 0;
for ( auto & rItem : rItems )
{
if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
{
rItem.mnPixSize += (nSizeDelta*rItem.mnPixSize)/nSizeWinSize;
nNewSizeWinSize += rItem.mnPixSize;
}
}
nSizeDelta -= nNewSizeWinSize-nSizeWinSize;
}
// compensate rounding errors now
sal_uInt16 j = 0;
nMins = 0;
while ( nSizeDelta && (nItems != nMins) )
{
// determine which items we can calculate
nCalcItems = 0;
while ( !nCalcItems )
{
for ( auto & rItem : rItems )
{
rItem.mbSubSize = false ;
if ( j >= 2 )
rItem.mbSubSize = true ;
else
{
if ( (nSizeDelta > 0) || rItem.mnPixSize )
{
if ( j >= 1 )
rItem.mbSubSize = true ;
else
{
if ( (j == 0) && (rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
rItem.mbSubSize = true ;
}
}
}
if ( rItem.mbSubSize )
nCalcItems++;
}
j++;
}
// subtract size of individual items
tools::Long nErrorSum = nSizeDelta % nCalcItems;
tools::Long nCurSizeDelta = nSizeDelta / nCalcItems;
nMins = 0;
for ( auto & rItem : rItems )
{
if ( rItem.mbSubSize )
{
tools::Long * pSize = &(rItem.mnPixSize);
tools::Long nTempErr;
if ( nErrorSum )
{
if ( nErrorSum < 0 )
nTempErr = -1;
else
nTempErr = 1;
}
else
nTempErr = 0;
if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 )
{
tools::Long nTemp = *pSize;
if ( nTemp )
{
*pSize -= nTemp;
nSizeDelta += nTemp;
}
nMins++;
}
else
{
*pSize += nCurSizeDelta;
nSizeDelta -= nCurSizeDelta;
if ( nTempErr && (*pSize || (nTempErr > 0)) )
{
*pSize += nTempErr;
nSizeDelta -= nTempErr;
nErrorSum -= nTempErr;
}
}
}
}
}
}
}
// calculate maximum size
if ( bRows )
{
nPos = nSetTop;
if ( !bDown )
nMaxPos = nSetTop-nSetHeight;
else
nMaxPos = nSetTop+nSetHeight;
}
else
{
nPos = nSetLeft;
if ( !bDown )
nMaxPos = nSetLeft-nSetWidth;
else
nMaxPos = nSetLeft+nSetWidth;
}
// order windows and adapt values
for ( size_t i = 0; i < nItems; i++ )
{
rItems[i].mnOldSplitPos = rItems[i].mnSplitPos;
rItems[i].mnOldSplitSize = rItems[i].mnSplitSize;
rItems[i].mnOldWidth = rItems[i].mnWidth;
rItems[i].mnOldHeight = rItems[i].mnHeight;
bEmpty = false ;
if ( bDown )
{
if ( nPos+rItems[i].mnPixSize > nMaxPos )
bEmpty = true ;
}
else
{
nPos -= rItems[i].mnPixSize;
if ( nPos < nMaxPos )
bEmpty = true ;
}
if ( bEmpty )
{
rItems[i].mnWidth = 0;
rItems[i].mnHeight = 0;
rItems[i].mnSplitSize = 0;
}
else
{
if ( bRows )
{
rItems[i].mnLeft = nSetLeft;
rItems[i].mnTop = nPos;
rItems[i].mnWidth = nSetWidth;
rItems[i].mnHeight = rItems[i].mnPixSize;
}
else
{
rItems[i].mnLeft = nPos;
rItems[i].mnTop = nSetTop;
rItems[i].mnWidth = rItems[i].mnPixSize;
rItems[i].mnHeight = nSetHeight;
}
if ( i > nItems-1 )
rItems[i].mnSplitSize = 0;
else
{
rItems[i].mnSplitSize = pSet->mnSplitSize;
if ( bDown )
{
rItems[i].mnSplitPos = nPos+rItems[i].mnPixSize;
if ( rItems[i].mnSplitPos+rItems[i].mnSplitSize > nMaxPos )
rItems[i].mnSplitSize = nMaxPos-rItems[i].mnSplitPos;
}
else
{
rItems[i].mnSplitPos = nPos-pSet->mnSplitSize;
if ( rItems[i].mnSplitPos < nMaxPos )
rItems[i].mnSplitSize = rItems[i].mnSplitPos+pSet->mnSplitSize-nMaxPos;
}
}
}
if ( !bDown )
nPos -= pSet->mnSplitSize;
else
nPos += rItems[i].mnPixSize+pSet->mnSplitSize;
}
// calculate Sub-Set's
for ( auto & rItem : rItems )
{
if ( rItem.mpSet && rItem.mnWidth && rItem.mnHeight )
{
ImplCalcSet( rItem.mpSet.get(),
rItem.mnLeft, rItem.mnTop,
rItem.mnWidth, rItem.mnHeight,
!(rItem.mnBits & SplitWindowItemFlags::ColSet) );
}
}
// set fixed
for ( auto & rItem : rItems )
{
rItem.mbFixed = false ;
if ( rItem.mnBits & SplitWindowItemFlags::Fixed )
rItem.mbFixed = true ;
else
{
// this item is also fixed if Child-Set is available,
// if a child is fixed
if ( rItem.mpSet )
{
for ( auto const & j: rItem.mpSet->mvItems )
{
if ( j.mbFixed )
{
rItem.mbFixed = true ;
break ;
}
}
}
}
}
}
void SplitWindow::ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, bool bHide,
bool bRows )
{
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
if ( pWindow->IsReallyVisible() && pWindow->IsUpdateMode() && pWindow->mbInvalidate )
{
for ( const auto & rItem : rItems )
{
if ( rItem.mnSplitSize )
{
// invalidate all, if applicable or only a small part
if ( (rItem.mnOldSplitPos != rItem.mnSplitPos) ||
(rItem.mnOldSplitSize != rItem.mnSplitSize) ||
(rItem.mnOldWidth != rItem.mnWidth) ||
(rItem.mnOldHeight != rItem.mnHeight) )
{
tools::Rectangle aRect;
// invalidate old rectangle
if ( bRows )
{
aRect.SetLeft( rItem.mnLeft );
aRect.SetRight( rItem.mnLeft+rItem.mnOldWidth-1 );
aRect.SetTop( rItem.mnOldSplitPos );
aRect.SetBottom( aRect.Top() + rItem.mnOldSplitSize );
}
else
{
aRect.SetTop( rItem.mnTop );
aRect.SetBottom( rItem.mnTop+rItem.mnOldHeight-1 );
aRect.SetLeft( rItem.mnOldSplitPos );
aRect.SetRight( aRect.Left() + rItem.mnOldSplitSize );
}
pWindow->Invalidate( aRect );
// invalidate new rectangle
if ( bRows )
{
aRect.SetLeft( rItem.mnLeft );
aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
aRect.SetTop( rItem.mnSplitPos );
aRect.SetBottom( aRect.Top() + rItem.mnSplitSize );
}
else
{
aRect.SetTop( rItem.mnTop );
aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
aRect.SetLeft( rItem.mnSplitPos );
aRect.SetRight( aRect.Left() + rItem.mnSplitSize );
}
pWindow->Invalidate( aRect );
// invalidate complete set, as these areas
// are not cluttered by windows
if ( rItem.mpSet && rItem.mpSet->mvItems.empty() )
{
aRect.SetLeft( rItem.mnLeft );
aRect.SetTop( rItem.mnTop );
aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
pWindow->Invalidate( aRect );
}
}
}
}
}
// position windows
for ( auto & rItem : rItems )
{
if ( rItem.mpSet )
{
bool bTempHide = bHide;
if ( !rItem.mnWidth || !rItem.mnHeight )
bTempHide = true ;
ImplCalcSet2( pWindow, rItem.mpSet.get(), bTempHide,
!(rItem.mnBits & SplitWindowItemFlags::ColSet) );
}
else
{
if ( rItem.mnWidth && rItem.mnHeight && !bHide )
{
Point aPos( rItem.mnLeft, rItem.mnTop );
Size aSize( rItem.mnWidth, rItem.mnHeight );
rItem.mpWindow->SetPosSizePixel( aPos, aSize );
}
else
rItem.mpWindow->Hide();
}
}
// show windows and reset flag
for ( auto & rItem : rItems )
{
if ( rItem.mpWindow && rItem.mnWidth && rItem.mnHeight && !bHide )
rItem.mpWindow->Show();
}
}
static void ImplCalcLogSize( std::vector< ImplSplitItem > & rItems, size_t nItems )
{
// update original sizes
size_t i;
tools::Long nRelSize = 0;
tools::Long nPerSize = 0;
for ( i = 0; i < nItems; i++ )
{
if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
nRelSize += rItems[i].mnPixSize;
else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
nPerSize += rItems[i].mnPixSize;
}
nPerSize += nRelSize;
for ( i = 0; i < nItems; i++ )
{
if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
{
if ( nRelSize )
rItems[i].mnSize = (rItems[i].mnPixSize+(nRelSize/2))/nRelSize;
else
rItems[i].mnSize = 1;
}
else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
{
if ( nPerSize )
rItems[i].mnSize = (rItems[i].mnPixSize*100)/nPerSize;
else
rItems[i].mnSize = 1;
}
else
rItems[i].mnSize = rItems[i].mnPixSize;
}
}
static void ImplDrawSplit(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet, bool bRows, bool bDown)
{
if (pSet->mvItems.empty())
return ;
size_t nItems = pSet->mvItems.size();
tools::Long nPos;
tools::Long nTop;
tools::Long nBottom;
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
for (size_t i = 0; i < nItems-1; i++)
{
if (rItems[i].mnSplitSize)
{
nPos = rItems[i].mnSplitPos;
tools::Long nItemSplitSize = rItems[i].mnSplitSize;
tools::Long nSplitSize = pSet->mnSplitSize;
if (bRows)
{
nTop = rItems[i].mnLeft;
nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
if (bDown || (nItemSplitSize >= nSplitSize))
{
rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
rRenderContext.DrawLine(Point(nTop, nPos + 1), Point(nBottom, nPos + 1));
}
nPos += nSplitSize-2;
if ((!bDown && (nItemSplitSize >= 2)) ||
(bDown && (nItemSplitSize >= nSplitSize - 1)))
{
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
}
nPos++;
if (!bDown || (nItemSplitSize >= nSplitSize))
{
rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
}
}
else
{
nTop = rItems[i].mnTop;
nBottom = rItems[i].mnTop+pSet->mvItems[i].mnHeight-1;
if (bDown || (nItemSplitSize >= nSplitSize))
{
rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
rRenderContext.DrawLine(Point(nPos + 1, nTop), Point(nPos+1, nBottom));
}
nPos += pSet->mnSplitSize - 2;
if ((!bDown && (nItemSplitSize >= 2)) ||
(bDown && (nItemSplitSize >= nSplitSize - 1)))
{
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
}
nPos++;
if (!bDown || (nItemSplitSize >= nSplitSize))
{
rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
}
}
}
}
for ( auto & rItem : rItems )
{
if (rItem.mpSet && rItem.mnWidth && rItem.mnHeight)
{
ImplDrawSplit(rRenderContext, rItem.mpSet.get(), !(rItem.mnBits & SplitWindowItemFlags::ColSet), true /*bDown*/);
}
}
}
sal_uInt16 SplitWindow::ImplTestSplit( ImplSplitSet* pSet, const Point& rPos,
tools::Long & rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos,
bool bRows )
{
if ( pSet->mvItems.empty() )
return 0;
sal_uInt16 nSplitTest;
size_t nItems = pSet->mvItems.size();
tools::Long nMPos1;
tools::Long nMPos2;
tools::Long nPos;
tools::Long nTop;
tools::Long nBottom;
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
if ( bRows )
{
nMPos1 = rPos.X();
nMPos2 = rPos.Y();
}
else
{
nMPos1 = rPos.Y();
nMPos2 = rPos.X();
}
for ( size_t i = 0; i < nItems-1; i++ )
{
if ( rItems[i].mnSplitSize )
{
if ( bRows )
{
nTop = rItems[i].mnLeft;
nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
}
else
{
nTop = rItems[i].mnTop;
nBottom = rItems[i].mnTop+rItems[i].mnHeight-1;
}
nPos = rItems[i].mnSplitPos;
if ( (nMPos1 >= nTop) && (nMPos1 <= nBottom) &&
(nMPos2 >= nPos) && (nMPos2 <= nPos+rItems[i].mnSplitSize) )
{
if ( !rItems[i].mbFixed && !rItems[i+1].mbFixed )
{
rMouseOff = nMPos2-nPos;
*ppFoundSet = pSet;
rFoundPos = i;
if ( bRows )
return SPLIT_VERT;
else
return SPLIT_HORZ;
}
else
return SPLIT_NOSPLIT;
}
}
}
for ( auto & rItem : rItems )
{
if ( rItem.mpSet )
{
nSplitTest = ImplTestSplit( rItem.mpSet.get(), rPos,
rMouseOff, ppFoundSet, rFoundPos,
!(rItem.mnBits & SplitWindowItemFlags::ColSet) );
if ( nSplitTest )
return nSplitTest;
}
}
return 0;
}
sal_uInt16 SplitWindow::ImplTestSplit( const SplitWindow* pWindow, const Point& rPos,
tools::Long & rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos )
{
// Resizable SplitWindow should be treated different
if ( pWindow->mnWinStyle & WB_SIZEABLE )
{
tools::Long nTPos;
tools::Long nPos;
tools::Long nBorder;
if ( pWindow->mbHorz )
{
if ( pWindow->mbBottomRight )
{
nBorder = pWindow->mnBottomBorder;
nPos = 0;
}
else
{
nBorder = pWindow->mnTopBorder;
nPos = pWindow->mnDY-nBorder;
}
nTPos = rPos.Y();
}
else
{
if ( pWindow->mbBottomRight )
{
nBorder = pWindow->mnRightBorder;
nPos = 0;
}
else
{
nBorder = pWindow->mnLeftBorder;
nPos = pWindow->mnDX-nBorder;
}
nTPos = rPos.X();
}
tools::Long nSplitSize = pWindow->mpMainSet->mnSplitSize-2;
if (pWindow->mbFadeOut)
nSplitSize += SPLITWIN_SPLITSIZEEXLN;
if ( !pWindow->mbBottomRight )
nPos -= nSplitSize;
if ( (nTPos >= nPos) && (nTPos <= nPos+nSplitSize+nBorder) )
{
rMouseOff = nTPos-nPos;
*ppFoundSet = pWindow->mpMainSet.get();
if ( !pWindow->mpMainSet->mvItems.empty() )
rFoundPos = pWindow->mpMainSet->mvItems.size() - 1;
else
rFoundPos = 0;
if ( pWindow->mbHorz )
return SPLIT_VERT | SPLIT_WINDOW;
else
return SPLIT_HORZ | SPLIT_WINDOW;
}
}
return ImplTestSplit( pWindow->mpMainSet.get(), rPos, rMouseOff, ppFoundSet, rFoundPos,
pWindow->mbHorz );
}
void SplitWindow::ImplDrawSplitTracking(const Point& rPos)
{
tools::Rectangle aRect;
if (mnSplitTest & SPLIT_HORZ)
{
aRect.SetTop( maDragRect.Top() );
aRect.SetBottom( maDragRect.Bottom() );
aRect.SetLeft( rPos.X() );
aRect.SetRight( aRect.Left() + mpSplitSet->mnSplitSize - 1 );
if (!(mnWinStyle & WB_NOSPLITDRAW))
aRect.AdjustRight( -1 );
if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
{
aRect.AdjustLeft(SPLITWIN_SPLITSIZEEXLN );
aRect.AdjustRight(SPLITWIN_SPLITSIZEEXLN );
}
}
else
{
aRect.SetLeft( maDragRect.Left() );
aRect.SetRight( maDragRect.Right() );
aRect.SetTop( rPos.Y() );
aRect.SetBottom( aRect.Top() + mpSplitSet->mnSplitSize - 1 );
if (!(mnWinStyle & WB_NOSPLITDRAW))
aRect.AdjustBottom( -1 );
if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
{
aRect.AdjustTop(SPLITWIN_SPLITSIZEEXLN );
aRect.AdjustBottom(SPLITWIN_SPLITSIZEEXLN );
}
}
ShowTracking(aRect, ShowTrackFlags::Split);
}
void SplitWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
mpMainSet.reset(new ImplSplitSet());
mpBaseSet = mpMainSet.get();
mpSplitSet = nullptr;
mpLastSizes = nullptr;
mnDX = 0;
mnDY = 0;
mnLeftBorder = 0;
mnTopBorder = 0;
mnRightBorder = 0;
mnBottomBorder = 0;
mnMaxSize = 0;
mnMouseOff = 0;
meAlign = WindowAlign::Top;
mnWinStyle = nStyle;
mnSplitTest = 0;
mnSplitPos = 0;
mnMouseModifier = 0;
mnMStartPos = 0;
mnMSplitPos = 0;
mbDragFull = false ;
mbHorz = true ;
mbBottomRight = false ;
mbCalc = false ;
mbRecalc = true ;
mbInvalidate = true ;
mbFadeIn = false ;
mbFadeOut = false ;
mbFadeInDown = false ;
mbFadeOutDown = false ;
mbFadeInPressed = false ;
mbFadeOutPressed = false ;
mbFadeNoButtonMode = false ;
if ( nStyle & WB_NOSPLITDRAW )
{
mpMainSet->mnSplitSize -= 2;
mbInvalidate = false ;
}
if ( nStyle & WB_BORDER )
{
ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
mnRightBorder, mnBottomBorder );
}
else
{
mnLeftBorder = 0;
mnTopBorder = 0;
mnRightBorder = 0;
mnBottomBorder = 0;
}
DockingWindow::ImplInit( pParent, (nStyle | WB_CLIPCHILDREN) & ~(WB_BORDER | WB_SIZEABLE) );
ImplInitSettings();
}
void SplitWindow::ImplInitSettings()
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
Color aColor;
if ( IsControlBackground() )
aColor = GetControlBackground();
else if ( Window::GetStyle() & WB_3DLOOK )
aColor = rStyleSettings.GetFaceColor();
else
aColor = rStyleSettings.GetWindowColor();
SetBackground( aColor );
}
SplitWindow::SplitWindow( vcl::Window* pParent, WinBits nStyle ) :
DockingWindow( WindowType::SPLITWINDOW, "vcl::SplitWindow maLayoutIdle" )
{
ImplInit( pParent, nStyle );
// ensure there is sufficient border reserved to fit the splitter into
set_border_width(SPLITWIN_SPLITSIZE);
}
SplitWindow::~SplitWindow()
{
disposeOnce();
}
void SplitWindow::dispose()
{
// delete Sets
mpMainSet.reset();
DockingWindow::dispose();
}
void SplitWindow::ImplSetWindowSize( tools::Long nDelta )
{
if ( !nDelta )
return ;
Size aSize = GetSizePixel();
switch ( meAlign )
{
case WindowAlign::Top:
aSize.AdjustHeight(nDelta );
SetSizePixel( aSize );
break ;
case WindowAlign::Bottom:
{
maDragRect.AdjustTop(nDelta );
Point aPos = GetPosPixel();
aPos.AdjustY( -nDelta );
aSize.AdjustHeight(nDelta );
SetPosSizePixel( aPos, aSize );
break ;
}
case WindowAlign::Left:
aSize.AdjustWidth(nDelta );
SetSizePixel( aSize );
break ;
case WindowAlign::Right:
default :
{
maDragRect.AdjustLeft(nDelta );
Point aPos = GetPosPixel();
aPos.AdjustX( -nDelta );
aSize.AdjustWidth(nDelta );
SetPosSizePixel( aPos, aSize );
break ;
}
}
SplitResize();
}
Size SplitWindow::CalcLayoutSizePixel( const Size& aNewSize )
{
Size aSize( aNewSize );
tools::Long nSplitSize = mpMainSet->mnSplitSize-2;
if (mbFadeOut)
nSplitSize += SPLITWIN_SPLITSIZEEXLN;
// if the window is sizeable and if it does not contain a relative window,
// the size is determined according to MainSet
if ( mnWinStyle & WB_SIZEABLE )
{
tools::Long nCalcSize = 0;
std::vector< ImplSplitItem* >::size_type i;
for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
{
if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
break ;
else
nCalcSize += mpMainSet->mvItems[i].mnSize;
}
if ( i == mpMainSet->mvItems.size() )
{
tools::Long nDelta = 0;
tools::Long nCurSize;
if ( mbHorz )
nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder;
else
nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder;
nCurSize -= nSplitSize;
nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
nDelta = nCalcSize-nCurSize;
if ( !nDelta )
return aSize;
switch ( meAlign )
{
case WindowAlign::Top:
case WindowAlign::Bottom:
aSize.AdjustHeight(nDelta );
break ;
case WindowAlign::Right:
case WindowAlign::Left:
default :
aSize.AdjustWidth(nDelta );
break ;
}
}
}
return aSize;
}
void SplitWindow::ImplCalcLayout()
{
if ( !mbCalc || !mbRecalc || mpMainSet->mvItems.empty() )
return ;
tools::Long nSplitSize = mpMainSet->mnSplitSize-2;
if (mbFadeOut)
nSplitSize += SPLITWIN_SPLITSIZEEXLN;
// if the window is sizeable and if it does not contain a relative window,
// the size is determined according to MainSet
if ( mnWinStyle & WB_SIZEABLE )
{
tools::Long nCalcSize = 0;
std::vector<ImplSplitItem *>::size_type i;
for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
{
if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
break ;
else
nCalcSize += mpMainSet->mvItems[i].mnSize;
}
if ( i == mpMainSet->mvItems.size() )
{
tools::Long nCurSize;
if ( mbHorz )
nCurSize = mnDY-mnTopBorder-mnBottomBorder;
else
nCurSize = mnDX-mnLeftBorder-mnRightBorder;
nCurSize -= nSplitSize;
nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
mbRecalc = false ;
ImplSetWindowSize( nCalcSize-nCurSize );
mbRecalc = true ;
}
}
if ( (mnDX <= 0) || (mnDY <= 0) )
return ;
// pre-calculate sizes/position
tools::Long nL;
tools::Long nT;
tools::Long nW;
tools::Long nH;
if ( mbHorz )
{
if ( mbBottomRight )
nT = mnDY-mnBottomBorder;
else
nT = mnTopBorder;
nL = mnLeftBorder;
}
else
{
if ( mbBottomRight )
nL = mnDX-mnRightBorder;
else
nL = mnLeftBorder;
nT = mnTopBorder;
}
nW = mnDX-mnLeftBorder-mnRightBorder;
nH = mnDY-mnTopBorder-mnBottomBorder;
if ( mnWinStyle & WB_SIZEABLE )
{
if ( mbHorz )
nH -= nSplitSize;
else
nW -= nSplitSize;
}
// calculate sets recursive
ImplCalcSet( mpMainSet.get(), nL, nT, nW, nH, mbHorz, !mbBottomRight );
ImplCalcSet2( this , mpMainSet.get(), false , mbHorz );
mbCalc = false ;
}
void SplitWindow::ImplUpdate()
{
mbCalc = true ;
if ( IsReallyShown() && IsUpdateMode() && mbRecalc )
{
if ( !mpMainSet->mvItems.empty() )
ImplCalcLayout();
else
Invalidate();
}
}
void SplitWindow::ImplSplitMousePos( Point& rMousePos )
{
if ( mnSplitTest & SPLIT_HORZ )
{
rMousePos.AdjustX( -mnMouseOff );
if ( rMousePos.X() < maDragRect.Left() )
rMousePos.setX( maDragRect.Left() );
else if ( rMousePos.X()+mpSplitSet->mnSplitSize+1 > maDragRect.Right() )
rMousePos.setX( maDragRect.Right()-mpSplitSet->mnSplitSize+1 );
// store in screen coordinates due to FullDrag
mnMSplitPos = OutputToScreenPixel( rMousePos ).X();
}
else
{
rMousePos.AdjustY( -mnMouseOff );
if ( rMousePos.Y() < maDragRect.Top() )
rMousePos.setY( maDragRect.Top() );
else if ( rMousePos.Y()+mpSplitSet->mnSplitSize+1 > maDragRect.Bottom() )
rMousePos.setY( maDragRect.Bottom()-mpSplitSet->mnSplitSize+1 );
mnMSplitPos = OutputToScreenPixel( rMousePos ).Y();
}
}
void SplitWindow::ImplGetButtonRect( tools::Rectangle& rRect, bool bTest ) const
{
tools::Long nSplitSize = mpMainSet->mnSplitSize-1;
if (mbFadeOut || mbFadeIn)
nSplitSize += SPLITWIN_SPLITSIZEEX;
tools::Long nButtonSize = 0;
if ( mbFadeIn )
nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
if ( mbFadeOut )
nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
tools::Long nCenterEx = 0;
if ( mbHorz )
nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2;
else
nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2;
tools::Long nEx = 0;
if ( nCenterEx > 0 )
nEx += nCenterEx;
switch ( meAlign )
{
case WindowAlign::Top:
rRect.SetLeft( mnLeftBorder+nEx );
rRect.SetTop( mnDY-mnBottomBorder-nSplitSize );
rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
rRect.SetBottom( mnDY-mnBottomBorder-1 );
if ( bTest )
{
rRect.AdjustTop( -mnTopBorder );
rRect.AdjustBottom(mnBottomBorder );
}
break ;
case WindowAlign::Bottom:
rRect.SetLeft( mnLeftBorder+nEx );
rRect.SetTop( mnTopBorder );
rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
rRect.SetBottom( mnTopBorder+nSplitSize-1 );
if ( bTest )
{
rRect.AdjustTop( -mnTopBorder );
rRect.AdjustBottom(mnBottomBorder );
}
break ;
case WindowAlign::Left:
rRect.SetLeft( mnDX-mnRightBorder-nSplitSize );
rRect.SetTop( mnTopBorder+nEx );
rRect.SetRight( mnDX-mnRightBorder-1 );
rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
if ( bTest )
{
rRect.AdjustLeft( -mnLeftBorder );
rRect.AdjustRight(mnRightBorder );
}
break ;
case WindowAlign::Right:
rRect.SetLeft( mnLeftBorder );
rRect.SetTop( mnTopBorder+nEx );
rRect.SetRight( mnLeftBorder+nSplitSize-1 );
rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
if ( bTest )
{
rRect.AdjustLeft( -mnLeftBorder );
rRect.AdjustRight(mnRightBorder );
}
break ;
}
}
void SplitWindow::ImplGetFadeInRect( tools::Rectangle& rRect, bool bTest ) const
{
tools::Rectangle aRect;
if ( mbFadeIn )
ImplGetButtonRect( aRect, bTest );
rRect = aRect;
}
void SplitWindow::ImplGetFadeOutRect( tools::Rectangle& rRect ) const
{
tools::Rectangle aRect;
if ( mbFadeOut )
ImplGetButtonRect( aRect, false );
rRect = aRect;
}
void SplitWindow::ImplDrawGrip(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, bool bHorizontal, bool bLeft)
{
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
Color aColor;
if (rRect.Contains(GetPointerPosPixel()))
{
vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this , rRect, 2, 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() )
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=97 H=92 G=94
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland
2026-04-02