bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / window / floatwin.cxx
blob7455a3bbb90c1b1b20dffe712b444b5cc42a0a2b
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 <svdata.hxx>
21 #include <brdwin.hxx>
22 #include <window.h>
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
39 public:
40 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()
50 mpBox = nullptr;
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;
63 mbInCleanUp = false;
64 mbGrabFocus = false;
66 SAL_WARN_IF(!pParent, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL!");
68 if (!pParent)
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
74 if (!nStyle)
76 mpWindowImpl->mbOverlapWin = true;
77 nStyle |= WB_DIALOGCONTROL;
78 ImplInit(pParent, nStyle, nullptr);
80 else
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);
95 else
97 VclPtr<ImplBorderWindow> pBorderWin;
98 BorderWindowStyle nBorderStyle = BorderWindowStyle::Float;
100 if (nStyle & WB_OWNERDRAWDECORATION)
101 nBorderStyle |= BorderWindowStyle::Frame;
102 else
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;
124 mnPostId = nullptr;
125 mnTitle = (nStyle & (WB_MOVEABLE | WB_POPUP)) ? FloatWinTitleType::Normal : FloatWinTitleType::NONE;
126 mnOldTitle = mnTitle;
127 mnPopupModeFlags = FloatWinPopupFlags::NONE;
128 mbInPopupMode = false;
129 mbPopupMode = false;
130 mbPopupModeCanceled = false;
131 mbPopupModeTearOff = false;
132 mbMouseDown = false;
134 ImplInitSettings();
137 void FloatingWindow::ImplInitSettings()
139 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
141 Color aColor;
142 if (IsControlBackground())
143 aColor = GetControlBackground();
144 else if (Window::GetStyle() & WB_3DLOOK)
145 aColor = rStyleSettings.GetFaceColor();
146 else
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)
161 , mnPostId(nullptr)
162 , mnPopupModeFlags(FloatWinPopupFlags::NONE)
163 , mnTitle(FloatWinTitleType::Unknown)
164 , mnOldTitle(FloatWinTitleType::Unknown)
165 , mbInPopupMode(false)
166 , mbPopupMode(false)
167 , mbPopupModeCanceled(false)
168 , mbPopupModeTearOff(false)
169 , mbMouseDown(false)
170 , mbGrabFocus(false)
171 , mbInCleanUp(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();
189 Color aColor;
190 if (Window::GetStyle() & WB_3DLOOK)
191 aColor = rStyleSettings.GetFaceColor();
192 else
193 aColor = rStyleSettings.GetWindowColor();
195 ApplyControlBackground(rRenderContext, aColor);
198 FloatingWindow::~FloatingWindow()
200 disposeOnce();
201 assert (!mnPostId);
204 void FloatingWindow::dispose()
206 ReleaseLOKNotifier();
208 if (mpImplData)
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 );
218 if ( mnPostId )
219 Application::RemoveUserEvent( mnPostId );
220 mnPostId = nullptr;
223 mpImplData.reset();
225 mpNextFloat.clear();
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
236 Point aPos;
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 );
241 // convert...
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 );
255 if( bRTL )
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;
291 else
293 nArrangeAry[2] = FloatWinPopupFlags::Right;
294 nArrangeAry[3] = FloatWinPopupFlags::Left;
295 nArrangeAry[4] = FloatWinPopupFlags::Up;
298 else
300 nArrangeAry[0] = FloatWinPopupFlags::Down;
301 nArrangeAry[1] = FloatWinPopupFlags::Up;
302 if (nFlags & FloatWinPopupFlags::NoHorzPlacement)
304 nArrangeAry[2] = FloatWinPopupFlags::Down;
305 nArrangeAttempts = 3;
307 else
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++ )
320 bool bBreak = true;
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) );
328 if( bRTL )
330 if( (devRectRTL.Right()+aSize.Width()) > aScreenRect.Right() )
331 bBreak = false;
333 else
335 if ( aPos.X() < aScreenRect.Left() )
336 bBreak = false;
338 if (bBreak || bLOKActive)
340 e1 = devRect.TopLeft();
341 e2 = devRect.BottomLeft();
342 // set non-zero width
343 e2.AdjustX( 1 );
344 // don't clip corners
345 e1.AdjustY( 1 );
346 e2.AdjustY( -1 );
348 break;
349 case FloatWinPopupFlags::Right:
350 aPos = devRect.TopRight();
351 aPos.AdjustY( -(pWindow->mpWindowImpl->mnTopBorder) );
352 if( bRTL )
354 if( (devRectRTL.Left() - aSize.Width()) < aScreenRect.Left() )
355 bBreak = false;
357 else
359 if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
360 bBreak = false;
362 if (bBreak || bLOKActive)
364 e1 = devRect.TopRight();
365 e2 = devRect.BottomRight();
366 // set non-zero width
367 e2.AdjustX( 1 );
368 // don't clip corners
369 e1.AdjustY( 1 );
370 e2.AdjustY( -1 );
372 break;
373 case FloatWinPopupFlags::Up:
374 aPos.setX( devRect.Left() );
375 aPos.setY( devRect.Top()-aSize.Height()+1 );
376 if ( aPos.Y() < aScreenRect.Top() )
377 bBreak = false;
378 if (bBreak || bLOKActive)
380 e1 = devRect.TopLeft();
381 e2 = devRect.TopRight();
382 // set non-zero height
383 e2.AdjustY( 1 );
384 // don't clip corners
385 e1.AdjustX( 1 );
386 e2.AdjustX( -1 );
388 break;
389 case FloatWinPopupFlags::Down:
390 aPos = devRect.BottomLeft();
391 if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
392 bBreak = false;
393 if (bBreak || bLOKActive)
395 e1 = devRect.BottomLeft();
396 e2 = devRect.BottomRight();
397 // set non-zero height
398 e2.AdjustY( 1 );
399 // don't clip corners
400 e1.AdjustX( 1 );
401 e2.AdjustX( -1 );
403 break;
404 default: break;
407 // no further adjustment for LibreOfficeKit
408 if (bLOKActive)
409 break;
411 // adjust if necessary
412 if (bBreak)
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() );
424 else
426 if( bRTL )
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() );
440 if ( bBreak )
441 break;
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));
471 else
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();
497 else
498 aAbsolute = pReference->OutputToAbsoluteScreenPixel(
499 pReference->ScreenToOutputPixel(rPos) );
501 return aAbsolute;
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);
520 else
521 aFloatRect.SetPos(pReference->OutputToAbsoluteScreenPixel(pReference->ScreenToOutputPixel(rRect.TopLeft())));
523 return aFloatRect;
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);
542 else
543 aFloatRect.SetPos(pReference->OutputToScreenPixel(pReference->AbsoluteScreenToOutputPixel(rRect.TopLeft())));
545 return aFloatRect;
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 );
561 if (!pBorderWin)
562 break;
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 ) )
568 // inside the window
569 return pWin;
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;
579 return pWin;
582 pWin = pWin->mpNextFloat;
584 while ( pWin );
586 return nullptr;
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;
601 while ( pWin );
603 return pLastFoundWin;
606 bool FloatingWindow::ImplIsFloatPopupModeWindow( const vcl::Window* pWindow )
608 FloatingWindow* pWin = this;
612 if ( pWin->mpFirstPopupModeWin == pWindow )
613 return true;
615 pWin = pWin->mpNextFloat;
617 while ( pWin );
619 return false;
622 IMPL_LINK_NOARG(FloatingWindow, ImplEndPopupModeHdl, void*, void)
624 VclPtr<FloatingWindow> pThis(this);
625 mnPostId = nullptr;
626 mnPopupModeFlags = FloatWinPopupFlags::NONE;
627 mbPopupMode = false;
628 PopupModeEnd();
631 bool FloatingWindow::EventNotify( NotifyEvent& rNEvt )
633 // call Base Class first for tab control
634 bool bRet = SystemWindow::EventNotify( rNEvt );
635 if ( !bRet )
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) )
645 Close();
646 return true;
651 return bRet;
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)
672 DoInitialLayout();
675 SystemWindow::StateChanged( nType );
677 VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier();
678 if (pParent)
680 if (nType == StateChangedType::InitShow)
682 std::vector<vcl::LOKPayloadItem> aItems;
683 if (pParent == this)
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
687 // later
688 if (mbInPopupMode)
689 aItems.emplace_back("type", "dropdown");
690 else
691 aItems.emplace_back("type", "dialog");
692 aItems.emplace_back("position", mpImplData->maLOKTwipsPos.toString()); // twips
694 else
696 SetLOKNotifier(pParent->GetLOKNotifier());
697 if (dynamic_cast<HelpTextWindow*>(this))
698 aItems.emplace_back("type", "tooltip");
699 else
700 aItems.emplace_back("type", "child");
702 aItems.emplace_back("parentId", OString::number(pParent->GetLOKWindowId()));
703 if (mbInPopupMode)
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 )
724 ImplInitSettings();
725 Invalidate();
729 void FloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
731 SystemWindow::DataChanged( rDCEvt );
733 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
734 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
736 ImplInitSettings();
737 Invalidate();
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 )
759 return;
761 mnTitle = nTitle;
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 )
778 // remove title
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 );
784 else
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;
793 DoInitialLayout();
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
803 autofilter dropdown.
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;
825 mbPopupMode = true;
826 mbPopupModeCanceled = false;
827 mbPopupModeTearOff = false;
828 mbMouseDown = 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);
835 if (bGrabFocus)
837 // force key input even without focus (useful for menus)
838 mbGrabFocus = true;
839 mxPrevFocusWin = Window::SaveFocus();
840 mpWindowImpl->mpFrameData->mbHasFocus = true;
842 Show( true, ShowFlags::NoActivate );
843 if (bGrabFocus)
844 GrabFocus();
847 void FloatingWindow::StartPopupMode( ToolBox* pBox, FloatWinPopupFlags nFlags )
849 mpImplData->mpBox = pBox;
851 // get selected button
852 ToolBoxItemId nItemId = pBox->GetDownItemId();
854 if ( nItemId )
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 );
864 nFlags |=
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;
874 else
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 )
885 return;
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);
930 // redo title
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 );
961 mbInCleanUp = false;
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();
978 if (pWin)
980 // Simulate Move, so the relative position of the floating window will be recalculated
981 pWin->ImplCallMove();
982 return true;
985 return false;
988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */