summaryrefslogtreecommitdiffstats
path: root/vcl/source/window/dockmgr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/window/dockmgr.cxx')
-rw-r--r--vcl/source/window/dockmgr.cxx1083
1 files changed, 1083 insertions, 0 deletions
diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx
new file mode 100644
index 0000000000..7cde1910fe
--- /dev/null
+++ b/vcl/source/window/dockmgr.cxx
@@ -0,0 +1,1083 @@
+/* -*- 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()->OutputToScreenPixel( 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()->OutputToScreenPixel( 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()->ScreenToOutputPixel( aFrameMousePos );
+ aMousePos.AdjustX( -(maMouseOff.X()) );
+ aMousePos.AdjustY( -(maMouseOff.Y()) );
+ Point aPos = GetWindow()->OutputToScreenPixel( 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()->ScreenToOutputPixel( 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();
+ // grab focus (again) after showing docking window, as e.g. a11y focus
+ // events require window to be visible first
+ if (nFlags & FloatWinPopupFlags::GrabFocus)
+ mpFloatWin->GrabFocus();
+
+ 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();
+ // grab focus (again) after showing docking window, as e.g. a11y focus
+ // events require window to be visible first
+ if (nFlags & FloatWinPopupFlags::GrabFocus)
+ mpFloatWin->GrabFocus();
+}
+
+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: */