bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / window / dockwin.cxx
blobb0d65fbd47d674449671ff152cf1f9f332d60b08
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/time.hxx>
21 #include <sal/log.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/toolkit/floatwin.hxx>
24 #include <vcl/layout.hxx>
25 #include <vcl/dockwin.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/timer.hxx>
28 #include <vcl/idle.hxx>
29 #include <vcl/settings.hxx>
30 #include <comphelper/lok.hxx>
32 #include <accel.hxx>
33 #include <svdata.hxx>
34 #include <window.h>
35 #include <brdwin.hxx>
37 #include "impldockingwrapper.hxx"
39 #define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE)
41 class DockingWindow::ImplData
43 public:
44 ImplData();
46 VclPtr<vcl::Window> mpParent;
47 Size maMaxOutSize;
50 DockingWindow::ImplData::ImplData()
52 mpParent = nullptr;
53 maMaxOutSize = Size( SHRT_MAX, SHRT_MAX );
56 namespace {
58 class ImplDockFloatWin : public FloatingWindow
60 private:
61 VclPtr<DockingWindow> mpDockWin;
62 sal_uInt64 mnLastTicks;
63 Idle maDockIdle;
64 Point maDockPos;
65 tools::Rectangle maDockRect;
66 bool mbInMove;
67 ImplSVEvent * mnLastUserEvent;
69 DECL_LINK(DockingHdl, void *, void);
70 DECL_LINK(DockTimerHdl, Timer *, void);
71 public:
72 ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits,
73 DockingWindow* pDockingWin );
74 virtual ~ImplDockFloatWin() override;
75 virtual void dispose() override;
77 virtual void Move() override;
78 virtual void Resize() override;
79 virtual void Resizing( Size& rSize ) override;
80 virtual bool Close() override;
85 ImplDockFloatWin::ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits,
86 DockingWindow* pDockingWin ) :
87 FloatingWindow( pParent, nWinBits ),
88 mpDockWin( pDockingWin ),
89 mnLastTicks( tools::Time::GetSystemTicks() ),
90 maDockIdle( "vcl::ImplDockFloatWin maDockIdle" ),
91 mbInMove( false ),
92 mnLastUserEvent( nullptr )
94 // copy settings of DockingWindow
95 if ( pDockingWin )
97 GetOutDev()->SetSettings( pDockingWin->GetSettings() );
98 Enable( pDockingWin->IsEnabled(), false );
99 EnableInput( pDockingWin->IsInputEnabled(), false );
100 AlwaysEnableInput( pDockingWin->IsAlwaysEnableInput(), false );
101 EnableAlwaysOnTop( pDockingWin->IsAlwaysOnTopEnabled() );
102 SetActivateMode( pDockingWin->GetActivateMode() );
105 SetBackground();
107 maDockIdle.SetInvokeHandler( LINK( this, ImplDockFloatWin, DockTimerHdl ) );
108 maDockIdle.SetPriority( TaskPriority::HIGH_IDLE );
111 ImplDockFloatWin::~ImplDockFloatWin()
113 disposeOnce();
116 void ImplDockFloatWin::dispose()
118 if( mnLastUserEvent )
119 Application::RemoveUserEvent( mnLastUserEvent );
121 disposeBuilder();
123 mpDockWin.clear();
124 FloatingWindow::dispose();
127 IMPL_LINK_NOARG(ImplDockFloatWin, DockTimerHdl, Timer *, void)
129 SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "docktimer called but not floating" );
131 maDockIdle.Stop();
132 PointerState aState = GetPointerState();
134 if( aState.mnState & KEY_MOD1 )
136 // i43499 CTRL disables docking now
137 mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
138 mpDockWin->EndDocking( maDockRect, true );
139 if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
140 maDockIdle.Start();
142 else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
144 mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
145 mpDockWin->EndDocking( maDockRect, false );
147 else
149 mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow );
150 maDockIdle.Start();
154 IMPL_LINK_NOARG(ImplDockFloatWin, DockingHdl, void*, void)
156 PointerState aState = mpDockWin->GetParent()->GetPointerState();
158 mnLastUserEvent = nullptr;
159 if( mpDockWin->IsDockable() &&
160 (tools::Time::GetSystemTicks() - mnLastTicks > 500) &&
161 ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
162 !(aState.mnState & KEY_MOD1) ) // i43499 CTRL disables docking now
164 maDockPos = mpDockWin->GetParent()->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) );
165 maDockPos = mpDockWin->GetParent()->OutputToScreenPixel( maDockPos ); // sfx expects screen coordinates
167 if( ! mpDockWin->IsDocking() )
168 mpDockWin->StartDocking();
169 maDockRect = tools::Rectangle( maDockPos, mpDockWin->GetSizePixel() );
171 // mouse pos also in screen pixels
172 Point aMousePos = mpDockWin->GetParent()->OutputToScreenPixel( aState.maPos );
174 bool bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
175 if( ! bFloatMode )
177 mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Object | ShowTrackFlags::TrackWindow );
178 DockTimerHdl( nullptr );
180 else
182 mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
183 maDockIdle.Stop();
184 mpDockWin->EndDocking( maDockRect, true );
187 mbInMove = false;
190 void ImplDockFloatWin::Move()
192 if( mbInMove )
193 return;
195 mbInMove = true;
196 FloatingWindow::Move();
197 mpDockWin->Move();
200 * note: the window should only dock if
201 * the user releases all mouse buttons. The real problem here
202 * is that we don't get mouse events (at least not on X)
203 * if the mouse is on the decoration. So we have to start an
204 * awkward timer based process that polls the modifier/buttons
205 * to see whether they are in the right condition shortly after the
206 * last Move message.
208 if( ! mnLastUserEvent )
209 mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin, DockingHdl ), nullptr, true );
212 void ImplDockFloatWin::Resize()
214 FloatingWindow::Resize();
215 Size aSize( GetSizePixel() );
216 mpDockWin->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), PosSizeFlags::PosSize );
219 void ImplDockFloatWin::Resizing( Size& rSize )
221 FloatingWindow::Resizing( rSize );
222 mpDockWin->Resizing( rSize );
225 bool ImplDockFloatWin::Close()
227 return mpDockWin->Close();
230 void DockingWindow::ImplStartDocking( const Point& rPos )
232 if ( !mbDockable )
233 return;
235 maMouseOff = rPos;
236 mbDocking = true;
237 mbLastFloatMode = IsFloatingMode();
238 mbStartFloat = mbLastFloatMode;
240 // calculate FloatingBorder
241 VclPtr<FloatingWindow> pWin;
242 if ( mpFloatWin )
243 pWin = mpFloatWin;
244 else
245 pWin = VclPtr<ImplDockFloatWin>::Create( mpImplData->mpParent, mnFloatBits, nullptr );
246 pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
247 if ( !mpFloatWin )
248 pWin.disposeAndClear();
250 Point aPos = ImplOutputToFrame( Point() );
251 Size aSize = Window::GetOutputSizePixel();
252 mnTrackX = aPos.X();
253 mnTrackY = aPos.Y();
254 mnTrackWidth = aSize.Width();
255 mnTrackHeight = aSize.Height();
257 if ( mbLastFloatMode )
259 maMouseOff.AdjustX(mnDockLeft );
260 maMouseOff.AdjustY(mnDockTop );
261 mnTrackX -= mnDockLeft;
262 mnTrackY -= mnDockTop;
263 mnTrackWidth += mnDockLeft+mnDockRight;
264 mnTrackHeight += mnDockTop+mnDockBottom;
267 if ( GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Docking &&
268 !( mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ) ) // no full drag when migrating to system window
269 mbDragFull = true;
270 else
272 StartDocking();
273 mbDragFull = false;
274 ImplUpdateAll();
275 ImplGetFrameWindow()->ImplUpdateAll();
278 StartTracking( StartTrackingFlags::KeyMod );
281 void DockingWindow::ImplInitDockingWindowData()
283 mpWindowImpl->mbDockWin = true;
284 mpFloatWin = nullptr;
285 mpOldBorderWin = nullptr;
286 mpImplData.reset(new ImplData);
287 mnTrackX = 0;
288 mnTrackY = 0;
289 mnTrackWidth = 0;
290 mnTrackHeight = 0;
291 mnDockLeft = 0;
292 mnDockTop = 0;
293 mnDockRight = 0;
294 mnDockBottom = 0;
295 mnFloatBits = 0;
296 mbDockCanceled = false;
297 mbDockable = false;
298 mbDocking = false;
299 mbDragFull = false;
300 mbLastFloatMode = false;
301 mbStartFloat = false;
302 mbDockBtn = false;
303 mbHideBtn = false;
304 mbIsDeferredInit = false;
305 mbIsCalculatingInitialLayoutSize = false;
306 mpDialogParent = nullptr;
308 //To-Do, reuse maResizeTimer
309 maLayoutIdle.SetPriority(TaskPriority::RESIZE);
310 maLayoutIdle.SetInvokeHandler( LINK( this, DockingWindow, ImplHandleLayoutTimerHdl ) );
313 void DockingWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
315 if ( !(nStyle & WB_NODIALOGCONTROL) )
316 nStyle |= WB_DIALOGCONTROL;
318 mpImplData->mpParent = pParent;
319 mbDockable = (nStyle & WB_DOCKABLE) != 0;
320 mnFloatBits = WB_BORDER | (nStyle & DOCKWIN_FLOATSTYLES);
321 nStyle &= ~(DOCKWIN_FLOATSTYLES | WB_BORDER);
323 Window::ImplInit( pParent, nStyle, nullptr );
325 ImplInitSettings();
328 void DockingWindow::ImplInitSettings()
330 // Hack: to be able to build DockingWindows w/o background before switching
331 // TODO: Hack
332 if ( !IsBackground() )
333 return;
335 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
337 Color aColor;
338 if ( IsControlBackground() )
339 aColor = GetControlBackground();
340 else if ( Window::GetStyle() & WB_3DLOOK )
341 aColor = rStyleSettings.GetFaceColor();
342 else
343 aColor = rStyleSettings.GetWindowColor();
344 SetBackground( aColor );
347 DockingWindow::DockingWindow( WindowType nType, const char* pIdleDebugName ) :
348 Window(nType),
349 maLayoutIdle( pIdleDebugName )
351 ImplInitDockingWindowData();
354 DockingWindow::DockingWindow( vcl::Window* pParent, WinBits nStyle, const char* pIdleDebugName ) :
355 Window( WindowType::DOCKINGWINDOW ),
356 maLayoutIdle( pIdleDebugName )
358 ImplInitDockingWindowData();
359 ImplInit( pParent, nStyle );
362 //Find the real parent stashed in mpDialogParent.
363 void DockingWindow::doDeferredInit(WinBits nBits)
365 vcl::Window *pParent = mpDialogParent;
366 mpDialogParent = nullptr;
367 ImplInit(pParent, nBits);
368 mbIsDeferredInit = false;
371 void DockingWindow::loadUI(vcl::Window* pParent, const OUString& rID, const OUString& rUIXMLDescription,
372 const css::uno::Reference<css::frame::XFrame> &rFrame)
374 mbIsDeferredInit = true;
375 mpDialogParent = pParent; //should be unset in doDeferredInit
376 m_pUIBuilder.reset( new VclBuilder(this, AllSettings::GetUIRootDir(), rUIXMLDescription, rID, rFrame) );
379 DockingWindow::DockingWindow(vcl::Window* pParent, const OUString& rID,
380 const OUString& rUIXMLDescription, const char* pIdleDebugName,
381 const css::uno::Reference<css::frame::XFrame> &rFrame)
382 : Window(WindowType::DOCKINGWINDOW),
383 maLayoutIdle( pIdleDebugName )
385 ImplInitDockingWindowData();
387 loadUI(pParent, rID, rUIXMLDescription, rFrame);
390 DockingWindow::~DockingWindow()
392 disposeOnce();
395 void DockingWindow::dispose()
397 if ( IsFloatingMode() )
399 Show( false, ShowFlags::NoFocusChange );
400 SetFloatingMode(false);
402 mpImplData.reset();
403 mpFloatWin.clear();
404 mpOldBorderWin.clear();
405 mpDialogParent.clear();
406 disposeBuilder();
407 Window::dispose();
410 void DockingWindow::Tracking( const TrackingEvent& rTEvt )
412 if( GetDockingManager()->IsDockable( this ) ) // new docking interface
413 return Window::Tracking( rTEvt );
415 if ( !mbDocking )
416 return;
418 if ( rTEvt.IsTrackingEnded() )
420 mbDocking = false;
421 if ( mbDragFull )
423 // reset old state on Cancel
424 if ( rTEvt.IsTrackingCanceled() )
426 StartDocking();
427 tools::Rectangle aRect( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) );
428 EndDocking( aRect, mbStartFloat );
431 else
433 HideTracking();
434 if ( rTEvt.IsTrackingCanceled() )
436 mbDockCanceled = true;
437 EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
438 mbDockCanceled = false;
440 else
441 EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
444 // dock only for non-synthetic MouseEvents
445 else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
447 Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
448 Point aFrameMousePos = ImplOutputToFrame( aMousePos );
449 Size aFrameSize = mpWindowImpl->mpFrameWindow->GetOutputSizePixel();
450 if ( aFrameMousePos.X() < 0 )
451 aFrameMousePos.setX( 0 );
452 if ( aFrameMousePos.Y() < 0 )
453 aFrameMousePos.setY( 0 );
454 if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
455 aFrameMousePos.setX( aFrameSize.Width()-1 );
456 if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
457 aFrameMousePos.setY( aFrameSize.Height()-1 );
458 aMousePos = ImplFrameToOutput( aFrameMousePos );
459 aMousePos.AdjustX( -(maMouseOff.X()) );
460 aMousePos.AdjustY( -(maMouseOff.Y()) );
461 Point aFramePos = ImplOutputToFrame( aMousePos );
462 tools::Rectangle aTrackRect( aFramePos, Size( mnTrackWidth, mnTrackHeight ) );
463 tools::Rectangle aCompRect = aTrackRect;
464 aFramePos.AdjustX(maMouseOff.X() );
465 aFramePos.AdjustY(maMouseOff.Y() );
466 if ( mbDragFull )
467 StartDocking();
468 bool bFloatMode = Docking( aFramePos, aTrackRect );
469 if ( mbLastFloatMode != bFloatMode )
471 if ( bFloatMode )
473 aTrackRect.AdjustLeft( -mnDockLeft );
474 aTrackRect.AdjustTop( -mnDockTop );
475 aTrackRect.AdjustRight(mnDockRight );
476 aTrackRect.AdjustBottom(mnDockBottom );
478 else
480 if ( aCompRect == aTrackRect )
482 aTrackRect.AdjustLeft(mnDockLeft );
483 aTrackRect.AdjustTop(mnDockTop );
484 aTrackRect.AdjustRight( -mnDockRight );
485 aTrackRect.AdjustBottom( -mnDockBottom );
488 mbLastFloatMode = bFloatMode;
490 if ( mbDragFull )
492 Point aOldPos = OutputToScreenPixel( Point() );
493 EndDocking( aTrackRect, mbLastFloatMode );
494 // repaint if state or position has changed
495 if ( aOldPos != OutputToScreenPixel( Point() ) )
497 ImplUpdateAll();
498 ImplGetFrameWindow()->ImplUpdateAll();
500 // EndDocking( aTrackRect, mbLastFloatMode );
502 else
504 ShowTrackFlags nTrackStyle;
505 if ( bFloatMode )
506 nTrackStyle = ShowTrackFlags::Big;
507 else
508 nTrackStyle = ShowTrackFlags::Object;
509 tools::Rectangle aShowTrackRect = aTrackRect;
510 aShowTrackRect.SetPos( ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
511 ShowTracking( aShowTrackRect, nTrackStyle );
513 // recalculate mouse offset, as the rectangle was changed
514 maMouseOff.setX( aFramePos.X() - aTrackRect.Left() );
515 maMouseOff.setY( aFramePos.Y() - aTrackRect.Top() );
518 mnTrackX = aTrackRect.Left();
519 mnTrackY = aTrackRect.Top();
520 mnTrackWidth = aTrackRect.GetWidth();
521 mnTrackHeight = aTrackRect.GetHeight();
525 bool DockingWindow::EventNotify( NotifyEvent& rNEvt )
527 if( GetDockingManager()->IsDockable( this ) ) // new docking interface
528 return Window::EventNotify( rNEvt );
530 if ( mbDockable )
532 const bool bDockingSupportCrippled = !StyleSettings::GetDockingFloatsSupported();
534 if ( rNEvt.GetType() == NotifyEventType::MOUSEBUTTONDOWN )
536 const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
537 if ( pMEvt->IsLeft() )
539 if (!bDockingSupportCrippled && pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) )
541 SetFloatingMode( !IsFloatingMode() );
542 if ( IsFloatingMode() )
543 ToTop( ToTopFlags::GrabFocusOnly );
544 return true;
546 else if ( pMEvt->GetClicks() == 1 )
548 // check if window is floating standalone (IsFloating())
549 // or only partially floating and still docked with one border
550 // ( !mpWindowImpl->mbFrame)
551 if( ! IsFloatingMode() || ! mpFloatWin->mpWindowImpl->mbFrame )
553 Point aPos = pMEvt->GetPosPixel();
554 vcl::Window* pWindow = rNEvt.GetWindow();
555 if ( pWindow != this )
557 aPos = pWindow->OutputToScreenPixel( aPos );
558 aPos = ScreenToOutputPixel( aPos );
560 ImplStartDocking( aPos );
562 return true;
566 else if( rNEvt.GetType() == NotifyEventType::KEYINPUT )
568 const vcl::KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode();
569 if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
570 rKey.IsShift() && rKey.IsMod1() && !bDockingSupportCrippled )
572 SetFloatingMode( !IsFloatingMode() );
573 if ( IsFloatingMode() )
574 ToTop( ToTopFlags::GrabFocusOnly );
575 return true;
580 return Window::EventNotify( rNEvt );
583 void DockingWindow::StartDocking()
585 mbDocking = true;
588 bool DockingWindow::Docking( const Point&, tools::Rectangle& )
590 return IsFloatingMode();
593 void DockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
595 bool bOrigDockCanceled = mbDockCanceled;
596 if (bFloatMode && !StyleSettings::GetDockingFloatsSupported())
597 mbDockCanceled = true;
599 if ( !IsDockingCanceled() )
601 if ( bFloatMode != IsFloatingMode() )
603 SetFloatingMode( bFloatMode );
604 if ( IsFloatingMode() )
605 ToTop( ToTopFlags::GrabFocusOnly );
606 if ( bFloatMode && mpFloatWin )
607 mpFloatWin->SetPosSizePixel( rRect.TopLeft(), rRect.GetSize() );
609 if ( !bFloatMode )
611 Point aPos = rRect.TopLeft();
612 aPos = GetParent()->ScreenToOutputPixel( aPos );
613 Window::SetPosSizePixel( aPos, rRect.GetSize() );
616 mbDocking = false;
617 mbDockCanceled = bOrigDockCanceled;
620 bool DockingWindow::PrepareToggleFloatingMode()
622 return true;
625 bool DockingWindow::Close()
627 VclPtr<vcl::Window> xWindow = this;
628 CallEventListeners( VclEventId::WindowClose );
629 if ( xWindow->isDisposed() )
630 return false;
632 if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() )
633 return false;
635 Show( false, ShowFlags::NoFocusChange );
636 return true;
639 void DockingWindow::ToggleFloatingMode()
643 void DockingWindow::Resizing( Size& )
647 void DockingWindow::DoInitialLayout()
649 if (GetSettings().GetStyleSettings().GetAutoMnemonic())
650 GenerateAutoMnemonicsOnHierarchy(this);
652 if (isLayoutEnabled())
654 mbIsCalculatingInitialLayoutSize = true;
655 setDeferredProperties();
656 if (IsFloatingMode())
657 setOptimalLayoutSize();
658 mbIsCalculatingInitialLayoutSize = false;
662 void DockingWindow::StateChanged( StateChangedType nType )
664 switch(nType)
666 case StateChangedType::InitShow:
667 DoInitialLayout();
668 break;
670 case StateChangedType::ControlBackground:
671 ImplInitSettings();
672 Invalidate();
673 break;
675 case StateChangedType::Style:
676 mbDockable = (GetStyle() & WB_DOCKABLE) != 0;
677 break;
679 default:
680 break;
683 Window::StateChanged( nType );
686 void DockingWindow::DataChanged( const DataChangedEvent& rDCEvt )
688 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
689 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
691 ImplInitSettings();
692 Invalidate();
694 else
695 Window::DataChanged( rDCEvt );
698 void DockingWindow::SetFloatingMode( bool bFloatMode )
700 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
701 if( pWrapper )
703 pWrapper->SetFloatingMode( bFloatMode );
704 return;
706 if ( IsFloatingMode() == bFloatMode )
707 return;
709 if ( !PrepareToggleFloatingMode() ) // changes to floating mode can be vetoed
710 return;
712 bool bVisible = IsVisible();
714 if ( bFloatMode )
716 // set deferred properties early, so border width will end up
717 // in our mpWindowImpl->mnBorderWidth, not in mpBorderWindow.
718 // (see its usage in setPosSizeOnContainee and GetOptimalSize.)
719 setDeferredProperties();
721 Show( false, ShowFlags::NoFocusChange );
723 maDockPos = Window::GetPosPixel();
725 vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
726 mpOldBorderWin = mpWindowImpl->mpBorderWindow;
728 VclPtrInstance<ImplDockFloatWin> pWin(
729 mpImplData->mpParent,
730 mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits,
731 this );
732 mpFloatWin = pWin;
733 mpWindowImpl->mpBorderWindow = nullptr;
734 mpWindowImpl->mnLeftBorder = 0;
735 mpWindowImpl->mnTopBorder = 0;
736 mpWindowImpl->mnRightBorder = 0;
737 mpWindowImpl->mnBottomBorder = 0;
738 // if the parent gets destroyed, we also have to reset the parent of the BorderWindow
739 if ( mpOldBorderWin )
740 mpOldBorderWin->SetParent( pWin );
742 // #i123765# reset the buffered DropTargets when undocking, else it may not
743 // be correctly initialized
744 mpWindowImpl->mxDNDListenerContainer.clear();
746 SetParent( pWin );
747 SetPosPixel( Point() );
748 mpWindowImpl->mpBorderWindow = pWin;
749 pWin->mpWindowImpl->mpClientWindow = this;
750 mpWindowImpl->mpRealParent = pRealParent;
751 pWin->SetText( Window::GetText() );
752 Size aSize(Window::GetSizePixel());
753 pWin->SetOutputSizePixel(aSize);
754 pWin->SetPosPixel( maFloatPos );
755 // pass on DockingData to FloatingWindow
756 pWin->ShowTitleButton( TitleButton::Docking, mbDockBtn );
757 pWin->ShowTitleButton( TitleButton::Hide, mbHideBtn );
758 pWin->SetMinOutputSizePixel( maMinOutSize );
760 pWin->SetMaxOutputSizePixel( mpImplData->maMaxOutSize );
762 ToggleFloatingMode();
764 if ( bVisible )
765 Show();
767 else
769 Show( false, ShowFlags::NoFocusChange );
771 // store FloatingData in FloatingWindow
772 maFloatPos = mpFloatWin->GetPosPixel();
773 mbDockBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Docking );
774 mbHideBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Hide );
775 maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
776 mpImplData->maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
778 vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
779 mpWindowImpl->mpBorderWindow = nullptr;
780 if ( mpOldBorderWin )
782 SetParent( mpOldBorderWin );
783 static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
784 mpOldBorderWin->Resize();
786 mpWindowImpl->mpBorderWindow = mpOldBorderWin;
787 SetParent( pRealParent );
788 mpWindowImpl->mpRealParent = pRealParent;
789 mpFloatWin.disposeAndClear();
790 SetPosPixel( maDockPos );
792 ToggleFloatingMode();
794 if ( bVisible )
795 Show();
799 void DockingWindow::SetFloatStyle( WinBits nStyle )
801 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
802 if( pWrapper )
804 pWrapper->SetFloatStyle( nStyle );
805 return;
808 mnFloatBits = nStyle;
811 WinBits DockingWindow::GetFloatStyle() const
813 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
814 if( pWrapper )
816 return pWrapper->GetFloatStyle();
819 return mnFloatBits;
822 void DockingWindow::setPosSizePixel( tools::Long nX, tools::Long nY,
823 tools::Long nWidth, tools::Long nHeight,
824 PosSizeFlags nFlags )
826 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
827 if (pWrapper)
829 if (!pWrapper->mpFloatWin)
830 Window::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
832 else
834 if (!mpFloatWin)
835 Window::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
836 else if (comphelper::LibreOfficeKit::isActive())
838 if ((nFlags & PosSizeFlags::Size) == PosSizeFlags::Size)
839 mpFloatWin->SetOutputSizePixel({ nWidth, nHeight });
840 if ((nFlags & PosSizeFlags::Pos) == PosSizeFlags::Pos)
841 mpFloatWin->SetPosPixel({ nX, nY });
845 if (::isLayoutEnabled(this))
846 setPosSizeOnContainee();
849 Point DockingWindow::GetPosPixel() const
851 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
852 if( pWrapper )
854 if ( pWrapper->mpFloatWin )
855 return pWrapper->mpFloatWin->GetPosPixel();
856 else
857 return Window::GetPosPixel();
860 if ( mpFloatWin )
861 return mpFloatWin->GetPosPixel();
862 else
863 return Window::GetPosPixel();
866 Size DockingWindow::GetSizePixel() const
868 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
869 if( pWrapper )
871 if ( pWrapper->mpFloatWin )
872 return pWrapper->mpFloatWin->GetSizePixel();
873 else
874 return Window::GetSizePixel();
877 if ( mpFloatWin )
878 return mpFloatWin->GetSizePixel();
879 else
880 return Window::GetSizePixel();
883 void DockingWindow::SetOutputSizePixel( const Size& rNewSize )
885 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
886 if( pWrapper )
888 if ( pWrapper->mpFloatWin )
889 pWrapper->mpFloatWin->SetOutputSizePixel( rNewSize );
890 else
891 Window::SetOutputSizePixel( rNewSize );
892 return;
895 if ( mpFloatWin )
896 mpFloatWin->SetOutputSizePixel( rNewSize );
897 else
898 Window::SetOutputSizePixel( rNewSize );
901 Size DockingWindow::GetOutputSizePixel() const
903 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
904 if( pWrapper )
906 if ( pWrapper->mpFloatWin )
907 return pWrapper->mpFloatWin->GetOutputSizePixel();
908 else
909 return Window::GetOutputSizePixel();
912 if ( mpFloatWin )
913 return mpFloatWin->GetOutputSizePixel();
914 else
915 return Window::GetOutputSizePixel();
918 Point DockingWindow::GetFloatingPos() const
920 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
921 if( pWrapper )
923 if ( pWrapper->mpFloatWin )
925 vcl::WindowData aData;
926 aData.setMask(vcl::WindowDataMask::Pos);
927 pWrapper->mpFloatWin->GetWindowState( aData );
928 Point aPos(aData.x(), aData.y());
929 // LOK needs logic coordinates not absolute screen position for autofilter menu
930 if (!comphelper::LibreOfficeKit::isActive() || get_id() != "check_list_menu")
931 aPos = pWrapper->mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
932 return aPos;
934 else
935 return maFloatPos;
938 if ( mpFloatWin )
940 vcl::WindowData aData;
941 aData.setMask(vcl::WindowDataMask::Pos);
942 mpFloatWin->GetWindowState( aData );
943 Point aPos(aData.x(), aData.y());
944 aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
945 return aPos;
947 else
948 return maFloatPos;
951 bool DockingWindow::IsFloatingMode() const
953 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
954 if( pWrapper )
955 return pWrapper->IsFloatingMode();
956 else
957 return (mpFloatWin != nullptr);
960 void DockingWindow::SetMaxOutputSizePixel( const Size& rSize )
962 if ( mpFloatWin )
963 mpFloatWin->SetMaxOutputSizePixel( rSize );
964 mpImplData->maMaxOutSize = rSize;
967 void DockingWindow::SetText(const OUString& rStr)
969 setDeferredProperties();
970 Window::SetText(rStr);
973 OUString DockingWindow::GetText() const
975 const_cast<DockingWindow*>(this)->setDeferredProperties();
976 return Window::GetText();
979 bool DockingWindow::isLayoutEnabled() const
981 //pre dtor called, and single child is a container => we're layout enabled
982 return mpImplData && ::isLayoutEnabled(this);
985 void DockingWindow::setOptimalLayoutSize()
987 maLayoutIdle.Stop();
989 //resize DockingWindow to fit requisition on initial show
990 Size aSize = get_preferred_size();
992 Size aMax(bestmaxFrameSizeForScreenSize(GetDesktopRectPixel().GetSize()));
994 aSize.setWidth( std::min(aMax.Width(), aSize.Width()) );
995 aSize.setHeight( std::min(aMax.Height(), aSize.Height()) );
997 SetMinOutputSizePixel(aSize);
998 setPosSizeOnContainee();
1001 void DockingWindow::setPosSizeOnContainee()
1003 Size aSize = GetOutputSizePixel();
1005 // Don't make the border width accessible via get_border_width(),
1006 // otherwise the floating window will handle the border as well.
1007 sal_Int32 nBorderWidth = mpWindowImpl->mnBorderWidth;
1009 aSize.AdjustWidth( -(2 * nBorderWidth) );
1010 aSize.AdjustHeight( -(2 * nBorderWidth) );
1012 Window* pBox = GetWindow(GetWindowType::FirstChild);
1013 assert(pBox);
1014 VclContainer::setLayoutAllocation(*pBox, Point(nBorderWidth, nBorderWidth), aSize);
1017 Size DockingWindow::GetOptimalSize() const
1019 if (!isLayoutEnabled())
1020 return Window::GetOptimalSize();
1022 Size aSize = VclContainer::getLayoutRequisition(*GetWindow(GetWindowType::FirstChild));
1024 // Don't make the border width accessible via get_border_width(),
1025 // otherwise the floating window will handle the border as well.
1026 sal_Int32 nBorderWidth = mpWindowImpl->mnBorderWidth;
1028 aSize.AdjustHeight(2 * nBorderWidth );
1029 aSize.AdjustWidth(2 * nBorderWidth );
1031 return aSize;
1034 void DockingWindow::queue_resize(StateChangedType eReason)
1036 bool bTriggerLayout = true;
1037 if (maLayoutIdle.IsActive() || mbIsCalculatingInitialLayoutSize)
1039 bTriggerLayout = false;
1041 if (!isLayoutEnabled())
1043 bTriggerLayout = false;
1045 if (bTriggerLayout)
1047 InvalidateSizeCache();
1048 maLayoutIdle.Start();
1050 vcl::Window::queue_resize(eReason);
1053 IMPL_LINK_NOARG(DockingWindow, ImplHandleLayoutTimerHdl, Timer*, void)
1055 if (!isLayoutEnabled())
1057 SAL_WARN_IF(GetWindow(GetWindowType::FirstChild), "vcl.layout", "DockingWindow has become non-layout because extra children have been added directly to it.");
1058 return;
1060 setPosSizeOnContainee();
1063 void DockingWindow::SetMinOutputSizePixel( const Size& rSize )
1065 if ( mpFloatWin )
1066 mpFloatWin->SetMinOutputSizePixel( rSize );
1067 maMinOutSize = rSize;
1070 const Size& DockingWindow::GetMinOutputSizePixel() const
1072 if ( mpFloatWin )
1073 return mpFloatWin->GetMinOutputSizePixel();
1074 return maMinOutSize;
1077 void DockingWindow::SetFloatingPos( const Point& rNewPos )
1079 if ( mpFloatWin )
1080 mpFloatWin->SetPosPixel( rNewPos );
1081 else
1082 maFloatPos = rNewPos;
1085 SystemWindow* DockingWindow::GetFloatingWindow() const
1087 return mpFloatWin;
1090 DropdownDockingWindow::DropdownDockingWindow(vcl::Window* pParent, const css::uno::Reference<css::frame::XFrame>& rFrame, bool bTearable)
1091 : DockingWindow(pParent,
1092 !bTearable ? OUString("InterimDockParent") : OUString("InterimTearableParent"),
1093 !bTearable ? OUString("vcl/ui/interimdockparent.ui") : OUString("vcl/ui/interimtearableparent.ui"),
1094 "vcl::DropdownDockingWindow maLayoutIdle",
1095 rFrame)
1096 , m_xBox(m_pUIBuilder->get("box"))
1100 DropdownDockingWindow::~DropdownDockingWindow()
1102 disposeOnce();
1105 void DropdownDockingWindow::dispose()
1107 m_xBox.clear();
1108 DockingWindow::dispose();
1111 ResizableDockingWindow::ResizableDockingWindow(vcl::Window* pParent, const css::uno::Reference<css::frame::XFrame>& rFrame)
1112 : DockingWindow(pParent, "DockingWindow", "vcl/ui/dockingwindow.ui", "vcl::ResizableDockingWindow maLayoutIdle", rFrame)
1113 , m_xBox(m_pUIBuilder->get("box"))
1117 ResizableDockingWindow::ResizableDockingWindow(vcl::Window* pParent, WinBits nStyle)
1118 : DockingWindow(pParent, nStyle, "vcl::ResizableDockingWindow maLayoutIdle")
1122 // needed to blow away the cached size of the boundary between vcl and hosted child widget
1123 void ResizableDockingWindow::InvalidateChildSizeCache()
1125 // find the bottom vcl::Window of the hierarchy and queue_resize on that
1126 // one will invalidate all the size caches upwards
1127 vcl::Window* pChild = GetWindow(GetWindowType::FirstChild);
1128 while (true)
1130 vcl::Window* pSubChild = pChild->GetWindow(GetWindowType::FirstChild);
1131 if (!pSubChild)
1132 break;
1133 pChild = pSubChild;
1135 pChild->queue_resize();
1138 ResizableDockingWindow::~ResizableDockingWindow()
1140 disposeOnce();
1143 void ResizableDockingWindow::dispose()
1145 m_xBox.clear();
1146 DockingWindow::dispose();
1149 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */