/* -*- 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 .
*/
namespace { // helper class to deactivate UpdateMode, if needed, for the life time of an instance class DeactivateUpdateMode
{ public: explicit DeactivateUpdateMode( SfxSplitWindow& rSplitWindow )
: mrSplitWindow( rSplitWindow )
, mbUpdateMode( rSplitWindow.IsUpdateMode() )
{ if ( mbUpdateMode )
{
mrSplitWindow.SetUpdateMode( false );
}
}
class SfxEmptySplitWin_Impl : public SplitWindow
{ /* [Description]
The SfxEmptySplitWin_Impldow is an empty SplitWindow, that replaces the SfxSplitWindow AutoHide mode. It only serves as a placeholder to receive mouse moves and if possible blend in the true SplitWindow display.
*/ friendclass SfxSplitWindow;
void SfxEmptySplitWin_Impl::Actualize()
{
Size aSize( pOwner->GetSizePixel() ); switch ( pOwner->GetAlign() )
{ case WindowAlign::Left: case WindowAlign::Right:
aSize.setWidth( GetFadeInSize() ); break; case WindowAlign::Top: case WindowAlign::Bottom:
aSize.setHeight( GetFadeInSize() ); break;
}
SetSizePixel( aSize );
}
void SfxEmptySplitWin_Impl::FadeIn()
{ if (!bAutoHide )
bAutoHide = IsFadeNoButtonMode();
pOwner->SetFadeIn_Impl( true ); if ( bAutoHide )
{ // Set Timer to close; the caller has to ensure themselves that the // Window is not closed instantly (eg by setting the focus or a modal // mode.
aLastPos = GetPointerPosPixel();
aTimer.Start();
} else
pOwner->SaveConfig_Impl();
}
A SfxSplitWindow brings the recursive structure of the SV-SplitWindows to the outside by simulating a table-like structure with rows and columns (maximum recursion depth 2). Furthermore, it ensures the persistence of the arrangement of the SfxDockingWindows.
*/
if ( pEmptyWin )
{ // Set pOwner to NULL, otherwise try to delete pEmptyWin once more. The // window that is just being docked is always deleted from the outside.
pEmptyWin->pOwner = nullptr;
}
pEmptyWin.disposeAndClear();
/* To insert SfxDockingWindows just pass no position. The SfxSplitWindow searches the last marked one to the passed SfxDockingWindow or appends a new one at the end.
*/
{ short nLine = -1; // so that the first window cab set nline to 0
sal_uInt16 nPos = 0; bool bNewLine = true; bool bSaveConfig = false;
SfxDock_Impl *pFoundDock=nullptr;
sal_uInt16 nCount = maDockArr.size(); for ( sal_uInt16 n=0; n<nCount; n++ )
{
SfxDock_Impl& rDock = *maDockArr[n]; if ( rDock.bNewLine )
{ // The window opens a new line if ( pFoundDock ) // But after the just inserted window break;
// New line
nPos = 0;
bNewLine = true;
}
if ( rDock.pWin )
{ // Does there exist a window now at this position if ( bNewLine && !pFoundDock )
{ // Not known until now in which real line it is located
sal_uInt16 nL = 0;
[[maybe_unused]] autoconst ok = GetWindowPos( rDock.pWin, nL, nPos );
assert(ok);
nLine = static_cast<short>(nL);
}
if ( !pFoundDock )
{ // The window is located before the inserted one
nPos++;
}
// Line is opened
bNewLine = false; if ( pFoundDock ) break;
}
if ( rDock.nType == pDockWin->GetType() )
{
DBG_ASSERT( !pFoundDock && !rDock.pWin, "Window already exists!");
pFoundDock = &rDock; if ( !bNewLine ) break; else
{ // A new line has been created but no window was found there; // continue searching for a window in this line in-order to set // bNewLine correctly. While doing so nline or nPos are not // to be changed!
nLine++;
}
}
}
if ( !pFoundDock )
{ // Not found, insert at end
pFoundDock = new SfxDock_Impl;
pFoundDock->bHide = true;
maDockArr.push_back( std::unique_ptr<SfxDock_Impl>(pFoundDock) );
pFoundDock->nType = pDockWin->GetType();
nLine++;
nPos = 0;
bNewLine = true;
pFoundDock->bNewLine = bNewLine;
bSaveConfig = true;
}
if ( nLine > nL && GetItemCount( GetItemId( nL ) ) == 1 )
{ // If the last window is removed from its line, then everything slips // one line to the front!
nLine--;
}
RemoveWindow( pDockWin );
InsertWindow( pDockWin, rSize, nLine, nPos, bNewLine );
}
The DockingWindow that is pushed on this SplitWindow and shall hold the given position and size.
*/
{
ReleaseWindow_Impl( pDockWin, false );
SfxDock_Impl *pDock = new SfxDock_Impl;
pDock->bHide = false;
pDock->nType = pDockWin->GetType();
pDock->bNewLine = bNewLine;
pDock->pWin = pDockWin;
// The window must be inserted before the first window so that it has the // same or a greater position than pDockWin.
sal_uInt16 nCount = maDockArr.size();
sal_uInt16 nLastWindowIdx(0);
// If no window is found, a first window is inserted
sal_uInt16 nInsertPos = 0; for ( sal_uInt16 n=0; n<nCount; n++ )
{
SfxDock_Impl& rD = *maDockArr[n];
if (rD.pWin)
{ // A docked window has been found. If no suitable window behind // the desired insertion point s found, then insertion is done at // the end.
nInsertPos = nCount;
nLastWindowIdx = n;
sal_uInt16 nL=0, nP=0;
GetWindowPos( rD.pWin, nL, nP );
if ( bNewLine || nLine == GetItemCount() )
{ // An existing row should not be inserted, instead a new one // will be created
sal_uInt16 nId = 1; for ( sal_uInt16 n=0; n<GetItemCount(); n++ )
{ if ( GetItemId(n) >= nId )
nId = GetItemId(n)+1;
}
// Create a new nLine:th line
SplitWindowItemFlags nBits = nItemBits; if ( GetAlign() == WindowAlign::Top || GetAlign() == WindowAlign::Bottom )
nBits |= SplitWindowItemFlags::ColSet;
InsertItem( nId, nSetSize, nLine, 0, nBits );
}
// Insert the window at line with the position nline. ItemWindowSize set to // "percentage" share since the SV then does the re-sizing as expected, // "pixel" actually only makes sense if also items with percentage or // relative sizes are present.
nItemBits |= SplitWindowItemFlags::PercentSize;
sal_uInt16 nSet = GetItemId( nLine );
InsertItem( pDockWin->GetType(), pDockWin, nWinSize, nPos, nSet, nItemBits );
// SplitWindows are once created in SFX and when inserting the first // DockingWindows is made visible. if ( GetItemCount() == 1 && GetItemCount( 1 ) == 1 )
{ // The Rearranging in WorkWindow and a Show() on the SplitWindow is // caused by SfxDockingwindow (->SfxWorkWindow::ConfigChild_Impl) if ( !bPinned && !IsFloatingMode() )
{
bPinned = true; bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
pEmptyWin->bFadeIn = false;
SetPinned_Impl( false );
pEmptyWin->Actualize();
SAL_INFO("sfx", "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign )->nVisible = SfxChildVisibility::VISIBLE; // tdf#113539 FadeIn will call ArrangeChildren_Impl() for us, and avoiding extra calls to that // can make a different to load times because it avoids extra accessibility calcs if ( bFadeIn )
FadeIn(); else
pWorkWin->ArrangeChildren_Impl();
} else
{ bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
pEmptyWin->bFadeIn = false;
pEmptyWin->Actualize(); if ( !bPinned || !pEmptyWin->bFadeIn )
{
SAL_INFO("sfx", "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
} else
{
SAL_INFO("sfx", "SfxSplitWindow::InsertWindow_Impl - registering real Splitwindow" );
}
pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign )->nVisible = SfxChildVisibility::VISIBLE; // tdf#113539 FadeIn will call ArrangeChildren_Impl() for us, and avoiding extra calls to that // can make a different to load times because it avoids extra accessibility calcs if ( bFadeIn )
FadeIn(); else
pWorkWin->ArrangeChildren_Impl();
}
pWorkWin->ShowChildren_Impl();
}
pDeactivateUpdateMode.reset();
// workaround insufficiency of <SplitWindow> regarding dock layouting: // apply FIXED item size as 'original' item size to improve layouting of undock-dock-cycle of a window
{
std::vector< std::pair< sal_uInt16, tools::Long > > aNewOrgSizes; // get FIXED item sizes
sal_uInt16 nCount = maDockArr.size(); for ( sal_uInt16 n=0; n<nCount; ++n )
{ const SfxDock_Impl& rD = *maDockArr[n]; if ( rD.pWin )
{ const sal_uInt16 nId = rD.nType; const tools::Long nSize = GetItemSize( nId, SplitWindowItemFlags::Fixed );
aNewOrgSizes.emplace_back( nId, nSize );
}
} // apply new item sizes
DeactivateUpdateMode aDeactivateUpdateMode( *this ); for (const std::pair< sal_uInt16, tools::Long > & rNewOrgSize : aNewOrgSizes)
{
SetItemSize( rNewOrgSize.first, rNewOrgSize.second );
}
}
}
Removes a DockingWindow. If it was the last one, then the SplitWindow is being hidden.
*/
{
sal_uInt16 nSet = GetSet( pDockWin->GetType() );
// SplitWindows are once created in SFX and is made invisible after // removing the last DockingWindows. if ( GetItemCount( nSet ) == 1 && GetItemCount() == 1 )
{ // The Rearranging in WorkWindow is caused by SfxDockingwindow
Hide();
pEmptyWin->aTimer.Stop();
sal_uInt16 nRealState = pEmptyWin->nState;
FadeOut_Impl();
pEmptyWin->Hide(); #ifdef DBG_UTIL if ( !bPinned || !pEmptyWin->bFadeIn )
{
SAL_INFO("sfx", "SfxSplitWindow::RemoveWindow - releasing empty Splitwindow" );
} else
{
SAL_INFO("sfx", "SfxSplitWindow::RemoveWindow - releasing real Splitwindow" );
} #endif
pWorkWin->ReleaseChild_Impl( *GetSplitWindow() );
pEmptyWin->nState = nRealState;
pWorkWin->ArrangeAutoHideWindows( this );
}
// Remove Windows, and if it was the last of the line, then also remove // the line (line = itemset)
DeactivateUpdateMode aDeactivateUpdateMode( *this );
if ( CursorIsOverRect() || !pTimer )
{ // If the cursor is within the window, display the SplitWindow and set // up the timer for close
pEmptyWin->bAutoHide = true; if ( !IsVisible() )
pEmptyWin->FadeIn();
pEmptyWin->aLastPos = GetPointerPosPixel();
pEmptyWin->aTimer.Start();
} elseif ( pEmptyWin->bAutoHide )
{ if ( GetPointerPosPixel() != pEmptyWin->aLastPos )
{ // The mouse has moved within the running time of the timer, thus // do nothing
pEmptyWin->aLastPos = GetPointerPosPixel();
pEmptyWin->aTimer.Start(); return;
}
// Especially for TF_AUTOSHOW_ON_MOUSEMOVE : // If the window is not visible, there is nothing to do // (user has simply moved the mouse over pEmptyWin) if ( IsVisible() )
{
pEmptyWin->bEndAutoHide = false; if ( !Application::IsInModalMode() &&
!vcl::IsInPopupMenuExecute() &&
!pEmptyWin->bSplit && !HasChildPathFocus( true ) )
{ // While a modal dialog or a popup menu is open or while the // Splitting is done, in any case, do not close. Even as long // as one of the Children has the focus, the window remains // open.
pEmptyWin->bEndAutoHide = true;
}
if ( pEmptyWin->bEndAutoHide )
{ // As far as I am concerned this can be the end of AutoShow // But maybe some other SfxSplitWindow will remain open, // then all others remain open too. if ( !pWorkWin->IsAutoHideMode( this ) )
{
FadeOut_Impl();
pWorkWin->ArrangeAutoHideWindows( this );
} else
{
pEmptyWin->aLastPos = GetPointerPosPixel();
pEmptyWin->aTimer.Start();
}
} else
{
pEmptyWin->aLastPos = GetPointerPosPixel();
pEmptyWin->aTimer.Start();
}
}
}
}
// Also, take the collapsed SplitWindow into account
Point aPos = pEmptyWin->GetParent()->OutputToScreenPixel( pEmptyWin->GetPosPixel() );
Size aSize = pEmptyWin->GetSizePixel();
tools::Rectangle aRect( aPos, aSize );
if ( bVisible )
{
Point aVisPos = GetPosPixel();
Size aVisSize = GetSizePixel();
// Extend with +/- a few pixels, otherwise it is too nervous
aVisPos.AdjustX( -(nPixel) );
aVisPos.AdjustY( -(nPixel) );
aVisSize.AdjustWidth(2 * nPixel );
aVisSize.AdjustHeight(2 * nPixel );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.