1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 #include <salframe.hxx>
24 #include <helpwin.hxx>
26 #include <comphelper/lok.hxx>
27 #include <sal/log.hxx>
28 #include <vcl/layout.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/wrkwin.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/toolbox.hxx>
33 #include <vcl/toolkit/floatwin.hxx>
34 #include <vcl/settings.hxx>
35 #include <vcl/IDialogRenderable.hxx>
37 class FloatingWindow::ImplData
42 VclPtr
<ToolBox
> mpBox
;
43 tools::Rectangle maItemEdgeClipRect
; // used to clip the common edge between a toolbar item and the border of this window
44 Point maPos
; // position of the floating window wrt. parent
45 Point maLOKTwipsPos
; ///< absolute position of the floating window in the document - in twips (for toplevel floating windows).
48 FloatingWindow::ImplData::ImplData()
53 tools::Rectangle
& FloatingWindow::ImplGetItemEdgeClipRect()
55 return mpImplData
->maItemEdgeClipRect
;
58 void FloatingWindow::ImplInitFloating( vcl::Window
* pParent
, WinBits nStyle
)
60 mpImplData
.reset(new ImplData
);
62 mpWindowImpl
->mbFloatWin
= true;
66 SAL_WARN_IF(!pParent
, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL!");
69 pParent
= ImplGetSVData()->maFrameData
.mpAppWin
;
71 SAL_WARN_IF(!pParent
, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL and no AppWindow exists");
73 // no Border, then we don't need a border window
76 mpWindowImpl
->mbOverlapWin
= true;
77 nStyle
|= WB_DIALOGCONTROL
;
78 ImplInit(pParent
, nStyle
, nullptr);
82 if (!(nStyle
& WB_NODIALOGCONTROL
))
83 nStyle
|= WB_DIALOGCONTROL
;
85 if (nStyle
& (WB_MOVEABLE
| WB_SIZEABLE
| WB_CLOSEABLE
| WB_STANDALONE
)
86 && !(nStyle
& WB_OWNERDRAWDECORATION
))
88 WinBits nFloatWinStyle
= nStyle
;
89 // #99154# floaters are not closeable by default anymore, eg fullscreen floater
90 // nFloatWinStyle |= WB_CLOSEABLE;
91 mpWindowImpl
->mbFrame
= true;
92 mpWindowImpl
->mbOverlapWin
= true;
93 ImplInit(pParent
, nFloatWinStyle
& ~WB_BORDER
, nullptr);
97 VclPtr
<ImplBorderWindow
> pBorderWin
;
98 BorderWindowStyle nBorderStyle
= BorderWindowStyle::Float
;
100 if (nStyle
& WB_OWNERDRAWDECORATION
)
101 nBorderStyle
|= BorderWindowStyle::Frame
;
103 nBorderStyle
|= BorderWindowStyle::Overlap
;
105 if ((nStyle
& WB_SYSTEMWINDOW
) && !(nStyle
& (WB_MOVEABLE
| WB_SIZEABLE
)))
107 nBorderStyle
|= BorderWindowStyle::Frame
;
108 nStyle
|= WB_CLOSEABLE
; // make undecorated floaters closeable
110 pBorderWin
= VclPtr
<ImplBorderWindow
>::Create(pParent
, nStyle
, nBorderStyle
);
111 ImplInit(pBorderWin
, nStyle
& ~WB_BORDER
, nullptr);
112 pBorderWin
->mpWindowImpl
->mpClientWindow
= this;
113 pBorderWin
->GetBorder(mpWindowImpl
->mnLeftBorder
, mpWindowImpl
->mnTopBorder
,
114 mpWindowImpl
->mnRightBorder
, mpWindowImpl
->mnBottomBorder
);
115 pBorderWin
->SetDisplayActive(true);
116 mpWindowImpl
->mpBorderWindow
= pBorderWin
;
117 mpWindowImpl
->mpRealParent
= pParent
;
120 SetActivateMode( ActivateModeFlags::NONE
);
122 mpNextFloat
= nullptr;
123 mpFirstPopupModeWin
= nullptr;
125 mnTitle
= (nStyle
& (WB_MOVEABLE
| WB_POPUP
)) ? FloatWinTitleType::Normal
: FloatWinTitleType::NONE
;
126 mnOldTitle
= mnTitle
;
127 mnPopupModeFlags
= FloatWinPopupFlags::NONE
;
128 mbInPopupMode
= false;
130 mbPopupModeCanceled
= false;
131 mbPopupModeTearOff
= false;
137 void FloatingWindow::ImplInitSettings()
139 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
142 if (IsControlBackground())
143 aColor
= GetControlBackground();
144 else if (Window::GetStyle() & WB_3DLOOK
)
145 aColor
= rStyleSettings
.GetFaceColor();
147 aColor
= rStyleSettings
.GetWindowColor();
148 SetBackground(aColor
);
151 FloatingWindow::FloatingWindow(vcl::Window
* pParent
, WinBits nStyle
) :
152 SystemWindow(WindowType::FLOATINGWINDOW
, "vcl::FloatingWindow maLayoutIdle")
154 ImplInitFloating(pParent
, nStyle
);
157 FloatingWindow::FloatingWindow(vcl::Window
* pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
, const css::uno::Reference
<css::frame::XFrame
> &rFrame
)
158 : SystemWindow(WindowType::FLOATINGWINDOW
, "vcl::FloatingWindow maLayoutIdle")
159 , mpNextFloat(nullptr)
160 , mpFirstPopupModeWin(nullptr)
162 , mnPopupModeFlags(FloatWinPopupFlags::NONE
)
163 , mnTitle(FloatWinTitleType::Unknown
)
164 , mnOldTitle(FloatWinTitleType::Unknown
)
165 , mbInPopupMode(false)
167 , mbPopupModeCanceled(false)
168 , mbPopupModeTearOff(false)
173 loadUI(pParent
, rID
, rUIXMLDescription
, rFrame
);
176 //Find the real parent stashed in mpDialogParent.
177 void FloatingWindow::doDeferredInit(WinBits nBits
)
179 vcl::Window
*pParent
= mpDialogParent
;
180 mpDialogParent
= nullptr;
181 ImplInitFloating(pParent
, nBits
);
182 mbIsDeferredInit
= false;
185 void FloatingWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
187 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
190 if (Window::GetStyle() & WB_3DLOOK
)
191 aColor
= rStyleSettings
.GetFaceColor();
193 aColor
= rStyleSettings
.GetWindowColor();
195 ApplyControlBackground(rRenderContext
, aColor
);
198 FloatingWindow::~FloatingWindow()
204 void FloatingWindow::dispose()
206 ReleaseLOKNotifier();
210 if( mbPopupModeCanceled
)
211 // indicates that ESC key was pressed
212 // will be handled in Window::ImplGrabFocus()
213 SetDialogControlFlags( GetDialogControlFlags() | DialogControlFlags::FloatWinPopupModeEndCancel
);
215 if ( IsInPopupMode() )
216 EndPopupMode( FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
| FloatWinPopupEndFlags::DontCallHdl
);
219 Application::RemoveUserEvent( mnPostId
);
226 mpFirstPopupModeWin
.clear();
227 mxPrevFocusWin
.clear();
228 SystemWindow::dispose();
231 Point
FloatingWindow::ImplCalcPos(vcl::Window
* pWindow
,
232 const tools::Rectangle
& rRect
, FloatWinPopupFlags nFlags
,
233 sal_uInt16
& rArrangeIndex
, Point
* pLOKTwipsPos
)
235 // get window position
237 Size aSize
= ::isLayoutEnabled(pWindow
) ? pWindow
->get_preferred_size() : pWindow
->GetSizePixel();
238 tools::Rectangle aScreenRect
= pWindow
->ImplGetFrameWindow()->GetDesktopRectPixel();
239 FloatingWindow
*pFloatingWindow
= dynamic_cast<FloatingWindow
*>( pWindow
);
242 vcl::Window
* pW
= pWindow
;
243 if ( pW
->mpWindowImpl
->mpRealParent
)
244 pW
= pW
->mpWindowImpl
->mpRealParent
;
246 tools::Rectangle
normRect( rRect
); // rRect is already relative to top-level window
247 normRect
.SetPos( pW
->ScreenToOutputPixel( normRect
.TopLeft() ) );
249 bool bRTL
= AllSettings::GetLayoutRTL();
251 tools::Rectangle
devRect( pW
->OutputToAbsoluteScreenPixel( normRect
.TopLeft() ),
252 pW
->OutputToAbsoluteScreenPixel( normRect
.BottomRight() ) );
254 tools::Rectangle
devRectRTL( devRect
);
256 // create a rect that can be compared to desktop coordinates
257 devRectRTL
= pW
->ImplOutputToUnmirroredAbsoluteScreenPixel( normRect
);
258 if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
259 aScreenRect
= Application::GetScreenPosSizePixel(
260 Application::GetBestScreen( bRTL
? devRectRTL
: devRect
) );
262 FloatWinPopupFlags nArrangeAry
[5];
263 sal_uInt16 nArrangeAttempts
= 5;
264 Point e1
,e2
; // the common edge between the item rect and the floating window
266 if ( nFlags
& FloatWinPopupFlags::Left
)
268 nArrangeAry
[0] = FloatWinPopupFlags::Left
;
269 nArrangeAry
[1] = FloatWinPopupFlags::Right
;
270 nArrangeAry
[2] = FloatWinPopupFlags::Up
;
271 nArrangeAry
[3] = FloatWinPopupFlags::Down
;
272 nArrangeAry
[4] = FloatWinPopupFlags::Left
;
274 else if ( nFlags
& FloatWinPopupFlags::Right
)
276 nArrangeAry
[0] = FloatWinPopupFlags::Right
;
277 nArrangeAry
[1] = FloatWinPopupFlags::Left
;
278 nArrangeAry
[2] = FloatWinPopupFlags::Up
;
279 nArrangeAry
[3] = FloatWinPopupFlags::Down
;
280 nArrangeAry
[4] = FloatWinPopupFlags::Right
;
282 else if ( nFlags
& FloatWinPopupFlags::Up
)
284 nArrangeAry
[0] = FloatWinPopupFlags::Up
;
285 nArrangeAry
[1] = FloatWinPopupFlags::Down
;
286 if (nFlags
& FloatWinPopupFlags::NoHorzPlacement
)
288 nArrangeAry
[2] = FloatWinPopupFlags::Up
;
289 nArrangeAttempts
= 3;
293 nArrangeAry
[2] = FloatWinPopupFlags::Right
;
294 nArrangeAry
[3] = FloatWinPopupFlags::Left
;
295 nArrangeAry
[4] = FloatWinPopupFlags::Up
;
300 nArrangeAry
[0] = FloatWinPopupFlags::Down
;
301 nArrangeAry
[1] = FloatWinPopupFlags::Up
;
302 if (nFlags
& FloatWinPopupFlags::NoHorzPlacement
)
304 nArrangeAry
[2] = FloatWinPopupFlags::Down
;
305 nArrangeAttempts
= 3;
309 nArrangeAry
[2] = FloatWinPopupFlags::Right
;
310 nArrangeAry
[3] = FloatWinPopupFlags::Left
;
311 nArrangeAry
[4] = FloatWinPopupFlags::Down
;
315 sal_uInt16 nArrangeIndex
= 0;
316 const bool bLOKActive
= comphelper::LibreOfficeKit::isActive();
318 for ( ; nArrangeIndex
< nArrangeAttempts
; nArrangeIndex
++ )
321 switch ( nArrangeAry
[nArrangeIndex
] )
324 case FloatWinPopupFlags::Left
:
325 aPos
.setX( devRect
.Left()-aSize
.Width()+1 );
326 aPos
.setY( devRect
.Top() );
327 aPos
.AdjustY( -(pWindow
->mpWindowImpl
->mnTopBorder
) );
330 if( (devRectRTL
.Right()+aSize
.Width()) > aScreenRect
.Right() )
335 if ( aPos
.X() < aScreenRect
.Left() )
338 if (bBreak
|| bLOKActive
)
340 e1
= devRect
.TopLeft();
341 e2
= devRect
.BottomLeft();
342 // set non-zero width
344 // don't clip corners
349 case FloatWinPopupFlags::Right
:
350 aPos
= devRect
.TopRight();
351 aPos
.AdjustY( -(pWindow
->mpWindowImpl
->mnTopBorder
) );
354 if( (devRectRTL
.Left() - aSize
.Width()) < aScreenRect
.Left() )
359 if ( aPos
.X()+aSize
.Width() > aScreenRect
.Right() )
362 if (bBreak
|| bLOKActive
)
364 e1
= devRect
.TopRight();
365 e2
= devRect
.BottomRight();
366 // set non-zero width
368 // don't clip corners
373 case FloatWinPopupFlags::Up
:
374 aPos
.setX( devRect
.Left() );
375 aPos
.setY( devRect
.Top()-aSize
.Height()+1 );
376 if ( aPos
.Y() < aScreenRect
.Top() )
378 if (bBreak
|| bLOKActive
)
380 e1
= devRect
.TopLeft();
381 e2
= devRect
.TopRight();
382 // set non-zero height
384 // don't clip corners
389 case FloatWinPopupFlags::Down
:
390 aPos
= devRect
.BottomLeft();
391 if ( aPos
.Y()+aSize
.Height() > aScreenRect
.Bottom() )
393 if (bBreak
|| bLOKActive
)
395 e1
= devRect
.BottomLeft();
396 e2
= devRect
.BottomRight();
397 // set non-zero height
399 // don't clip corners
407 // no further adjustment for LibreOfficeKit
411 // adjust if necessary
414 if ( (nArrangeAry
[nArrangeIndex
] == FloatWinPopupFlags::Left
) ||
415 (nArrangeAry
[nArrangeIndex
] == FloatWinPopupFlags::Right
) )
417 if ( aPos
.Y()+aSize
.Height() > aScreenRect
.Bottom() )
419 aPos
.setY( devRect
.Bottom()-aSize
.Height()+1 );
420 if ( aPos
.Y() < aScreenRect
.Top() )
421 aPos
.setY( aScreenRect
.Top() );
428 if( devRectRTL
.Right()-aSize
.Width()+1 < aScreenRect
.Left() )
429 aPos
.AdjustX( -(aScreenRect
.Left() - devRectRTL
.Right() + aSize
.Width() - 1) );
431 else if ( aPos
.X()+aSize
.Width() > aScreenRect
.Right() )
433 aPos
.setX( devRect
.Right()-aSize
.Width()+1 );
434 if ( aPos
.X() < aScreenRect
.Left() )
435 aPos
.setX( aScreenRect
.Left() );
443 if (nArrangeIndex
>= nArrangeAttempts
)
444 nArrangeIndex
= nArrangeAttempts
- 1;
446 rArrangeIndex
= nArrangeIndex
;
448 aPos
= pW
->AbsoluteScreenToOutputPixel( aPos
);
450 // store a cliprect that can be used to clip the common edge of the itemrect and the floating window
451 if( pFloatingWindow
&& pFloatingWindow
->mpImplData
->mpBox
)
453 pFloatingWindow
->mpImplData
->maItemEdgeClipRect
=
454 tools::Rectangle( e1
, e2
);
457 if (bLOKActive
&& pLOKTwipsPos
)
459 if (pW
->IsMapModeEnabled() || pW
->GetMapMode().GetMapUnit() == MapUnit::MapPixel
)
461 // if we use pW->LogicToLogic(aPos, pW->GetMapMode(), MapMode(MapUnit::MapTwip)),
462 // for pixel conversions when map mode is not enabled, we get
463 // a 20 twips per pixel conversion since LogicToLogic uses
464 // a fixed 72 dpi value, instead of a correctly computed output
465 // device dpi or at least the most commonly used 96 dpi value;
466 // and anyway the following is what we already do in
467 // ScGridWindow::LogicInvalidate when map mode is not enabled.
469 *pLOKTwipsPos
= pW
->PixelToLogic(aPos
, MapMode(MapUnit::MapTwip
));
473 *pLOKTwipsPos
= OutputDevice::LogicToLogic(aPos
, pW
->GetMapMode(), MapMode(MapUnit::MapTwip
));
477 // caller expects coordinates relative to top-level win
478 return pW
->OutputToScreenPixel( aPos
);
481 Point
FloatingWindow::ImplConvertToAbsPos(vcl::Window
* pReference
, const Point
& rPos
)
483 Point
aAbsolute( rPos
);
485 const OutputDevice
*pWindowOutDev
= pReference
->GetOutDev();
487 // compare coordinates in absolute screen coordinates
488 if( pWindowOutDev
->HasMirroredGraphics() )
490 if(!pReference
->IsRTLEnabled() )
491 pWindowOutDev
->ReMirror( aAbsolute
);
493 tools::Rectangle
aRect( pReference
->ScreenToOutputPixel(aAbsolute
), Size(1,1) ) ;
494 aRect
= pReference
->ImplOutputToUnmirroredAbsoluteScreenPixel( aRect
);
495 aAbsolute
= aRect
.TopLeft();
498 aAbsolute
= pReference
->OutputToAbsoluteScreenPixel(
499 pReference
->ScreenToOutputPixel(rPos
) );
504 tools::Rectangle
FloatingWindow::ImplConvertToAbsPos(vcl::Window
* pReference
, const tools::Rectangle
& rRect
)
506 tools::Rectangle aFloatRect
= rRect
;
508 const OutputDevice
*pParentWinOutDev
= pReference
->GetOutDev();
510 // compare coordinates in absolute screen coordinates
511 // Keep in sync with FloatingWindow::ImplFloatHitTest, e.g. fdo#33509
512 if( pParentWinOutDev
->HasMirroredGraphics() && !comphelper::LibreOfficeKit::isActive() )
514 if(!pReference
->IsRTLEnabled() )
515 pParentWinOutDev
->ReMirror(aFloatRect
);
517 aFloatRect
.SetPos(pReference
->ScreenToOutputPixel(aFloatRect
.TopLeft()));
518 aFloatRect
= pReference
->ImplOutputToUnmirroredAbsoluteScreenPixel(aFloatRect
);
521 aFloatRect
.SetPos(pReference
->OutputToAbsoluteScreenPixel(pReference
->ScreenToOutputPixel(rRect
.TopLeft())));
526 tools::Rectangle
FloatingWindow::ImplConvertToRelPos(vcl::Window
* pReference
, const tools::Rectangle
& rRect
)
528 tools::Rectangle aFloatRect
= rRect
;
530 const OutputDevice
*pParentWinOutDev
= pReference
->GetOutDev();
532 // compare coordinates in absolute screen coordinates
533 // Keep in sync with FloatingWindow::ImplFloatHitTest, e.g. fdo#33509
534 if( pParentWinOutDev
->HasMirroredGraphics() )
536 aFloatRect
= pReference
->ImplUnmirroredAbsoluteScreenToOutputPixel(aFloatRect
);
537 aFloatRect
.SetPos(pReference
->OutputToScreenPixel(aFloatRect
.TopLeft()));
539 if(!pReference
->IsRTLEnabled() )
540 pParentWinOutDev
->ReMirror(aFloatRect
);
543 aFloatRect
.SetPos(pReference
->OutputToScreenPixel(pReference
->AbsoluteScreenToOutputPixel(rRect
.TopLeft())));
548 FloatingWindow
* FloatingWindow::ImplFloatHitTest( vcl::Window
* pReference
, const Point
& rPos
, bool& rbHitTestInsideRect
)
550 FloatingWindow
* pWin
= this;
551 rbHitTestInsideRect
= false;
553 Point
aAbsolute(FloatingWindow::ImplConvertToAbsPos(pReference
, rPos
));
557 // compute the floating window's size in absolute screen coordinates
559 // use the border window to have the exact position
560 vcl::Window
*pBorderWin
= pWin
->GetWindow( GetWindowType::Border
);
564 // the top-left corner in output coordinates ie (0,0)
565 tools::Rectangle
devRect( pBorderWin
->ImplOutputToUnmirroredAbsoluteScreenPixel( tools::Rectangle( Point(), pBorderWin
->GetSizePixel()) ) ) ;
566 if ( devRect
.Contains( aAbsolute
) )
572 // test, if mouse is in rectangle, (this is typically the rect of the active
573 // toolbox item or similar)
574 // note: maFloatRect is set in FloatingWindow::StartPopupMode() and
575 // is already in absolute device coordinates
576 if ( pWin
->maFloatRect
.Contains( aAbsolute
) )
578 rbHitTestInsideRect
= true;
582 pWin
= pWin
->mpNextFloat
;
589 FloatingWindow
* FloatingWindow::ImplFindLastLevelFloat()
591 FloatingWindow
* pWin
= this;
592 FloatingWindow
* pLastFoundWin
= pWin
;
596 if ( pWin
->GetPopupModeFlags() & FloatWinPopupFlags::NewLevel
)
597 pLastFoundWin
= pWin
;
599 pWin
= pWin
->mpNextFloat
;
603 return pLastFoundWin
;
606 bool FloatingWindow::ImplIsFloatPopupModeWindow( const vcl::Window
* pWindow
)
608 FloatingWindow
* pWin
= this;
612 if ( pWin
->mpFirstPopupModeWin
== pWindow
)
615 pWin
= pWin
->mpNextFloat
;
622 IMPL_LINK_NOARG(FloatingWindow
, ImplEndPopupModeHdl
, void*, void)
624 VclPtr
<FloatingWindow
> pThis(this);
626 mnPopupModeFlags
= FloatWinPopupFlags::NONE
;
631 bool FloatingWindow::EventNotify( NotifyEvent
& rNEvt
)
633 // call Base Class first for tab control
634 bool bRet
= SystemWindow::EventNotify( rNEvt
);
637 if ( rNEvt
.GetType() == NotifyEventType::KEYINPUT
)
639 const KeyEvent
* pKEvt
= rNEvt
.GetKeyEvent();
640 vcl::KeyCode aKeyCode
= pKEvt
->GetKeyCode();
641 sal_uInt16 nKeyCode
= aKeyCode
.GetCode();
643 if ( (nKeyCode
== KEY_ESCAPE
) && (GetStyle() & WB_CLOSEABLE
) )
654 void FloatingWindow::PixelInvalidate(const tools::Rectangle
* /*pRectangle*/)
656 if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
658 const tools::Rectangle
aRect(Point(0,0), Size(GetSizePixel().Width()+1, GetSizePixel().Height()+1));
659 std::vector
<vcl::LOKPayloadItem
> aPayload
661 std::make_pair(OString("rectangle"), aRect
.toString())
663 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pParent
->GetLOKNotifier();
664 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
668 void FloatingWindow::StateChanged( StateChangedType nType
)
670 if (nType
== StateChangedType::InitShow
)
675 SystemWindow::StateChanged( nType
);
677 VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier();
680 if (nType
== StateChangedType::InitShow
)
682 std::vector
<vcl::LOKPayloadItem
> aItems
;
685 // we are a toplevel window, let's so far pretend to be a
686 // dialog - but maybe we'll need a separate type for this
689 aItems
.emplace_back("type", "dropdown");
691 aItems
.emplace_back("type", "dialog");
692 aItems
.emplace_back("position", mpImplData
->maLOKTwipsPos
.toString()); // twips
696 SetLOKNotifier(pParent
->GetLOKNotifier());
697 if (dynamic_cast<HelpTextWindow
*>(this))
698 aItems
.emplace_back("type", "tooltip");
700 aItems
.emplace_back("type", "child");
702 aItems
.emplace_back("parentId", OString::number(pParent
->GetLOKWindowId()));
704 aItems
.emplace_back("position", mpImplData
->maPos
.toString()); // pixels
705 else // mpImplData->maPos is not set
706 aItems
.emplace_back("position", GetPosPixel().toString());
709 aItems
.emplace_back("size", GetSizePixel().toString());
710 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "created", aItems
);
712 else if (!IsVisible() && nType
== StateChangedType::Visible
)
714 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
716 pNotifier
->notifyWindow(GetLOKWindowId(), "close");
717 ReleaseLOKNotifier();
722 if ( nType
== StateChangedType::ControlBackground
)
729 void FloatingWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
731 SystemWindow::DataChanged( rDCEvt
);
733 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
734 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
) )
741 void FloatingWindow::ImplCallPopupModeEnd()
743 // PopupMode is finished
744 mbInPopupMode
= false;
746 // call Handler asynchronously.
747 if ( mpImplData
&& !mnPostId
)
748 mnPostId
= Application::PostUserEvent(LINK(this, FloatingWindow
, ImplEndPopupModeHdl
));
751 void FloatingWindow::PopupModeEnd()
753 maPopupModeEndHdl
.Call( this );
756 void FloatingWindow::SetTitleType( FloatWinTitleType nTitle
)
758 if ( (mnTitle
== nTitle
) || !mpWindowImpl
->mpBorderWindow
)
762 Size aOutSize
= GetOutputSizePixel();
763 BorderWindowTitleType nTitleStyle
;
764 if ( nTitle
== FloatWinTitleType::Normal
)
765 nTitleStyle
= BorderWindowTitleType::Small
;
766 else if ( nTitle
== FloatWinTitleType::TearOff
)
767 nTitleStyle
= BorderWindowTitleType::Tearoff
;
768 else if ( nTitle
== FloatWinTitleType::Popup
)
769 nTitleStyle
= BorderWindowTitleType::Popup
;
770 else // nTitle == FloatWinTitleType::NONE
771 nTitleStyle
= BorderWindowTitleType::NONE
;
772 static_cast<ImplBorderWindow
*>(mpWindowImpl
->mpBorderWindow
.get())->SetTitleType( nTitleStyle
, aOutSize
);
773 static_cast<ImplBorderWindow
*>(mpWindowImpl
->mpBorderWindow
.get())->GetBorder( mpWindowImpl
->mnLeftBorder
, mpWindowImpl
->mnTopBorder
, mpWindowImpl
->mnRightBorder
, mpWindowImpl
->mnBottomBorder
);
776 void FloatingWindow::StartPopupMode( const tools::Rectangle
& rRect
, FloatWinPopupFlags nFlags
)
779 mnOldTitle
= mnTitle
;
780 if ( ( mpWindowImpl
->mnStyle
& WB_POPUP
) && !GetText().isEmpty() )
781 SetTitleType( FloatWinTitleType::Popup
);
782 else if ( nFlags
& FloatWinPopupFlags::AllowTearOff
)
783 SetTitleType( FloatWinTitleType::TearOff
);
785 SetTitleType( FloatWinTitleType::NONE
);
787 // avoid close on focus change for decorated floating windows only
788 if( mpWindowImpl
->mbFrame
&& (GetStyle() & WB_MOVEABLE
) )
789 nFlags
|= FloatWinPopupFlags::NoAppFocusClose
;
791 // compute window position according to flags and arrangement
792 sal_uInt16 nArrangeIndex
;
794 mpImplData
->maPos
= ImplCalcPos(this, rRect
, nFlags
, nArrangeIndex
, &mpImplData
->maLOKTwipsPos
);
795 SetPosPixel( mpImplData
->maPos
);
796 ImplGetFrame()->PositionByToolkit(rRect
, nFlags
);
799 tdf#140762 tdf#152671 Make dock win visible before showing popup
801 Make them visible again *before* starting popup mode for the floating
802 window. This e.g. makes NVDA announce popups in the toolbar or the Calc
805 if (nFlags
& FloatWinPopupFlags::MakeClientWindowVisibleBeforePopup
)
807 if (vcl::Window
* pClientWindow
= ImplGetClientWindow())
809 pClientWindow
->Show(true, ShowFlags::NoFocusChange
| ShowFlags::NoActivate
);
813 // set data and display window
814 // convert maFloatRect to absolute device coordinates
815 // so they can be compared across different frames
816 // !!! rRect is expected to be in screen coordinates of the parent frame window !!!
817 maFloatRect
= FloatingWindow::ImplConvertToAbsPos(GetParent(), rRect
);
819 maFloatRect
.AdjustLeft( -2 );
820 maFloatRect
.AdjustTop( -2 );
821 maFloatRect
.AdjustRight(2 );
822 maFloatRect
.AdjustBottom(2 );
823 mnPopupModeFlags
= nFlags
;
824 mbInPopupMode
= true;
826 mbPopupModeCanceled
= false;
827 mbPopupModeTearOff
= false;
830 // add FloatingWindow to list of windows that are in popup mode
831 ImplSVData
* pSVData
= ImplGetSVData();
832 mpNextFloat
= pSVData
->mpWinData
->mpFirstFloat
;
833 pSVData
->mpWinData
->mpFirstFloat
= this;
834 bool bGrabFocus(nFlags
& FloatWinPopupFlags::GrabFocus
);
837 // force key input even without focus (useful for menus)
839 mxPrevFocusWin
= Window::SaveFocus();
840 mpWindowImpl
->mpFrameData
->mbHasFocus
= true;
842 Show( true, ShowFlags::NoActivate
);
847 void FloatingWindow::StartPopupMode( ToolBox
* pBox
, FloatWinPopupFlags nFlags
)
849 mpImplData
->mpBox
= pBox
;
851 // get selected button
852 ToolBoxItemId nItemId
= pBox
->GetDownItemId();
855 pBox
->ImplFloatControl( true, this );
857 // retrieve some data from the ToolBox
858 tools::Rectangle aRect
= nItemId
? pBox
->GetItemRect( nItemId
) : pBox
->GetOverflowRect();
860 // convert to parent's screen coordinates
861 mpImplData
->maPos
= GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox
->OutputToAbsoluteScreenPixel( aRect
.TopLeft() ) ) );
862 aRect
.SetPos( mpImplData
->maPos
);
865 FloatWinPopupFlags::AllMouseButtonClose
|
866 FloatWinPopupFlags::NoMouseUpClose
;
868 // set Flags for positioning
869 if ( !(nFlags
& (FloatWinPopupFlags::Down
| FloatWinPopupFlags::Up
|
870 FloatWinPopupFlags::Left
| FloatWinPopupFlags::Right
)) )
872 if ( pBox
->IsHorizontal() )
873 nFlags
|= FloatWinPopupFlags::Down
;
875 nFlags
|= FloatWinPopupFlags::Right
;
878 // start FloatingMode
879 StartPopupMode( aRect
, nFlags
);
882 void FloatingWindow::ImplEndPopupMode( FloatWinPopupEndFlags nFlags
, const VclPtr
<vcl::Window
>& xFocusId
)
884 if ( !mbInPopupMode
)
887 ImplSVData
* pSVData
= ImplGetSVData();
889 mbInCleanUp
= true; // prevent killing this window due to focus change while working with it
891 if (!(nFlags
& FloatWinPopupEndFlags::NoCloseChildren
))
893 // stop the PopupMode also for all PopupMode windows created after us
894 std::vector
<VclPtr
<FloatingWindow
>> aCancelFloats
;
895 // stop the PopupMode also for all following PopupMode windows
896 for (auto pFloat
= pSVData
->mpWinData
->mpFirstFloat
;
897 pFloat
!= nullptr && pFloat
!= this;
898 pFloat
= pFloat
->mpNextFloat
)
899 aCancelFloats
.push_back(pFloat
);
900 for (auto & it
: aCancelFloats
)
901 it
->EndPopupMode(FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::NoCloseChildren
);
904 // delete window from the list
905 pSVData
->mpWinData
->mpFirstFloat
= mpNextFloat
;
906 mpNextFloat
= nullptr;
908 FloatWinPopupFlags nPopupModeFlags
= mnPopupModeFlags
;
909 mbPopupModeTearOff
= nFlags
& FloatWinPopupEndFlags::TearOff
&&
910 nPopupModeFlags
& FloatWinPopupFlags::AllowTearOff
;
912 // hide window again if it was not deleted
913 if (!mbPopupModeTearOff
)
914 Show( false, ShowFlags::NoFocusChange
);
916 if (HasChildPathFocus() && xFocusId
!= nullptr)
918 // restore focus to previous focus window if we still have the focus
919 Window::EndSaveFocus(xFocusId
);
921 else if ( pSVData
->mpWinData
->mpFocusWin
&& pSVData
->mpWinData
->mpFirstFloat
&&
922 ImplIsWindowOrChild( pSVData
->mpWinData
->mpFocusWin
) )
924 // maybe pass focus on to a suitable FloatingWindow
925 pSVData
->mpWinData
->mpFirstFloat
->GrabFocus();
928 mbPopupModeCanceled
= bool(nFlags
& FloatWinPopupEndFlags::Cancel
);
931 SetTitleType( mnOldTitle
);
933 // set ToolBox again to normal
934 if (mpImplData
&& mpImplData
->mpBox
)
936 mpImplData
->mpBox
->ImplFloatControl( false, this );
937 // if the parent ToolBox is in popup mode, it should be closed too.
938 if ( GetDockingManager()->IsInPopupMode( mpImplData
->mpBox
) )
939 nFlags
|= FloatWinPopupEndFlags::CloseAll
;
941 mpImplData
->mpBox
= nullptr;
944 // call PopupModeEnd-Handler depending on parameter
945 if ( !(nFlags
& FloatWinPopupEndFlags::DontCallHdl
) )
946 ImplCallPopupModeEnd();
948 // close all other windows depending on parameter
949 if ( nFlags
& FloatWinPopupEndFlags::CloseAll
)
951 if ( !(nPopupModeFlags
& FloatWinPopupFlags::NewLevel
) )
953 if (pSVData
->mpWinData
->mpFirstFloat
)
955 FloatingWindow
* pLastLevelFloat
= pSVData
->mpWinData
->mpFirstFloat
->ImplFindLastLevelFloat();
956 pLastLevelFloat
->EndPopupMode( FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
964 void FloatingWindow::EndPopupMode( FloatWinPopupEndFlags nFlags
)
966 ImplEndPopupMode(nFlags
, mxPrevFocusWin
);
969 void FloatingWindow::AddPopupModeWindow(vcl::Window
* pWindow
)
971 // !!! up-to-now only 1 window and not yet a list
972 mpFirstPopupModeWin
= pWindow
;
975 bool SystemWindow::UpdatePositionData()
977 auto pWin
= ImplGetParent();
980 // Simulate Move, so the relative position of the floating window will be recalculated
981 pWin
->ImplCallMove();
988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */