Files
libreoffice/vcl/source/window/splitwin.cxx
Stephan Bergmann f853ec317f Extend loplugin:external to warn about classes
...following up on 314f15bff0 "Extend
loplugin:external to warn about enums".

Cases where free functions were moved into an unnamed namespace along with a
class, to not break ADL, are in:

  filter/source/svg/svgexport.cxx
  sc/source/filter/excel/xelink.cxx
  sc/source/filter/excel/xilink.cxx
  svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx

All other free functions mentioning moved classes appear to be harmless and not
give rise to (silent, even) ADL breakage.  (One remaining TODO in
compilerplugins/clang/external.cxx is that derived classes are not covered by
computeAffectedTypes, even though they could also be affected by ADL-breakage---
but don't seem to be in any acutal case across the code base.)

For friend declarations using elaborate type specifiers, like

  class C1 {};
  class C2 { friend class C1; };

* If C2 (but not C1) is moved into an unnamed namespace, the friend declaration
must be changed to not use an elaborate type specifier (i.e., "friend C1;"; see
C++17 [namespace.memdef]/3: "If the name in a friend declaration is neither
qualified nor a template-id and the declaration is a function or an
elaborated-type-specifier, the lookup to determine whether the entity has been
previously declared shall not consider any scopes outside the innermost
enclosing namespace.")

* If C1 (but not C2) is moved into an unnamed namespace, the friend declaration
must be changed too, see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71882>
"elaborated-type-specifier friend not looked up in unnamed namespace".

Apart from that, to keep changes simple and mostly mechanical (which should help
avoid regressions), out-of-line definitions of class members have been left in
the enclosing (named) namespace.  But explicit specializations of class
templates had to be moved into the unnamed namespace to appease
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92598> "explicit specialization of
template from unnamed namespace using unqualified-id in enclosing namespace".

Also, accompanying declarations (of e.g. typedefs or static variables) that
could arguably be moved into the unnamed namespace too have been left alone.

And in some cases, mention of affected types in blacklists in other loplugins
needed to be adapted.

And sc/qa/unit/mark_test.cxx uses a hack of including other .cxx, one of which
is sc/source/core/data/segmenttree.cxx where e.g. ScFlatUInt16SegmentsImpl is
not moved into an unnamed namespace (because it is declared in
sc/inc/segmenttree.hxx), but its base ScFlatSegmentsImpl is.  GCC warns about
such combinations with enabled-by-default -Wsubobject-linkage, but "The compiler
doesn’t give this warning for types defined in the main .C file, as those are
unlikely to have multiple definitions."
(<https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Warning-Options.html>)  The
warned-about classes also don't have multiple definitions in the given test, so
disable the warning when including the .cxx.

Change-Id: Ib694094c0d8168be68f8fe90dfd0acbb66a3f1e4
Reviewed-on: https://gerrit.libreoffice.org/83239
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2019-11-22 12:57:32 +01:00

2810 lines
82 KiB
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 <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_SPLITSIZE 4
#define SPLITWIN_SPLITSIZEEX 4
#define SPLITWIN_SPLITSIZEEXLN 7
#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();
long mnSize;
long mnPixSize;
long mnLeft;
long mnTop;
long mnWidth;
long mnHeight;
long mnSplitPos;
long mnSplitSize;
long mnOldSplitPos;
long mnOldSplitSize;
long mnOldWidth;
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.
long mnMinSize;
/// Maximal width or height of the item. -1 means no restriction.
long mnMaxSize;
};
}
class ImplSplitSet
{
public:
ImplSplitSet();
~ImplSplitSet();
std::vector< ImplSplitItem > mvItems;
std::unique_ptr<Wallpaper> mpWallpaper;
long mnLastSize;
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 )
{
}
ImplSplitSet::~ImplSplitSet()
{
mpWallpaper.reset();
}
/** 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 {
long ValidateSize (const 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,
long& rLeft, long& rTop,
long& rRight, 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();
long nDX = mnDX;
long nDY = mnDY;
switch (meAlign)
{
case WindowAlign::Bottom:
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(0, 0), Point(nDX - 1, 0));
rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 1, nDY - 2));
rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
rRenderContext.DrawLine(Point(0, 1), Point(nDX - 1, 1));
rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 1, nDY - 1));
break;
case WindowAlign::Top:
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 1, nDY - 2));
rRenderContext.DrawLine(Point(0, 0), Point(nDX - 1, 0));
rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 1, nDY - 1));
rRenderContext.DrawLine(Point(0, 1), Point(nDX - 1, 1));
break;
case WindowAlign::Left:
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(nDX - 2, 0), Point(nDX - 2, nDY - 2));
rRenderContext.DrawLine(Point(0, 0), Point(nDX - 1, 0));
rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 2, nDY - 2));
rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
rRenderContext.DrawLine(Point(nDX - 1, 0), Point(nDX - 1, nDY - 1));
rRenderContext.DrawLine(Point(0, 1), Point(nDX - 3, 1));
rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 2, nDY - 1));
break;
default:
rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
rRenderContext.DrawLine(Point(0, 0), Point( 0, nDY - 2));
rRenderContext.DrawLine(Point(0, 0), Point( nDX - 1, 0));
rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 1, nDY - 2));
rRenderContext.SetLineColor( rStyleSettings.GetLightColor());
rRenderContext.DrawLine(Point(1, 1), Point(1, nDY - 3));
rRenderContext.DrawLine(Point(1, 1), Point(nDX - 1, 1));
rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 1, nDY - 1));
}
}
void SplitWindow::ImplDrawBorderLine(vcl::RenderContext& rRenderContext)
{
if (mbFadeOut)
{
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
long nDX = mnDX;
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:
rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
rRenderContext.DrawLine( Point( SPLITWIN_SPLITSIZEEXLN-1, 0 ), Point( SPLITWIN_SPLITSIZEEXLN-1, nDY-2 ) );
rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
rRenderContext.DrawLine( Point( SPLITWIN_SPLITSIZEEXLN, 1 ), Point( SPLITWIN_SPLITSIZEEXLN, nDY-3 ) );
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.IsInside( 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,
long nSetLeft, long nSetTop,
long nSetWidth, 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;
long nCalcSize;
long nPos;
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) )
{
long nPercentFactor = 10;
long nRelCount = 0;
long nPercent = 0;
long nRelPercent = 0;
long nAbsSize = 0;
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 )
{
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;
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;
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 < static_cast<sal_uInt16>(std::abs( nSizeDelta ))) && nSizeWinSize )
{
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
long nErrorSum = nSizeDelta % nCalcItems;
long nCurSizeDelta = nSizeDelta / nCalcItems;
nMins = 0;
for ( auto& rItem : rItems )
{
if ( rItem.mbSubSize )
{
long* pSize = &(rItem.mnPixSize);
long nTempErr;
if ( nErrorSum )
{
if ( nErrorSum < 0 )
nTempErr = -1;
else
nTempErr = 1;
}
else
nTempErr = 0;
if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 )
{
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 adept 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;
long nRelSize = 0;
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;
}
}
void SplitWindow::ImplDrawBack(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet)
{
std::vector< ImplSplitItem >& rItems = pSet->mvItems;
for ( const auto& rItem : rItems )
{
pSet = rItem.mpSet.get();
if (pSet && pSet->mpWallpaper)
{
Point aPoint(rItem.mnLeft, rItem.mnTop);
Size aSize(rItem.mnWidth, rItem.mnHeight);
tools::Rectangle aRect(aPoint, aSize);
rRenderContext.DrawWallpaper(aRect, *pSet->mpWallpaper);
}
}
for ( auto& rItem : rItems )
{
if (rItem.mpSet)
ImplDrawBack(rRenderContext, rItem.mpSet.get());
}
}
static void ImplDrawSplit(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet, bool bRows, bool bDown)
{
if (pSet->mvItems.empty())
return;
size_t nItems = pSet->mvItems.size();
long nPos;
long nTop;
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;
long nItemSplitSize = rItems[i].mnSplitSize;
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,
long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos,
bool bRows )
{
if ( pSet->mvItems.empty() )
return 0;
sal_uInt16 nSplitTest;
size_t nItems = pSet->mvItems.size();
long nMPos1;
long nMPos2;
long nPos;
long nTop;
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,
long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos )
{
// Resizable SplitWindow should be treated different
if ( pWindow->mnWinStyle & WB_SIZEABLE )
{
long nTPos;
long nPos;
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();
}
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()
{
// If MainSet has a Wallpaper, this is the background,
// otherwise it is the standard colour
if ( mpMainSet->mpWallpaper )
SetBackground( *mpMainSet->mpWallpaper );
else
{
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 )
{
ImplInit( pParent, nStyle );
DockingWindow::SetIdleDebugName( "vcl::SplitWindow maLayoutIdle" );
}
SplitWindow::~SplitWindow()
{
disposeOnce();
}
void SplitWindow::dispose()
{
// delete Sets
mpMainSet.reset();
DockingWindow::dispose();
}
void SplitWindow::ImplSetWindowSize( 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 );
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 )
{
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() )
{
long nDelta = 0;
long nCurSize;
if ( mbHorz )
nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder;
else
nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder;
nCurSize -= nSplitSize;
nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
nDelta = nCalcSize-nCurSize;
if ( !nDelta )
return aSize;
switch ( meAlign )
{
case WindowAlign::Top:
aSize.AdjustHeight(nDelta );
break;
case WindowAlign::Bottom:
aSize.AdjustHeight(nDelta );
break;
case WindowAlign::Left:
aSize.AdjustWidth(nDelta );
break;
case WindowAlign::Right:
default:
aSize.AdjustWidth(nDelta );
break;
}
}
}
return aSize;
}
void SplitWindow::ImplCalcLayout()
{
if ( !mbCalc || !mbRecalc || mpMainSet->mvItems.empty() )
return;
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 )
{
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() )
{
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
long nL;
long nT;
long nW;
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
{
long nSplitSize = mpMainSet->mnSplitSize-1;
if (mbFadeOut || mbFadeIn)
nSplitSize += SPLITWIN_SPLITSIZEEX;
long nButtonSize = 0;
if ( mbFadeIn )
nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
if ( mbFadeOut )
nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
long nCenterEx = 0;
if ( mbHorz )
nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2;
else
nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2;
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.IsInside(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::EnableB2dDraw);
long nWidth = rRect.getWidth();
long nWidthHalf = nWidth / 2;
long nHeight = rRect.getHeight();
long nHeightHalf = nHeight / 2;
long nLeft = rRect.Left();
long nRight = rRect.Right();
long nTop = rRect.Top();
long nBottom = rRect.Bottom();
long nMargin = 1;
rRenderContext.SetLineColor(aColor);
rRenderContext.SetFillColor(aColor);
tools::Polygon aPoly(3);
if (bHorizontal)
{
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
{
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)
{
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)
{
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;
long nCurMaxSize;
bool bPropSmaller;
mnMouseModifier = rMEvt.GetModifier();
bPropSmaller = (mnMouseModifier & KEY_SHIFT) && (static_cast<sal_uInt16>(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 )
{
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 = new 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.IsInside( aMousePosPixel ) )
{
mbFadeOutDown = true;
mbFadeOutPressed = true;
Invalidate();
}
else
{
ImplGetFadeInRect( aTestRect, true );
if ( aTestRect.IsInside( 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();
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.IsInside( aPos ) &&
!aFadeOutRect.IsInside( 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.IsInside( 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.IsInside( 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;
long nDelta = mnMSplitPos-mnMStartPos;
if ( (mnSplitTest & SPLIT_WINDOW) && mpMainSet->mvItems.empty() )
{
if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
nDelta *= -1;
ImplSetWindowSize( nDelta );
}
else
{
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 )
{
Update();
mnMStartPos = mnMSplitPos;
}
}
if ( rTEvt.IsTrackingEnded() )
{
delete [] mpLastSizes;
mpLastSizes = nullptr;
mpSplitSet = nullptr;
mnMouseOff = 0;
mnMStartPos = 0;
mnMSplitPos = 0;
mnMouseModifier = 0;
mnSplitTest = 0;
mnSplitPos = 0;
}
}
}
bool SplitWindow::PreNotify( NotifyEvent& rNEvt )
{
const MouseEvent* pMouseEvt = nullptr;
if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr )
{
if( !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.IsInside( GetPointerPosPixel() ) != aFadeInRect.IsInside( GetLastPointerPosPixel() ) )
Invalidate( aFadeInRect );
if ( aFadeOutRect.IsInside( GetPointerPosPixel() ) != aFadeOutRect.IsInside( 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 FrameSet-backgrounds
ImplDrawBack(rRenderContext, mpMainSet.get());
// 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;
const char* pHelpResId = nullptr;
ImplGetFadeInRect( aHelpRect, true );
if ( aHelpRect.IsInside( aMousePosPixel ) )
pHelpResId = SV_HELPTEXT_FADEIN;
else
{
ImplGetFadeOutRect( aHelpRect );
if ( aHelpRect.IsInside( 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, 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, long nSize,
sal_uInt16 nPos, sal_uInt16 nIntoSetId,
SplitWindowItemFlags nBits )
{
InsertItem( nId, nullptr, nSize, nPos, nIntoSetId, nBits );
}
void SplitWindow::RemoveItem( sal_uInt16 nId )
{
#ifdef DBG_UTIL
sal_uInt16 nDbgDummy;
SAL_WARN_IF( !ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl", "SplitWindow::RemoveItem() - Id not found" );
#endif
// search set
sal_uInt16 nPos;
ImplSplitSet* pSet = ImplFindItem( mpMainSet.get(), nId, nPos );
if (!pSet)
return;
ImplSplitItem* pItem = &pSet->mvItems[nPos];
VclPtr<vcl::Window> pWindow = pItem->mpWindow;
VclPtr<vcl::Window> pOrgParent = pItem->mpOrgParent;
// delete set if required
if ( !pWindow )
pItem->mpSet.reset();
// remove item
pSet->mbCalcPix = true;
pSet->mvItems.erase( pSet->mvItems.begin() + nPos );
ImplUpdate();
// to have the least amounts of paints delete window only here
if ( pWindow )
{
// restore window
pWindow->Hide();
pWindow->SetParent( pOrgParent );
}
// Clear and delete
pWindow.clear();
pOrgParent.clear();
}
void SplitWindow::Clear()
{
// create Main-Set again
mpMainSet.reset(new ImplSplitSet());
if ( mnWinStyle & WB_NOSPLITDRAW )
mpMainSet->mnSplitSize -= 2;
mpBaseSet = mpMainSet.get();
// and invalidate again
ImplUpdate();
}
void SplitWindow::SplitItem( sal_uInt16 nId, 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;
}
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;
bool bTemp = bPropSmall;
bPropSmall = bPropGreat;
bPropGreat = bTemp;
}
sal_uInt16 n;
// now splitt the windows
if ( nDelta < 0 )
{
if ( bGreat )
{
if ( bPropGreat )
{
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 )
{
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, 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();
}
}
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;
}
long SplitWindow::GetItemSize( sal_uInt16 nId, SplitWindowItemFlags nBits ) const
{
sal_uInt16 nPos;
ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
if ( pSet )
{
if ( nBits == pSet->mvItems[nPos].mnBits )
return pSet->mvItems[nPos].mnSize;
else
{
const_cast<SplitWindow*>(this)->ImplCalcLayout();
long nRelSize = 0;
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();
}
long SplitWindow::GetFadeInSize() const
{
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: */