diff options
Diffstat (limited to 'vcl/source/window/dockmgr.cxx')
-rw-r--r-- | vcl/source/window/dockmgr.cxx | 1075 |
1 files changed, 1075 insertions, 0 deletions
diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx new file mode 100644 index 000000000..f836ff2f1 --- /dev/null +++ b/vcl/source/window/dockmgr.cxx @@ -0,0 +1,1075 @@ +/* -*- 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 <tools/time.hxx> +#include <sal/log.hxx> +#include <o3tl/deleter.hxx> + +#include <brdwin.hxx> +#include <svdata.hxx> +#include <window.h> + +#include <vcl/event.hxx> +#include <vcl/toolkit/floatwin.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/svapp.hxx> +#include <vcl/timer.hxx> +#include <vcl/settings.hxx> + +#include "impldockingwrapper.hxx" + +#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE) + +namespace { + +class ImplDockFloatWin2 : public FloatingWindow +{ +private: + ImplDockingWindowWrapper* mpDockWin; + sal_uInt64 mnLastTicks; + Timer m_aDockTimer; + Timer m_aEndDockTimer; + Point maDockPos; + tools::Rectangle maDockRect; + bool mbInMove; + ImplSVEvent * mnLastUserEvent; + + DECL_LINK(DockingHdl, void *, void); + DECL_LINK(DockTimerHdl, Timer *, void); + DECL_LINK(EndDockTimerHdl, Timer *, void); +public: + ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits, + ImplDockingWindowWrapper* pDockingWin ); + virtual ~ImplDockFloatWin2() override; + virtual void dispose() override; + + virtual void Move() override; + virtual void Resize() override; + virtual void TitleButtonClick( TitleButton nButton ) override; + virtual void Resizing( Size& rSize ) override; + virtual bool Close() override; +}; + +} + +ImplDockFloatWin2::ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits, + ImplDockingWindowWrapper* pDockingWin ) : + FloatingWindow( pParent, nWinBits ), + mpDockWin( pDockingWin ), + mnLastTicks( tools::Time::GetSystemTicks() ), + m_aDockTimer("vcl::ImplDockFloatWin2 m_aDockTimer"), + m_aEndDockTimer( "vcl::ImplDockFloatWin2 m_aEndDockTimer" ), + mbInMove( false ), + mnLastUserEvent( nullptr ) +{ + // copy state of DockingWindow + if ( pDockingWin ) + { + GetOutDev()->SetSettings( pDockingWin->GetWindow()->GetSettings() ); + Enable( pDockingWin->GetWindow()->IsEnabled(), false ); + EnableInput( pDockingWin->GetWindow()->IsInputEnabled(), false ); + AlwaysEnableInput( pDockingWin->GetWindow()->IsAlwaysEnableInput(), false ); + EnableAlwaysOnTop( pDockingWin->GetWindow()->IsAlwaysOnTopEnabled() ); + SetActivateMode( pDockingWin->GetWindow()->GetActivateMode() ); + } + + SetBackground( GetSettings().GetStyleSettings().GetFaceColor() ); + + m_aDockTimer.SetInvokeHandler( LINK( this, ImplDockFloatWin2, DockTimerHdl ) ); + m_aDockTimer.SetPriority( TaskPriority::HIGH_IDLE ); + m_aDockTimer.SetTimeout( 50 ); + + m_aEndDockTimer.SetInvokeHandler( LINK( this, ImplDockFloatWin2, EndDockTimerHdl ) ); + m_aEndDockTimer.SetPriority( TaskPriority::HIGH_IDLE ); + m_aEndDockTimer.SetTimeout( 50 ); +} + +ImplDockFloatWin2::~ImplDockFloatWin2() +{ + disposeOnce(); +} + +void ImplDockFloatWin2::dispose() +{ + if( mnLastUserEvent ) + Application::RemoveUserEvent( mnLastUserEvent ); + FloatingWindow::dispose(); +} + +IMPL_LINK_NOARG(ImplDockFloatWin2, DockTimerHdl, Timer *, void) +{ + SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "docktimer called but not floating" ); + + PointerState aState = GetPointerState(); + + if( aState.mnState & KEY_MOD1 ) + { + // i43499 CTRL disables docking now + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) + m_aDockTimer.Start(); + } + else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) ) + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + mpDockWin->EndDocking( maDockRect, false ); + } + else + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow ); + m_aDockTimer.Start(); + } +} + +IMPL_LINK_NOARG(ImplDockFloatWin2, EndDockTimerHdl, Timer *, void) +{ + SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "enddocktimer called but not floating" ); + + PointerState aState = GetPointerState(); + if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) ) + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + mpDockWin->EndDocking( maDockRect, true ); + } + else + m_aEndDockTimer.Start(); +} + +IMPL_LINK_NOARG(ImplDockFloatWin2, DockingHdl, void*, void) +{ + // called during move of a floating window + mnLastUserEvent = nullptr; + + vcl::Window *pDockingArea = mpDockWin->GetWindow()->GetParent(); + PointerState aState = pDockingArea->GetPointerState(); + + bool bRealMove = true; + if( GetStyle() & WB_OWNERDRAWDECORATION ) + { + // for windows with ownerdraw decoration + // we allow docking only when the window was moved + // by dragging its caption + // and ignore move request due to resizing + vcl::Window *pBorder = GetWindow( GetWindowType::Border ); + if( pBorder != this ) + { + tools::Rectangle aBorderRect( Point(), pBorder->GetSizePixel() ); + sal_Int32 nLeft, nTop, nRight, nBottom; + GetBorder( nLeft, nTop, nRight, nBottom ); + // limit borderrect to the caption part only and without the resizing borders + aBorderRect.SetBottom( aBorderRect.Top() + nTop ); + aBorderRect.AdjustLeft(nLeft ); + aBorderRect.AdjustRight( -nRight ); + + PointerState aBorderState = pBorder->GetPointerState(); + bRealMove = aBorderRect.Contains( aBorderState.maPos ); + } + } + + if( mpDockWin->GetWindow()->IsVisible() && + (tools::Time::GetSystemTicks() - mnLastTicks > 500) && + ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) && + !(aState.mnState & KEY_MOD1) && // i43499 CTRL disables docking now + bRealMove ) + { + maDockPos = pDockingArea->OutputToScreenPixel( pDockingArea->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) ); + maDockRect = tools::Rectangle( maDockPos, mpDockWin->GetSizePixel() ); + + // mouse pos in screen pixels + Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos ); + + if( ! mpDockWin->IsDocking() ) + mpDockWin->StartDocking( aMousePos, maDockRect ); + + bool bFloatMode = mpDockWin->Docking( aMousePos, maDockRect ); + + if( ! bFloatMode ) + { + // indicates that the window could be docked at maDockRect + maDockRect.SetPos( mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ScreenToOutputPixel( + maDockRect.TopLeft() ) ); + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow ); + m_aEndDockTimer.Stop(); + m_aDockTimer.Invoke(); + } + else + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + m_aDockTimer.Stop(); + m_aEndDockTimer.Invoke(); + } + } + mbInMove = false; +} + +void ImplDockFloatWin2::Move() +{ + if( mbInMove ) + return; + + mbInMove = true; + FloatingWindow::Move(); + mpDockWin->GetWindow()->Move(); + + /* + * note: the window should only dock if KEY_MOD1 is pressed + * and the user releases all mouse buttons. The real problem here + * is that we don't get mouse events (at least not on X) + * if the mouse is on the decoration. So we have to start an + * awkward timer based process that polls the modifier/buttons + * to see whether they are in the right condition shortly after the + * last Move message. + */ + if( ! mnLastUserEvent ) + mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin2, DockingHdl ), nullptr, true ); +} + +void ImplDockFloatWin2::Resize() +{ + // forwarding of resize only required if we have no borderwindow ( GetWindow() then returns 'this' ) + if( GetWindow( GetWindowType::Border ) == this ) + { + FloatingWindow::Resize(); + Size aSize( GetSizePixel() ); + mpDockWin->GetWindow()->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), PosSizeFlags::PosSize ); // TODO: is this needed ??? + } +} + +void ImplDockFloatWin2::TitleButtonClick( TitleButton nButton ) +{ + FloatingWindow::TitleButtonClick( nButton ); + mpDockWin->TitleButtonClick( nButton ); +} + +void ImplDockFloatWin2::Resizing( Size& rSize ) +{ + FloatingWindow::Resizing( rSize ); + mpDockWin->Resizing( rSize ); +} + +bool ImplDockFloatWin2::Close() +{ + return true; +} + +DockingManager::DockingManager() +{ +} + +DockingManager::~DockingManager() +{ +} + +ImplDockingWindowWrapper* DockingManager::GetDockingWindowWrapper( const vcl::Window *pWindow ) +{ + for( const auto& xWrapper : mvDockingWindows ) + { + if (xWrapper && xWrapper->mpDockingWindow == pWindow) + return xWrapper.get(); + } + return nullptr; +} + +bool DockingManager::IsDockable( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + + /* + if( pWindow->HasDockingHandler() ) + return true; + */ + return (pWrapper != nullptr); +} + +bool DockingManager::IsFloating( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + return pWrapper->IsFloatingMode(); + else + return false; +} + +bool DockingManager::IsLocked( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + return pWrapper && pWrapper->IsLocked(); +} + +void DockingManager::Lock( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->Lock(); +} + +void DockingManager::Unlock( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->Unlock(); +} + +void DockingManager::SetFloatingMode( const vcl::Window *pWindow, bool bFloating ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->SetFloatingMode( bFloating ); +} + +void DockingManager::StartPopupMode( const vcl::Window *pWindow, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->StartPopupMode( rRect, nFlags ); +} + +void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWindow, FloatWinPopupFlags nFlags ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->StartPopupMode( pParentToolBox, nFlags ); +} + +void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWindow ) +{ + StartPopupMode( pParentToolBox, pWindow, FloatWinPopupFlags::AllowTearOff | + FloatWinPopupFlags::AllMouseButtonClose | + FloatWinPopupFlags::NoMouseUpClose ); +} + +bool DockingManager::IsInPopupMode( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + return pWrapper && pWrapper->IsInPopupMode(); +} + +void DockingManager::EndPopupMode( const vcl::Window *pWin ) +{ + ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin ); + if( pWrapper && pWrapper->GetFloatingWindow() && static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->IsInPopupMode() ) + static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->EndPopupMode(); +} + +SystemWindow* DockingManager::GetFloatingWindow(const vcl::Window *pWin) +{ + ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin ); + if (pWrapper) + return pWrapper->GetFloatingWindow(); + return nullptr; +} + +void DockingManager::SetPopupModeEndHdl( const vcl::Window *pWindow, const Link<FloatingWindow*,void>& rLink ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->SetPopupModeEndHdl(rLink); +} + +void DockingManager::AddWindow( const vcl::Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + return; + mvDockingWindows.emplace_back( new ImplDockingWindowWrapper( pWindow ) ); +} + +void DockingManager::RemoveWindow( const vcl::Window *pWindow ) +{ + for( auto it = mvDockingWindows.begin(); it != mvDockingWindows.end(); ++it ) + { + const auto& xWrapper = *it; + if (xWrapper && xWrapper->mpDockingWindow == pWindow) + { + // deleting wrappers calls set of actions which may want to use + // wrapper we want to delete - avoid crash using temporary owner + // while erasing + auto pTemporaryOwner = std::move(*it); + mvDockingWindows.erase( it ); + break; + } + } +} + +void DockingManager::SetPosSizePixel( vcl::Window const *pWindow, tools::Long nX, tools::Long nY, + tools::Long nWidth, tools::Long nHeight, + PosSizeFlags nFlags ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); +} + +tools::Rectangle DockingManager::GetPosSizePixel( const vcl::Window *pWindow ) +{ + tools::Rectangle aRect; + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + aRect = tools::Rectangle( pWrapper->GetPosPixel(), pWrapper->GetSizePixel() ); + + return aRect; +} + +class ImplPopupFloatWin : public FloatingWindow +{ +private: + bool mbToolBox; + +public: + ImplPopupFloatWin( vcl::Window* pParent, bool bToolBox ); + virtual ~ImplPopupFloatWin() override; + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; +}; + +ImplPopupFloatWin::ImplPopupFloatWin( vcl::Window* pParent, bool bToolBox ) : + FloatingWindow( pParent, bToolBox ? WB_BORDER | WB_POPUP | WB_SYSTEMWINDOW | WB_NOSHADOW : WB_STDPOPUP ), + mbToolBox( bToolBox ) +{ + if ( bToolBox ) + { + // indicate window type, required for accessibility + // which should not see this window as a toplevel window + mpWindowImpl->mbToolbarFloatingWindow = true; + } +} + +ImplPopupFloatWin::~ImplPopupFloatWin() +{ + disposeOnce(); +} + +css::uno::Reference< css::accessibility::XAccessible > ImplPopupFloatWin::CreateAccessible() +{ + if ( !mbToolBox ) + return FloatingWindow::CreateAccessible(); + + // switch off direct accessibility support for this window + + // this is to avoid appearance of this window as standalone window in the accessibility hierarchy + // as this window is only used as a helper for subtoolbars that are not teared-off, the parent toolbar + // has to provide accessibility support (as implemented in the toolkit) + // so the contained toolbar should appear as child of the corresponding toolbar item of the parent toolbar + return css::uno::Reference< css::accessibility::XAccessible >(); +} + +ImplDockingWindowWrapper::ImplDockingWindowWrapper( const vcl::Window *pWindow ) + : mpDockingWindow(const_cast<vcl::Window*>(pWindow)) + , mpFloatWin(nullptr) + , mpOldBorderWin(nullptr) + , mpParent(pWindow->GetParent()) + , maMaxOutSize( SHRT_MAX, SHRT_MAX ) + , mnTrackX(0) + , mnTrackY(0) + , mnTrackWidth(0) + , mnTrackHeight(0) + , mnDockLeft(0) + , mnDockTop(0) + , mnDockRight(0) + , mnDockBottom(0) + , mnFloatBits(WB_BORDER | WB_CLOSEABLE | WB_SIZEABLE | (pWindow->GetStyle() & DOCKWIN_FLOATSTYLES)) + , mbDockCanceled(false) + , mbDocking(false) + , mbLastFloatMode(false) + , mbDockBtn(false) + , mbHideBtn(false) + // must be enabled in Window::Notify to prevent permanent docking during mouse move + , mbStartDockingEnabled(false) + , mbLocked(false) +{ + assert(mpDockingWindow); + DockingWindow *pDockWin = dynamic_cast< DockingWindow* > ( mpDockingWindow.get() ); + if( pDockWin ) + mnFloatBits = pDockWin->GetFloatStyle(); +} + +ImplDockingWindowWrapper::~ImplDockingWindowWrapper() +{ + if ( IsFloatingMode() ) + { + GetWindow()->Show( false, ShowFlags::NoFocusChange ); + SetFloatingMode(false); + } +} + +void ImplDockingWindowWrapper::ImplStartDocking( const Point& rPos ) +{ + if( !mbStartDockingEnabled ) + return; + + maMouseOff = rPos; + mbDocking = true; + mbLastFloatMode = IsFloatingMode(); + + // calculate FloatingBorder + VclPtr<FloatingWindow> pWin; + if ( mpFloatWin ) + pWin = mpFloatWin; + else + pWin = VclPtr<ImplDockFloatWin2>::Create( mpParent, mnFloatBits, nullptr ); + pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom ); + if ( !mpFloatWin ) + pWin.disposeAndClear(); + + Point aPos = GetWindow()->ImplOutputToFrame( Point() ); + Size aSize = GetWindow()->GetOutputSizePixel(); + mnTrackX = aPos.X(); + mnTrackY = aPos.Y(); + mnTrackWidth = aSize.Width(); + mnTrackHeight = aSize.Height(); + + if ( mbLastFloatMode ) + { + maMouseOff.AdjustX(mnDockLeft ); + maMouseOff.AdjustY(mnDockTop ); + mnTrackX -= mnDockLeft; + mnTrackY -= mnDockTop; + mnTrackWidth += mnDockLeft+mnDockRight; + mnTrackHeight += mnDockTop+mnDockBottom; + } + + vcl::Window *pDockingArea = GetWindow()->GetParent(); + vcl::Window::PointerState aState = pDockingArea->GetPointerState(); + + // mouse pos in screen pixels + Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos ); + Point aDockPos = pDockingArea->AbsoluteScreenToOutputPixel( GetWindow()->OutputToAbsoluteScreenPixel( GetWindow()->GetPosPixel() ) ); + tools::Rectangle aDockRect( aDockPos, GetWindow()->GetSizePixel() ); + StartDocking( aMousePos, aDockRect ); + + GetWindow()->ImplUpdateAll(); + GetWindow()->ImplGetFrameWindow()->ImplUpdateAll(); + + GetWindow()->StartTracking( StartTrackingFlags::KeyMod ); +} + +void ImplDockingWindowWrapper::Tracking( const TrackingEvent& rTEvt ) +{ + // used during docking of a currently docked window + if ( !mbDocking ) + return; + + if ( rTEvt.IsTrackingEnded() ) + { + mbDocking = false; + GetWindow()->HideTracking(); + if ( rTEvt.IsTrackingCanceled() ) + { + mbDockCanceled = true; + EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode ); + mbDockCanceled = false; + } + else + EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode ); + } + // Docking only upon non-synthetic MouseEvents + else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() ) + { + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + Point aFrameMousePos = GetWindow()->ImplOutputToFrame( aMousePos ); + Size aFrameSize = GetWindow()->ImplGetFrameWindow()->GetOutputSizePixel(); + if ( aFrameMousePos.X() < 0 ) + aFrameMousePos.setX( 0 ); + if ( aFrameMousePos.Y() < 0 ) + aFrameMousePos.setY( 0 ); + if ( aFrameMousePos.X() > aFrameSize.Width()-1 ) + aFrameMousePos.setX( aFrameSize.Width()-1 ); + if ( aFrameMousePos.Y() > aFrameSize.Height()-1 ) + aFrameMousePos.setY( aFrameSize.Height()-1 ); + aMousePos = GetWindow()->ImplFrameToOutput( aFrameMousePos ); + aMousePos.AdjustX( -(maMouseOff.X()) ); + aMousePos.AdjustY( -(maMouseOff.Y()) ); + Point aPos = GetWindow()->ImplOutputToFrame( aMousePos ); + tools::Rectangle aTrackRect( aPos, Size( mnTrackWidth, mnTrackHeight ) ); + tools::Rectangle aCompRect = aTrackRect; + aPos.AdjustX(maMouseOff.X() ); + aPos.AdjustY(maMouseOff.Y() ); + + bool bFloatMode = Docking( aPos, aTrackRect ); + + if ( mbLastFloatMode != bFloatMode ) + { + if ( bFloatMode ) + { + aTrackRect.AdjustLeft( -mnDockLeft ); + aTrackRect.AdjustTop( -mnDockTop ); + aTrackRect.AdjustRight(mnDockRight ); + aTrackRect.AdjustBottom(mnDockBottom ); + } + else + { + if ( aCompRect == aTrackRect ) + { + aTrackRect.AdjustLeft(mnDockLeft ); + aTrackRect.AdjustTop(mnDockTop ); + aTrackRect.AdjustRight( -mnDockRight ); + aTrackRect.AdjustBottom( -mnDockBottom ); + } + } + mbLastFloatMode = bFloatMode; + } + + ShowTrackFlags nTrackStyle; + if ( bFloatMode ) + nTrackStyle = ShowTrackFlags::Object; + else + nTrackStyle = ShowTrackFlags::Big; + tools::Rectangle aShowTrackRect = aTrackRect; + aShowTrackRect.SetPos( GetWindow()->ImplFrameToOutput( aShowTrackRect.TopLeft() ) ); + + GetWindow()->ShowTracking( aShowTrackRect, nTrackStyle ); + + // calculate mouse offset again, as the rectangle was changed + maMouseOff.setX( aPos.X() - aTrackRect.Left() ); + maMouseOff.setY( aPos.Y() - aTrackRect.Top() ); + + mnTrackX = aTrackRect.Left(); + mnTrackY = aTrackRect.Top(); + mnTrackWidth = aTrackRect.GetWidth(); + mnTrackHeight = aTrackRect.GetHeight(); + } +} + +void ImplDockingWindowWrapper::StartDocking( const Point& rPoint, tools::Rectangle const & rRect ) +{ + DockingData data( rPoint, rRect, IsFloatingMode() ); + + GetWindow()->CallEventListeners( VclEventId::WindowStartDocking, &data ); + mbDocking = true; +} + +bool ImplDockingWindowWrapper::Docking( const Point& rPoint, tools::Rectangle& rRect ) +{ + DockingData data( rPoint, rRect, IsFloatingMode() ); + + GetWindow()->CallEventListeners( VclEventId::WindowDocking, &data ); + rRect = data.maTrackRect; + return data.mbFloating; +} + +void ImplDockingWindowWrapper::EndDocking( const tools::Rectangle& rRect, bool bFloatMode ) +{ + tools::Rectangle aRect( rRect ); + + bool bOrigDockCanceled = mbDockCanceled; + if (bFloatMode && !StyleSettings::GetDockingFloatsSupported()) + mbDockCanceled = true; + + if ( !IsDockingCanceled() ) + { + bool bShow = false; + if ( bFloatMode != IsFloatingMode() ) + { + GetWindow()->Show( false, ShowFlags::NoFocusChange ); + SetFloatingMode( bFloatMode ); + bShow = true; + if ( bFloatMode ) + { + // #i44800# always use outputsize - as in all other places + mpFloatWin->SetOutputSizePixel( aRect.GetSize() ); + mpFloatWin->SetPosPixel( aRect.TopLeft() ); + } + } + if ( !bFloatMode ) + { + Point aPos = aRect.TopLeft(); + aPos = GetWindow()->GetParent()->ScreenToOutputPixel( aPos ); + GetWindow()->SetPosSizePixel( aPos, aRect.GetSize() ); + } + + if ( bShow ) + GetWindow()->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate ); + } + + EndDockingData data( aRect, IsFloatingMode(), IsDockingCanceled() ); + GetWindow()->CallEventListeners( VclEventId::WindowEndDocking, &data ); + + mbDocking = false; + + // must be enabled in Window::Notify to prevent permanent docking during mouse move + mbStartDockingEnabled = false; + + mbDockCanceled = bOrigDockCanceled; +} + +bool ImplDockingWindowWrapper::PrepareToggleFloatingMode() +{ + bool bFloating = true; + GetWindow()->CallEventListeners( VclEventId::WindowPrepareToggleFloating, &bFloating ); + return bFloating; +} + +void ImplDockingWindowWrapper::ToggleFloatingMode() +{ + // notify dockingwindow/toolbox + // note: this must be done *before* notifying the + // listeners to have the toolbox in the proper state + if( GetWindow()->IsDockingWindow() ) + static_cast<DockingWindow*>(GetWindow())->ToggleFloatingMode(); + + // now notify listeners + GetWindow()->CallEventListeners( VclEventId::WindowToggleFloating ); + + // must be enabled in Window::Notify to prevent permanent docking during mouse move + mbStartDockingEnabled = false; +} + +void ImplDockingWindowWrapper::TitleButtonClick( TitleButton nType ) +{ + if( nType == TitleButton::Menu ) + { + ToolBox *pToolBox = dynamic_cast< ToolBox* >( GetWindow() ); + if( pToolBox ) + { + pToolBox->ExecuteCustomMenu(); + } + } + if( nType == TitleButton::Docking ) + { + SetFloatingMode( !IsFloatingMode() ); + } +} + +void ImplDockingWindowWrapper::Resizing( Size& rSize ) +{ + // TODO: add virtual Resizing() to class Window, so we can get rid of class DockingWindow + DockingWindow *pDockingWindow = dynamic_cast< DockingWindow* >( GetWindow() ); + if( pDockingWindow ) + pDockingWindow->Resizing( rSize ); +} + +void ImplDockingWindowWrapper::ShowMenuTitleButton( bool bVisible ) +{ + if ( mpFloatWin ) + mpFloatWin->ShowTitleButton( TitleButton::Menu, bVisible ); +} + +void ImplDockingWindowWrapper::ImplPreparePopupMode() +{ + VclPtr<vcl::Window> xWindow = GetWindow(); + xWindow->Show( false, ShowFlags::NoFocusChange ); + + // prepare reparenting + vcl::Window* pRealParent = xWindow->GetWindow( GetWindowType::Parent ); + mpOldBorderWin = xWindow->GetWindow( GetWindowType::Border ); + if( mpOldBorderWin.get() == xWindow ) + mpOldBorderWin = nullptr; // no border window found + + // the new parent for popup mode + VclPtrInstance<ImplPopupFloatWin> pWin( mpParent, xWindow->GetType() == WindowType::TOOLBOX ); + pWin->SetPopupModeEndHdl( LINK( this, ImplDockingWindowWrapper, PopupModeEnd ) ); + + // At least for DockingWindow, GetText() has a side effect of setting deferred + // properties. This must be done before setting the border window (see below), + // so that the border width will end up in mpWindowImpl->mnBorderWidth, not in + // the border window (See DockingWindow::setPosSizeOnContainee() and + // DockingWindow::GetOptimalSize()). + pWin->SetText( xWindow->GetText() ); + pWin->SetOutputSizePixel( xWindow->GetSizePixel() ); + + xWindow->mpWindowImpl->mpBorderWindow = nullptr; + xWindow->mpWindowImpl->mnLeftBorder = 0; + xWindow->mpWindowImpl->mnTopBorder = 0; + xWindow->mpWindowImpl->mnRightBorder = 0; + xWindow->mpWindowImpl->mnBottomBorder = 0; + + // reparent borderwindow and window + if ( mpOldBorderWin ) + mpOldBorderWin->SetParent( pWin ); + xWindow->SetParent( pWin ); + + // correct border window pointers + xWindow->mpWindowImpl->mpBorderWindow = pWin; + pWin->mpWindowImpl->mpClientWindow = xWindow; + xWindow->mpWindowImpl->mpRealParent = pRealParent; + + // set mpFloatWin not until all window positioning is done !!! + // (SetPosPixel etc. check for valid mpFloatWin pointer) + mpFloatWin = pWin; +} + +void ImplDockingWindowWrapper::StartPopupMode( ToolBox *pParentToolBox, FloatWinPopupFlags nFlags ) +{ + // do nothing if window is floating + if( IsFloatingMode() ) + return; + + ImplPreparePopupMode(); + + // don't allow tearoff, if globally disabled + if( !StyleSettings::GetDockingFloatsSupported() ) + nFlags &= ~FloatWinPopupFlags::AllowTearOff; + + // if the subtoolbar was opened via keyboard make sure that key events + // will go into subtoolbar + if( pParentToolBox->IsKeyEvent() ) + nFlags |= FloatWinPopupFlags::GrabFocus; + + mpFloatWin->StartPopupMode( pParentToolBox, nFlags ); + GetWindow()->Show(); + + if( pParentToolBox->IsKeyEvent() ) + { + // send HOME key to subtoolbar in order to select first item + KeyEvent aEvent( 0, vcl::KeyCode( KEY_HOME ) ); + GetWindow()->KeyInput(aEvent); + } +} + +void ImplDockingWindowWrapper::StartPopupMode( const tools::Rectangle& rRect, FloatWinPopupFlags nFlags ) +{ + // do nothing if window is floating + if( IsFloatingMode() ) + return; + + ImplPreparePopupMode(); + mpFloatWin->StartPopupMode( rRect, nFlags ); + GetWindow()->Show(); +} + +IMPL_LINK_NOARG(ImplDockingWindowWrapper, PopupModeEnd, FloatingWindow*, void) +{ + VclPtr<vcl::Window> xWindow = GetWindow(); + xWindow->Show( false, ShowFlags::NoFocusChange ); + + // set parameter for handler before destroying floating window + EndPopupModeData aData( mpFloatWin->GetWindow( GetWindowType::Border )->GetPosPixel(), mpFloatWin->IsPopupModeTearOff() ); + + // before deleting change parent back, so we can delete the floating window alone + vcl::Window* pRealParent = xWindow->GetWindow( GetWindowType::Parent ); + xWindow->mpWindowImpl->mpBorderWindow = nullptr; + if ( mpOldBorderWin ) + { + xWindow->SetParent( mpOldBorderWin ); + static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder( + xWindow->mpWindowImpl->mnLeftBorder, xWindow->mpWindowImpl->mnTopBorder, + xWindow->mpWindowImpl->mnRightBorder, xWindow->mpWindowImpl->mnBottomBorder ); + mpOldBorderWin->Resize(); + } + xWindow->mpWindowImpl->mpBorderWindow = mpOldBorderWin; + xWindow->SetParent( pRealParent ); + xWindow->mpWindowImpl->mpRealParent = pRealParent; + + // take ownership to local variable to protect against maPopupModeEndHdl destroying this object + auto xFloatWin = std::move(mpFloatWin); + maPopupModeEndHdl.Call(xFloatWin); + xFloatWin.disposeAndClear(); + + // call handler - which will destroy the window and thus the wrapper as well ! + xWindow->CallEventListeners( VclEventId::WindowEndPopupMode, &aData ); +} + +bool ImplDockingWindowWrapper::IsInPopupMode() const +{ + if( GetFloatingWindow() ) + return static_cast<FloatingWindow*>(GetFloatingWindow())->IsInPopupMode(); + else + return false; +} + +void ImplDockingWindowWrapper::SetFloatingMode( bool bFloatMode ) +{ + // do nothing if window is docked and locked + if( !IsFloatingMode() && IsLocked() ) + return; + + if ( IsFloatingMode() == bFloatMode ) + return; + + if ( !PrepareToggleFloatingMode() ) + return; + + bool bVisible = GetWindow()->IsVisible(); + + if ( bFloatMode ) + { + GetWindow()->Show( false, ShowFlags::NoFocusChange ); + + maDockPos = GetWindow()->GetPosPixel(); + + vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent ); + mpOldBorderWin = GetWindow()->GetWindow( GetWindowType::Border ); + if( mpOldBorderWin == mpDockingWindow ) + mpOldBorderWin = nullptr; // no border window found + + VclPtrInstance<ImplDockFloatWin2> pWin( + mpParent, + mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? + mnFloatBits | WB_SYSTEMWINDOW + | WB_OWNERDRAWDECORATION + : mnFloatBits, + this ); + + // At least for DockingWindow, GetText() has a side effect of setting deferred + // properties. This must be done before setting the border window (see below), + // so that the border width will end up in mpWindowImpl->mnBorderWidth, not in + // the border window (See DockingWindow::setPosSizeOnContainee() and + // DockingWindow::GetOptimalSize()). + pWin->SetText( GetWindow()->GetText() ); + + GetWindow()->mpWindowImpl->mpBorderWindow = nullptr; + GetWindow()->mpWindowImpl->mnLeftBorder = 0; + GetWindow()->mpWindowImpl->mnTopBorder = 0; + GetWindow()->mpWindowImpl->mnRightBorder = 0; + GetWindow()->mpWindowImpl->mnBottomBorder = 0; + + // if the parent gets destroyed, we also have to reset the parent of the BorderWindow + if ( mpOldBorderWin ) + mpOldBorderWin->SetParent( pWin ); + GetWindow()->SetParent( pWin ); + pWin->SetPosPixel( Point() ); + + GetWindow()->mpWindowImpl->mpBorderWindow = pWin; + pWin->mpWindowImpl->mpClientWindow = mpDockingWindow; + GetWindow()->mpWindowImpl->mpRealParent = pRealParent; + + pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() ); + pWin->SetPosPixel( maFloatPos ); + // pass on DockingData to FloatingWindow + pWin->ShowTitleButton( TitleButton::Docking, mbDockBtn ); + pWin->ShowTitleButton( TitleButton::Hide, mbHideBtn ); + pWin->SetMinOutputSizePixel( maMinOutSize ); + pWin->SetMaxOutputSizePixel( maMaxOutSize ); + + mpFloatWin = pWin; + + if ( bVisible ) + GetWindow()->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate ); + + ToggleFloatingMode(); + } + else + { + GetWindow()->Show( false, ShowFlags::NoFocusChange ); + + // store FloatingData in FloatingWindow + maFloatPos = mpFloatWin->GetPosPixel(); + mbDockBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Docking ); + mbHideBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Hide ); + maMinOutSize = mpFloatWin->GetMinOutputSizePixel(); + maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel(); + + vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent ); //mpWindowImpl->mpRealParent; + GetWindow()->mpWindowImpl->mpBorderWindow = nullptr; + if ( mpOldBorderWin ) + { + GetWindow()->SetParent( mpOldBorderWin ); + static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder( + GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder, + GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder ); + mpOldBorderWin->Resize(); + } + GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin; + GetWindow()->SetParent( pRealParent ); + GetWindow()->mpWindowImpl->mpRealParent = pRealParent; + + mpFloatWin.disposeAndClear(); + GetWindow()->SetPosPixel( maDockPos ); + + if ( bVisible ) + GetWindow()->Show(); + + ToggleFloatingMode(); + + } +} + +void ImplDockingWindowWrapper::SetFloatStyle( WinBits nStyle ) +{ + mnFloatBits = nStyle; +} + + +void ImplDockingWindowWrapper::setPosSizePixel( tools::Long nX, tools::Long nY, + tools::Long nWidth, tools::Long nHeight, + PosSizeFlags nFlags ) +{ + if ( mpFloatWin ) + mpFloatWin->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); + else + GetWindow()->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); +} + +Point ImplDockingWindowWrapper::GetPosPixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetPosPixel(); + else + return mpDockingWindow->GetPosPixel(); +} + +Size ImplDockingWindowWrapper::GetSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetSizePixel(); + else + return mpDockingWindow->GetSizePixel(); +} + +// old inlines from DockingWindow + +void ImplDockingWindowWrapper::SetMinOutputSizePixel( const Size& rSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetMinOutputSizePixel( rSize ); + maMinOutSize = rSize; +} + +void ImplDockingWindowWrapper::SetMaxOutputSizePixel( const Size& rSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetMaxOutputSizePixel( rSize ); + maMaxOutSize = rSize; +} + +bool ImplDockingWindowWrapper::IsFloatingMode() const +{ + return (mpFloatWin != nullptr); +} + +void ImplDockingWindowWrapper::SetDragArea( const tools::Rectangle& rRect ) +{ + maDragArea = rRect; +} + + +void ImplDockingWindowWrapper::Lock() +{ + mbLocked = true; + // only toolbars support locking + ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() ); + if( pToolBox ) + pToolBox->Lock( mbLocked ); +} + +void ImplDockingWindowWrapper::Unlock() +{ + mbLocked = false; + // only toolbars support locking + ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() ); + if( pToolBox ) + pToolBox->Lock( mbLocked ); +} + +SystemWindow* ImplDockingWindowWrapper::GetFloatingWindow() const +{ + return mpFloatWin; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |