Files
libreoffice/vcl/source/window/dockwin.cxx
Caolán McNamara 81fb7720e5 Resolves: tdf#89104 Missing actions from toolbar
Toolboxes derive from Docking Windows, they are
not layout aware, which is ok, but they need
to tell the thing they are inserted in that their
state has changed if the parent is layout aware.

i.e. docking windows are not toplevel things like
dialogs and need to pass on queue_resize to things
above them

Change-Id: If0eeff90314bef4e828355661a75a0d34a6fc1bc
2015-06-07 17:40:54 +01:00

1163 lines
35 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 <tools/time.hxx>
#include <tools/rc.h>
#include <vcl/event.hxx>
#include <vcl/floatwin.hxx>
#include <vcl/dockwin.hxx>
#include <vcl/layout.hxx>
#include <vcl/svapp.hxx>
#include <vcl/timer.hxx>
#include <vcl/idle.hxx>
#include <vcl/unowrap.hxx>
#include <vcl/settings.hxx>
#include <svdata.hxx>
#include <window.h>
#include <brdwin.hxx>
#include <salframe.hxx>
#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_PINABLE | WB_ROLLABLE )
class DockingWindow::ImplData
{
public:
ImplData();
~ImplData();
VclPtr<vcl::Window> mpParent;
Size maMaxOutSize;
};
DockingWindow::ImplData::ImplData()
{
mpParent = NULL;
maMaxOutSize = Size( SHRT_MAX, SHRT_MAX );
}
DockingWindow::ImplData::~ImplData()
{
}
class ImplDockFloatWin : public FloatingWindow
{
private:
VclPtr<DockingWindow> mpDockWin;
sal_uInt64 mnLastTicks;
Idle maDockIdle;
Point maDockPos;
Rectangle maDockRect;
bool mbInMove;
ImplSVEvent * mnLastUserEvent;
DECL_LINK(DockingHdl, void *);
DECL_LINK_TYPED(DockTimerHdl, Idle *, void);
public:
ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits,
DockingWindow* pDockingWin );
virtual ~ImplDockFloatWin();
virtual void dispose() SAL_OVERRIDE;
virtual void Move() SAL_OVERRIDE;
virtual void Resize() SAL_OVERRIDE;
virtual void TitleButtonClick( TitleButton nButton ) SAL_OVERRIDE;
virtual void Pin() SAL_OVERRIDE;
virtual void Roll() SAL_OVERRIDE;
virtual void PopupModeEnd() SAL_OVERRIDE;
virtual void Resizing( Size& rSize ) SAL_OVERRIDE;
virtual bool Close() SAL_OVERRIDE;
};
ImplDockFloatWin::ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits,
DockingWindow* pDockingWin ) :
FloatingWindow( pParent, nWinBits ),
mpDockWin( pDockingWin ),
mnLastTicks( tools::Time::GetSystemTicks() ),
mbInMove( false ),
mnLastUserEvent( 0 )
{
// copy settings of DockingWindow
if ( pDockingWin )
{
SetSettings( pDockingWin->GetSettings() );
Enable( pDockingWin->IsEnabled(), false );
EnableInput( pDockingWin->IsInputEnabled(), false );
AlwaysEnableInput( pDockingWin->IsAlwaysEnableInput(), false );
EnableAlwaysOnTop( pDockingWin->IsAlwaysOnTopEnabled() );
SetActivateMode( pDockingWin->GetActivateMode() );
}
SetBackground();
maDockIdle.SetIdleHdl( LINK( this, ImplDockFloatWin, DockTimerHdl ) );
maDockIdle.SetPriority( SchedulerPriority::MEDIUM );
}
ImplDockFloatWin::~ImplDockFloatWin()
{
disposeOnce();
}
void ImplDockFloatWin::dispose()
{
if( mnLastUserEvent )
Application::RemoveUserEvent( mnLastUserEvent );
disposeBuilder();
mpDockWin.clear();
FloatingWindow::dispose();
}
IMPL_LINK_NOARG_TYPED(ImplDockFloatWin, DockTimerHdl, Idle *, void)
{
DBG_ASSERT( mpDockWin->IsFloatingMode(), "docktimer called but not floating" );
maDockIdle.Stop();
PointerState aState = GetPointerState();
if( aState.mnState & KEY_MOD1 )
{
// i43499 CTRL disables docking now
mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
mpDockWin->EndDocking( maDockRect, true );
if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
maDockIdle.Start();
}
else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
{
mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
mpDockWin->EndDocking( maDockRect, false );
}
else
{
mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW );
maDockIdle.Start();
}
}
IMPL_LINK_NOARG(ImplDockFloatWin, DockingHdl)
{
PointerState aState = mpDockWin->GetParent()->GetPointerState();
mnLastUserEvent = 0;
if( mpDockWin->IsDockable() &&
(tools::Time::GetSystemTicks() - mnLastTicks > 500) &&
( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
!(aState.mnState & KEY_MOD1) ) // i43499 CTRL disables docking now
{
maDockPos = Point( mpDockWin->GetParent()->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) );
maDockPos = mpDockWin->GetParent()->OutputToScreenPixel( maDockPos ); // sfx expects screen coordinates
if( ! mpDockWin->IsDocking() )
mpDockWin->StartDocking();
maDockRect = Rectangle( maDockPos, mpDockWin->GetSizePixel() );
// mouse pos also in screen pixels
Point aMousePos = mpDockWin->GetParent()->OutputToScreenPixel( aState.maPos );
bool bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
if( ! bFloatMode )
{
mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_OBJECT | SHOWTRACK_WINDOW );
DockTimerHdl( nullptr );
}
else
{
mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
maDockIdle.Stop();
mpDockWin->EndDocking( maDockRect, true );
}
}
mbInMove = false;
return 0;
}
void ImplDockFloatWin::Move()
{
if( mbInMove )
return;
mbInMove = true;
FloatingWindow::Move();
mpDockWin->Move();
/*
* note: the window should only dock if
* 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, ImplDockFloatWin, DockingHdl ), NULL, true );
}
void ImplDockFloatWin::Resize()
{
FloatingWindow::Resize();
Size aSize( GetSizePixel() );
mpDockWin->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), PosSizeFlags::PosSize );
}
void ImplDockFloatWin::TitleButtonClick( TitleButton nButton )
{
FloatingWindow::TitleButtonClick( nButton );
}
void ImplDockFloatWin::Pin()
{
FloatingWindow::Pin();
}
void ImplDockFloatWin::Roll()
{
FloatingWindow::Roll();
}
void ImplDockFloatWin::PopupModeEnd()
{
FloatingWindow::PopupModeEnd();
}
void ImplDockFloatWin::Resizing( Size& rSize )
{
FloatingWindow::Resizing( rSize );
mpDockWin->Resizing( rSize );
}
bool ImplDockFloatWin::Close()
{
return mpDockWin->Close();
}
bool DockingWindow::ImplStartDocking( const Point& rPos )
{
if ( !mbDockable )
return false;
maMouseOff = rPos;
maMouseStart = maMouseOff;
mbDocking = true;
mbLastFloatMode = IsFloatingMode();
mbStartFloat = mbLastFloatMode;
// calculate FloatingBorder
VclPtr<FloatingWindow> pWin;
if ( mpFloatWin )
pWin = mpFloatWin;
else
pWin = VclPtr<ImplDockFloatWin>::Create( mpImplData->mpParent, mnFloatBits, nullptr );
pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
if ( !mpFloatWin )
pWin.disposeAndClear();
Point aPos = ImplOutputToFrame( Point() );
Size aSize = Window::GetOutputSizePixel();
mnTrackX = aPos.X();
mnTrackY = aPos.Y();
mnTrackWidth = aSize.Width();
mnTrackHeight = aSize.Height();
if ( mbLastFloatMode )
{
maMouseOff.X() += mnDockLeft;
maMouseOff.Y() += mnDockTop;
mnTrackX -= mnDockLeft;
mnTrackY -= mnDockTop;
mnTrackWidth += mnDockLeft+mnDockRight;
mnTrackHeight += mnDockTop+mnDockBottom;
}
if ( GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Docking &&
!( mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ) ) // no full drag when migrating to system window
mbDragFull = true;
else
{
StartDocking();
mbDragFull = false;
ImplUpdateAll();
ImplGetFrameWindow()->ImplUpdateAll();
}
StartTracking( StartTrackingFlags::KeyMod );
return true;
}
void DockingWindow::ImplInitDockingWindowData()
{
mpWindowImpl->mbDockWin = true;
mpFloatWin = NULL;
mpOldBorderWin = NULL;
mpImplData = new ImplData;
mnTrackX = 0;
mnTrackY = 0;
mnTrackWidth = 0;
mnTrackHeight = 0;
mnDockLeft = 0;
mnDockTop = 0;
mnDockRight = 0;
mnDockBottom = 0;
mnFloatBits = 0;
mbDockCanceled = false;
mbDockPrevented = false;
mbFloatPrevented = false;
mbDockable = false;
mbDocking = false;
mbDragFull = false;
mbLastFloatMode = false;
mbStartFloat = false;
mbTrackDock = false;
mbPinned = false;
mbRollUp = false;
mbDockBtn = false;
mbHideBtn = false;
mbIsDefferedInit = false;
mbIsCalculatingInitialLayoutSize = false;
mbInitialLayoutDone = false;
mpDialogParent = NULL;
//To-Do, reuse maResizeTimer
maLayoutIdle.SetPriority(SchedulerPriority::RESIZE);
maLayoutIdle.SetIdleHdl( LINK( this, DockingWindow, ImplHandleLayoutTimerHdl ) );
}
void DockingWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
if ( !(nStyle & WB_NODIALOGCONTROL) )
nStyle |= WB_DIALOGCONTROL;
mpImplData->mpParent = pParent;
mbDockable = (nStyle & WB_DOCKABLE) != 0;
mnFloatBits = WB_BORDER | (nStyle & DOCKWIN_FLOATSTYLES);
nStyle &= ~(DOCKWIN_FLOATSTYLES | WB_BORDER);
if ( nStyle & WB_DOCKBORDER )
nStyle |= WB_BORDER;
Window::ImplInit( pParent, nStyle, NULL );
ImplInitSettings();
}
void DockingWindow::ImplInitSettings()
{
// Hack: to be able to build DockingWindows w/o background before switching
// TODO: Hack
if ( IsBackground() )
{
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 );
}
}
void DockingWindow::ImplLoadRes( const ResId& rResId )
{
Window::ImplLoadRes( rResId );
sal_uLong nMask = ReadLongRes();
if ( (RSC_DOCKINGWINDOW_XYMAPMODE | RSC_DOCKINGWINDOW_X |
RSC_DOCKINGWINDOW_Y) & nMask )
{
// use Sizes of the Resource
Point aPos;
MapUnit ePosMap = MAP_PIXEL;
if ( RSC_DOCKINGWINDOW_XYMAPMODE & nMask )
ePosMap = (MapUnit)ReadLongRes();
if ( RSC_DOCKINGWINDOW_X & nMask )
{
aPos.X() = ReadShortRes();
aPos.X() = ImplLogicUnitToPixelX( aPos.X(), ePosMap );
}
if ( RSC_DOCKINGWINDOW_Y & nMask )
{
aPos.Y() = ReadShortRes();
aPos.Y() = ImplLogicUnitToPixelY( aPos.Y(), ePosMap );
}
SetFloatingPos( aPos );
}
if ( nMask & RSC_DOCKINGWINDOW_FLOATING )
{
if ( ReadShortRes() != 0 )
SetFloatingMode( true );
}
}
DockingWindow::DockingWindow( WindowType nType ) :
Window(nType)
{
ImplInitDockingWindowData();
}
DockingWindow::DockingWindow( vcl::Window* pParent, WinBits nStyle ) :
Window( WINDOW_DOCKINGWINDOW )
{
ImplInitDockingWindowData();
ImplInit( pParent, nStyle );
}
DockingWindow::DockingWindow( vcl::Window* pParent, const ResId& rResId ) :
Window( WINDOW_DOCKINGWINDOW )
{
ImplInitDockingWindowData();
rResId.SetRT( RSC_DOCKINGWINDOW );
WinBits nStyle = ImplInitRes( rResId );
ImplInit( pParent, nStyle );
ImplLoadRes( rResId );
if ( !(nStyle & WB_HIDE) )
Show();
}
//Find the real parent stashed in mpDialogParent.
void DockingWindow::doDeferredInit(WinBits nBits)
{
vcl::Window *pParent = mpDialogParent;
mpDialogParent = NULL;
ImplInit(pParent, nBits);
mbIsDefferedInit = false;
}
void DockingWindow::loadUI(vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription,
const css::uno::Reference<css::frame::XFrame> &rFrame)
{
mbIsDefferedInit = true;
mpDialogParent = pParent; //should be unset in doDeferredInit
m_pUIBuilder = new VclBuilder(this, getUIRootDir(), rUIXMLDescription, rID, rFrame);
}
DockingWindow::DockingWindow(vcl::Window* pParent, const OString& rID,
const OUString& rUIXMLDescription, const css::uno::Reference<css::frame::XFrame> &rFrame)
: Window(WINDOW_DOCKINGWINDOW)
{
ImplInitDockingWindowData();
loadUI(pParent, rID, rUIXMLDescription, rFrame);
}
DockingWindow::~DockingWindow()
{
disposeOnce();
}
void DockingWindow::dispose()
{
if ( IsFloatingMode() )
{
Show( false, ShowFlags::NoFocusChange );
SetFloatingMode( false );
}
delete mpImplData;
mpImplData = NULL;
mpFloatWin.clear();
mpOldBorderWin.clear();
mpDialogParent.clear();
disposeBuilder();
Window::dispose();
}
void DockingWindow::Tracking( const TrackingEvent& rTEvt )
{
if( GetDockingManager()->IsDockable( this ) ) // new docking interface
return Window::Tracking( rTEvt );
if ( mbDocking )
{
if ( rTEvt.IsTrackingEnded() )
{
mbDocking = false;
if ( mbDragFull )
{
// reset old state on Cancel
if ( rTEvt.IsTrackingCanceled() )
{
StartDocking();
Rectangle aRect( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) );
EndDocking( aRect, mbStartFloat );
}
}
else
{
HideTracking();
if ( rTEvt.IsTrackingCanceled() )
{
mbDockCanceled = true;
EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
mbDockCanceled = false;
}
else
EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
}
}
// dock only for non-synthetic MouseEvents
else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
{
Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
Point aFrameMousePos = ImplOutputToFrame( aMousePos );
Size aFrameSize = mpWindowImpl->mpFrameWindow->GetOutputSizePixel();
if ( aFrameMousePos.X() < 0 )
aFrameMousePos.X() = 0;
if ( aFrameMousePos.Y() < 0 )
aFrameMousePos.Y() = 0;
if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
aFrameMousePos.X() = aFrameSize.Width()-1;
if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
aFrameMousePos.Y() = aFrameSize.Height()-1;
aMousePos = ImplFrameToOutput( aFrameMousePos );
aMousePos.X() -= maMouseOff.X();
aMousePos.Y() -= maMouseOff.Y();
Point aFramePos = ImplOutputToFrame( aMousePos );
Rectangle aTrackRect( aFramePos, Size( mnTrackWidth, mnTrackHeight ) );
Rectangle aCompRect = aTrackRect;
aFramePos.X() += maMouseOff.X();
aFramePos.Y() += maMouseOff.Y();
if ( mbDragFull )
StartDocking();
bool bFloatMode = Docking( aFramePos, aTrackRect );
mbDockPrevented = false;
mbFloatPrevented = false;
if ( mbLastFloatMode != bFloatMode )
{
if ( bFloatMode )
{
aTrackRect.Left() -= mnDockLeft;
aTrackRect.Top() -= mnDockTop;
aTrackRect.Right() += mnDockRight;
aTrackRect.Bottom() += mnDockBottom;
}
else
{
if ( aCompRect == aTrackRect )
{
aTrackRect.Left() += mnDockLeft;
aTrackRect.Top() += mnDockTop;
aTrackRect.Right() -= mnDockRight;
aTrackRect.Bottom() -= mnDockBottom;
}
}
mbLastFloatMode = bFloatMode;
}
if ( mbDragFull )
{
Point aPos;
Point aOldPos = OutputToScreenPixel( aPos );
EndDocking( aTrackRect, mbLastFloatMode );
// repaint if state or position has changed
if ( aOldPos != OutputToScreenPixel( aPos ) )
{
ImplUpdateAll();
ImplGetFrameWindow()->ImplUpdateAll();
}
// EndDocking( aTrackRect, mbLastFloatMode );
}
else
{
sal_uInt16 nTrackStyle;
if ( bFloatMode )
nTrackStyle = SHOWTRACK_BIG;
else
nTrackStyle = SHOWTRACK_OBJECT;
Rectangle aShowTrackRect = aTrackRect;
aShowTrackRect.SetPos( ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
ShowTracking( aShowTrackRect, nTrackStyle );
// recalculate mouse offset, as the rectangle was changed
maMouseOff.X() = aFramePos.X() - aTrackRect.Left();
maMouseOff.Y() = aFramePos.Y() - aTrackRect.Top();
}
mnTrackX = aTrackRect.Left();
mnTrackY = aTrackRect.Top();
mnTrackWidth = aTrackRect.GetWidth();
mnTrackHeight = aTrackRect.GetHeight();
}
}
}
bool DockingWindow::Notify( NotifyEvent& rNEvt )
{
if( GetDockingManager()->IsDockable( this ) ) // new docking interface
return Window::Notify( rNEvt );
if ( mbDockable )
{
if ( rNEvt.GetType() == MouseNotifyEvent::MOUSEBUTTONDOWN )
{
const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
if ( pMEvt->IsLeft() )
{
if ( pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) )
{
SetFloatingMode( !IsFloatingMode() );
return true;
}
else if ( pMEvt->GetClicks() == 1 )
{
// check if window is floating standalone (IsFloating())
// or only partially floating and still docked with one border
// ( !mpWindowImpl->mbFrame)
if( ! IsFloatingMode() || ! mpFloatWin->mpWindowImpl->mbFrame )
{
Point aPos = pMEvt->GetPosPixel();
vcl::Window* pWindow = rNEvt.GetWindow();
if ( pWindow != this )
{
aPos = pWindow->OutputToScreenPixel( aPos );
aPos = ScreenToOutputPixel( aPos );
}
ImplStartDocking( aPos );
}
return true;
}
}
}
else if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
{
const vcl::KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode();
if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
rKey.IsShift() && rKey.IsMod1() )
{
SetFloatingMode( !IsFloatingMode() );
return true;
}
}
}
return Window::Notify( rNEvt );
}
void DockingWindow::StartDocking()
{
mbDocking = true;
}
bool DockingWindow::Docking( const Point&, Rectangle& )
{
return IsFloatingMode();
}
void DockingWindow::EndDocking( const Rectangle& rRect, bool bFloatMode )
{
if ( !IsDockingCanceled() )
{
bool bShow = false;
if ( bool(bFloatMode) != IsFloatingMode() )
{
Show( false, ShowFlags::NoFocusChange );
SetFloatingMode( bFloatMode );
bShow = true;
if ( bFloatMode && mpFloatWin )
mpFloatWin->SetPosSizePixel( rRect.TopLeft(), rRect.GetSize() );
}
if ( !bFloatMode )
{
Point aPos = rRect.TopLeft();
aPos = GetParent()->ScreenToOutputPixel( aPos );
Window::SetPosSizePixel( aPos, rRect.GetSize() );
}
if ( bShow )
Show();
}
mbDocking = false;
}
bool DockingWindow::PrepareToggleFloatingMode()
{
return true;
}
bool DockingWindow::Close()
{
ImplDelData aDelData;
ImplAddDel( &aDelData );
CallEventListeners( VCLEVENT_WINDOW_CLOSE );
if ( aDelData.IsDead() )
return false;
ImplRemoveDel( &aDelData );
if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() )
return false;
Show( false, ShowFlags::NoFocusChange );
return true;
}
void DockingWindow::ToggleFloatingMode()
{
}
void DockingWindow::Resizing( Size& )
{
}
void DockingWindow::DoInitialLayout()
{
if ( GetSettings().GetStyleSettings().GetAutoMnemonic() )
ImplWindowAutoMnemonic( this );
if (isLayoutEnabled())
{
mbIsCalculatingInitialLayoutSize = true;
setDeferredProperties();
setOptimalLayoutSize();
mbIsCalculatingInitialLayoutSize = false;
mbInitialLayoutDone = true;
}
}
void DockingWindow::StateChanged( StateChangedType nType )
{
switch(nType)
{
case StateChangedType::InitShow:
DoInitialLayout();
break;
case StateChangedType::ControlBackground:
ImplInitSettings();
Invalidate();
break;
case StateChangedType::Style:
mbDockable = (GetStyle() & WB_DOCKABLE) != 0;
break;
default:
break;
}
Window::StateChanged( nType );
}
void DockingWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
(rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
{
ImplInitSettings();
Invalidate();
}
else
Window::DataChanged( rDCEvt );
}
void DockingWindow::SetFloatingMode( bool bFloatMode )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
pWrapper->SetFloatingMode( bFloatMode );
return;
}
if ( IsFloatingMode() != bFloatMode )
{
if ( PrepareToggleFloatingMode() ) // changes to floating mode can be vetoed
{
bool bVisible = IsVisible();
if ( bFloatMode )
{
Show( false, ShowFlags::NoFocusChange );
sal_Int32 nBorderWidth = get_border_width();
maDockPos = Window::GetPosPixel();
vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
mpOldBorderWin = mpWindowImpl->mpBorderWindow;
ImplDockFloatWin* pWin =
VclPtr<ImplDockFloatWin>::Create(
mpImplData->mpParent,
mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits,
this );
mpFloatWin = pWin;
mpWindowImpl->mpBorderWindow = NULL;
mpWindowImpl->mnLeftBorder = 0;
mpWindowImpl->mnTopBorder = 0;
mpWindowImpl->mnRightBorder = 0;
mpWindowImpl->mnBottomBorder = 0;
// if the parent gets destroyed, we also have to reset the parent of the BorderWindow
if ( mpOldBorderWin )
mpOldBorderWin->SetParent( pWin );
// #i123765# reset the buffered DropTargets when undocking, else it may not
// be correctly initialized
mpWindowImpl->mxDNDListenerContainer.clear();
SetParent( pWin );
SetPosPixel( Point() );
mpWindowImpl->mpBorderWindow = pWin;
pWin->mpWindowImpl->mpClientWindow = this;
mpWindowImpl->mpRealParent = pRealParent;
pWin->SetText( Window::GetText() );
Size aSize(Window::GetSizePixel());
pWin->SetOutputSizePixel(aSize);
pWin->SetPosPixel( maFloatPos );
// pass on DockingData to FloatingWindow
pWin->ShowTitleButton( TitleButton::Docking, mbDockBtn );
pWin->ShowTitleButton( TitleButton::Hide, mbHideBtn );
pWin->SetPin( mbPinned );
if ( mbRollUp )
pWin->RollUp();
else
pWin->RollDown();
pWin->SetRollUpOutputSizePixel( maRollUpOutSize );
pWin->SetMinOutputSizePixel( maMinOutSize );
pWin->SetMaxOutputSizePixel( mpImplData->maMaxOutSize );
ToggleFloatingMode();
set_border_width(nBorderWidth);
if ( bVisible )
Show();
mpFloatWin->queue_resize();
}
else
{
Show( false, ShowFlags::NoFocusChange );
sal_Int32 nBorderWidth = get_border_width();
// store FloatingData in FloatingWindow
maFloatPos = mpFloatWin->GetPosPixel();
mbDockBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Docking );
mbHideBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Hide );
mbPinned = mpFloatWin->IsPinned();
mbRollUp = mpFloatWin->IsRollUp();
maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel();
maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
mpImplData->maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
mpWindowImpl->mpBorderWindow = NULL;
if ( mpOldBorderWin )
{
SetParent( mpOldBorderWin );
static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
mpOldBorderWin->Resize();
}
mpWindowImpl->mpBorderWindow = mpOldBorderWin;
SetParent( pRealParent );
mpWindowImpl->mpRealParent = pRealParent;
mpFloatWin.disposeAndClear();
SetPosPixel( maDockPos );
ToggleFloatingMode();
set_border_width(nBorderWidth);
if ( bVisible )
Show();
}
}
}
}
void DockingWindow::SetFloatStyle( WinBits nStyle )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
pWrapper->SetFloatStyle( nStyle );
return;
}
mnFloatBits = nStyle;
}
WinBits DockingWindow::GetFloatStyle() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
return pWrapper->GetFloatStyle();
}
return mnFloatBits;
}
void DockingWindow::setPosSizePixel( long nX, long nY,
long nWidth, long nHeight,
PosSizeFlags nFlags )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if (pWrapper)
{
if (!pWrapper->mpFloatWin)
Window::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
}
else
{
if (!mpFloatWin)
Window::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
}
if (::isLayoutEnabled(this))
{
Size aSize(GetSizePixel());
sal_Int32 nBorderWidth = get_border_width();
aSize.Width() -= 2 * nBorderWidth;
aSize.Height() -= 2 * nBorderWidth;
Point aPos(nBorderWidth, nBorderWidth);
Window *pBox = GetWindow(GetWindowType::FirstChild);
assert(pBox);
VclContainer::setLayoutAllocation(*pBox, aPos, aSize);
}
}
Point DockingWindow::GetPosPixel() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
return pWrapper->mpFloatWin->GetPosPixel();
else
return Window::GetPosPixel();
}
if ( mpFloatWin )
return mpFloatWin->GetPosPixel();
else
return Window::GetPosPixel();
}
Size DockingWindow::GetSizePixel() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
return pWrapper->mpFloatWin->GetSizePixel();
else
return Window::GetSizePixel();
}
if ( mpFloatWin )
return mpFloatWin->GetSizePixel();
else
return Window::GetSizePixel();
}
void DockingWindow::SetOutputSizePixel( const Size& rNewSize )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
pWrapper->mpFloatWin->SetOutputSizePixel( rNewSize );
else
Window::SetOutputSizePixel( rNewSize );
return;
}
if ( mpFloatWin )
mpFloatWin->SetOutputSizePixel( rNewSize );
else
Window::SetOutputSizePixel( rNewSize );
}
Size DockingWindow::GetOutputSizePixel() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
return pWrapper->mpFloatWin->GetOutputSizePixel();
else
return Window::GetOutputSizePixel();
}
if ( mpFloatWin )
return mpFloatWin->GetOutputSizePixel();
else
return Window::GetOutputSizePixel();
}
Point DockingWindow::GetFloatingPos() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
{
if ( pWrapper->mpFloatWin )
{
WindowStateData aData;
aData.SetMask( WINDOWSTATE_MASK_POS );
pWrapper->mpFloatWin->GetWindowStateData( aData );
Point aPos( aData.GetX(), aData.GetY() );
aPos = pWrapper->mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
return aPos;
}
else
return maFloatPos;
}
if ( mpFloatWin )
{
WindowStateData aData;
aData.SetMask( WINDOWSTATE_MASK_POS );
mpFloatWin->GetWindowStateData( aData );
Point aPos( aData.GetX(), aData.GetY() );
aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
return aPos;
}
else
return maFloatPos;
}
bool DockingWindow::IsFloatingMode() const
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
return pWrapper->IsFloatingMode();
else
return (mpFloatWin != nullptr);
}
void DockingWindow::SetMaxOutputSizePixel( const Size& rSize )
{
if ( mpFloatWin )
mpFloatWin->SetMaxOutputSizePixel( rSize );
mpImplData->maMaxOutSize = rSize;
}
void DockingWindow::SetText(const OUString& rStr)
{
setDeferredProperties();
Window::SetText(rStr);
}
OUString DockingWindow::GetText() const
{
const_cast<DockingWindow*>(this)->setDeferredProperties();
return Window::GetText();
}
bool DockingWindow::isLayoutEnabled() const
{
//pre dtor called, and single child is a container => we're layout enabled
return mpImplData && ::isLayoutEnabled(this);
}
void DockingWindow::setOptimalLayoutSize()
{
maLayoutIdle.Stop();
//resize DockingWindow to fit requisition on initial show
Window *pBox = GetWindow(GetWindowType::FirstChild);
Size aSize = get_preferred_size();
Size aMax(bestmaxFrameSizeForScreenSize(GetDesktopRectPixel().GetSize()));
aSize.Width() = std::min(aMax.Width(), aSize.Width());
aSize.Height() = std::min(aMax.Height(), aSize.Height());
SetMinOutputSizePixel(aSize);
SetSizePixel(aSize);
setPosSizeOnContainee(aSize, *pBox);
}
void DockingWindow::setPosSizeOnContainee(Size aSize, Window &rBox)
{
sal_Int32 nBorderWidth = get_border_width();
aSize.Width() -= 2 * nBorderWidth;
aSize.Height() -= 2 * nBorderWidth;
Point aPos(nBorderWidth, nBorderWidth);
VclContainer::setLayoutAllocation(rBox, aPos, aSize);
}
Size DockingWindow::GetOptimalSize() const
{
if (!isLayoutEnabled())
return Window::GetOptimalSize();
Size aSize = VclContainer::getLayoutRequisition(*GetWindow(GetWindowType::FirstChild));
sal_Int32 nBorderWidth = get_border_width();
aSize.Height() += mpWindowImpl->mnLeftBorder + mpWindowImpl->mnRightBorder
+ 2*nBorderWidth;
aSize.Width() += mpWindowImpl->mnTopBorder + mpWindowImpl->mnBottomBorder
+ 2*nBorderWidth;
return Window::CalcWindowSize(aSize);
}
void DockingWindow::queue_resize(StateChangedType eReason)
{
bool bTriggerLayout = true;
if (hasPendingLayout() || isCalculatingInitialLayoutSize())
{
bTriggerLayout = false;
}
if (!isLayoutEnabled())
{
bTriggerLayout = false;
}
if (bTriggerLayout)
{
InvalidateSizeCache();
maLayoutIdle.Start();
}
vcl::Window::queue_resize(eReason);
}
IMPL_LINK_NOARG_TYPED(DockingWindow, ImplHandleLayoutTimerHdl, Idle*, void)
{
if (!isLayoutEnabled())
{
SAL_WARN("vcl.layout", "DockingWindow has become non-layout because extra children have been added directly to it.");
return;
}
Window *pBox = GetWindow(GetWindowType::FirstChild);
assert(pBox);
setPosSizeOnContainee(GetSizePixel(), *pBox);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */