bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / window / floatwin.cxx
blobbaa3a46bc978ac7c739e542c9cfb93f40f2aa469
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>
25 #include <comphelper/lok.hxx>
26 #include <sal/log.hxx>
27 #include <vcl/layout.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/wrkwin.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/toolbox.hxx>
32 #include <vcl/floatwin.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/IDialogRenderable.hxx>
36 class FloatingWindow::ImplData
38 public:
39 ImplData();
41 VclPtr<ToolBox> mpBox;
42 tools::Rectangle maItemEdgeClipRect; // used to clip the common edge between a toolbar item and the border of this window
43 Point maPos; // position of the floating window wrt. parent
44 Point maLOKTwipsPos; ///< absolute position of the floating window in the document - in twips (for toplevel floating windows).
47 FloatingWindow::ImplData::ImplData()
49 mpBox = nullptr;
52 tools::Rectangle& FloatingWindow::ImplGetItemEdgeClipRect()
54 return mpImplData->maItemEdgeClipRect;
57 void FloatingWindow::ImplInitFloating( vcl::Window* pParent, WinBits nStyle )
59 mpImplData.reset(new ImplData);
61 mpWindowImpl->mbFloatWin = true;
62 mbInCleanUp = false;
63 mbGrabFocus = false;
65 SAL_WARN_IF(!pParent, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL!");
67 if (!pParent)
68 pParent = ImplGetSVData()->maWinData.mpAppWin;
70 SAL_WARN_IF(!pParent, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL and no AppWindow exists");
72 // no Border, then we don't need a border window
73 if (!nStyle)
75 mpWindowImpl->mbOverlapWin = true;
76 nStyle |= WB_DIALOGCONTROL;
77 ImplInit(pParent, nStyle, nullptr);
79 else
81 if (!(nStyle & WB_NODIALOGCONTROL))
82 nStyle |= WB_DIALOGCONTROL;
84 if (nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE)
85 && !(nStyle & WB_OWNERDRAWDECORATION))
87 WinBits nFloatWinStyle = nStyle;
88 // #99154# floaters are not closeable by default anymore, eg fullscreen floater
89 // nFloatWinStyle |= WB_CLOSEABLE;
90 mpWindowImpl->mbFrame = true;
91 mpWindowImpl->mbOverlapWin = true;
92 ImplInit(pParent, nFloatWinStyle & ~WB_BORDER, nullptr);
94 else
96 VclPtr<ImplBorderWindow> pBorderWin;
97 BorderWindowStyle nBorderStyle = BorderWindowStyle::Float;
99 if (nStyle & WB_OWNERDRAWDECORATION)
100 nBorderStyle |= BorderWindowStyle::Frame;
101 else
102 nBorderStyle |= BorderWindowStyle::Overlap;
104 if ((nStyle & WB_SYSTEMWINDOW) && !(nStyle & (WB_MOVEABLE | WB_SIZEABLE)))
106 nBorderStyle |= BorderWindowStyle::Frame;
107 nStyle |= WB_CLOSEABLE; // make undecorated floaters closeable
109 pBorderWin = VclPtr<ImplBorderWindow>::Create(pParent, nStyle, nBorderStyle);
110 ImplInit(pBorderWin, nStyle & ~WB_BORDER, nullptr);
111 pBorderWin->mpWindowImpl->mpClientWindow = this;
112 pBorderWin->GetBorder(mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder,
113 mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder);
114 pBorderWin->SetDisplayActive(true);
115 mpWindowImpl->mpBorderWindow = pBorderWin;
116 mpWindowImpl->mpRealParent = pParent;
119 SetActivateMode( ActivateModeFlags::NONE );
121 mpNextFloat = nullptr;
122 mpFirstPopupModeWin = nullptr;
123 mnPostId = nullptr;
124 mnTitle = (nStyle & (WB_MOVEABLE | WB_POPUP)) ? FloatWinTitleType::Normal : FloatWinTitleType::NONE;
125 mnOldTitle = mnTitle;
126 mnPopupModeFlags = FloatWinPopupFlags::NONE;
127 mbInPopupMode = false;
128 mbPopupMode = false;
129 mbPopupModeCanceled = false;
130 mbPopupModeTearOff = false;
131 mbMouseDown = false;
133 ImplInitSettings();
136 void FloatingWindow::ImplInitSettings()
138 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
140 Color aColor;
141 if (IsControlBackground())
142 aColor = GetControlBackground();
143 else if (Window::GetStyle() & WB_3DLOOK)
144 aColor = rStyleSettings.GetFaceColor();
145 else
146 aColor = rStyleSettings.GetWindowColor();
147 SetBackground(aColor);
150 FloatingWindow::FloatingWindow(vcl::Window* pParent, WinBits nStyle) :
151 SystemWindow(WindowType::FLOATINGWINDOW)
153 ImplInitFloating(pParent, nStyle);
156 FloatingWindow::FloatingWindow(vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription, const css::uno::Reference<css::frame::XFrame> &rFrame)
157 : SystemWindow(WindowType::FLOATINGWINDOW)
158 , mpNextFloat(nullptr)
159 , mpFirstPopupModeWin(nullptr)
160 , mnPostId(nullptr)
161 , mnPopupModeFlags(FloatWinPopupFlags::NONE)
162 , mnTitle(FloatWinTitleType::Unknown)
163 , mnOldTitle(FloatWinTitleType::Unknown)
164 , mbInPopupMode(false)
165 , mbPopupMode(false)
166 , mbPopupModeCanceled(false)
167 , mbPopupModeTearOff(false)
168 , mbMouseDown(false)
169 , mbGrabFocus(false)
170 , mbInCleanUp(false)
172 loadUI(pParent, rID, rUIXMLDescription, rFrame);
175 //Find the real parent stashed in mpDialogParent.
176 void FloatingWindow::doDeferredInit(WinBits nBits)
178 vcl::Window *pParent = mpDialogParent;
179 mpDialogParent = nullptr;
180 ImplInitFloating(pParent, nBits);
181 mbIsDeferredInit = false;
184 void FloatingWindow::ApplySettings(vcl::RenderContext& rRenderContext)
186 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
188 Color aColor;
189 if (Window::GetStyle() & WB_3DLOOK)
190 aColor = rStyleSettings.GetFaceColor();
191 else
192 aColor = rStyleSettings.GetWindowColor();
194 ApplyControlBackground(rRenderContext, aColor);
197 FloatingWindow::~FloatingWindow()
199 disposeOnce();
200 assert (!mnPostId);
203 void FloatingWindow::dispose()
205 if (mpImplData)
207 if( mbPopupModeCanceled )
208 // indicates that ESC key was pressed
209 // will be handled in Window::ImplGrabFocus()
210 SetDialogControlFlags( GetDialogControlFlags() | DialogControlFlags::FloatWinPopupModeEndCancel );
212 if ( IsInPopupMode() )
213 EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll | FloatWinPopupEndFlags::DontCallHdl );
215 if ( mnPostId )
216 Application::RemoveUserEvent( mnPostId );
217 mnPostId = nullptr;
220 mpImplData.reset();
222 mpNextFloat.clear();
223 mpFirstPopupModeWin.clear();
224 mxPrevFocusWin.clear();
225 SystemWindow::dispose();
228 Point FloatingWindow::CalcFloatingPosition( vcl::Window* pWindow, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags, sal_uInt16& rArrangeIndex )
230 return ImplCalcPos( pWindow, rRect, nFlags, rArrangeIndex );
233 Point FloatingWindow::ImplCalcPos(vcl::Window* pWindow,
234 const tools::Rectangle& rRect, FloatWinPopupFlags nFlags,
235 sal_uInt16& rArrangeIndex, Point* pLOKTwipsPos)
237 // get window position
238 Point aPos;
239 Size aSize = ::isLayoutEnabled(pWindow) ? pWindow->get_preferred_size() : pWindow->GetSizePixel();
240 tools::Rectangle aScreenRect = pWindow->ImplGetFrameWindow()->GetDesktopRectPixel();
241 FloatingWindow *pFloatingWindow = dynamic_cast<FloatingWindow*>( pWindow );
243 // convert...
244 vcl::Window* pW = pWindow;
245 if ( pW->mpWindowImpl->mpRealParent )
246 pW = pW->mpWindowImpl->mpRealParent;
248 tools::Rectangle normRect( rRect ); // rRect is already relative to top-level window
249 normRect.SetPos( pW->ScreenToOutputPixel( normRect.TopLeft() ) );
251 bool bRTL = AllSettings::GetLayoutRTL();
253 tools::Rectangle devRect( pW->OutputToAbsoluteScreenPixel( normRect.TopLeft() ),
254 pW->OutputToAbsoluteScreenPixel( normRect.BottomRight() ) );
256 tools::Rectangle devRectRTL( devRect );
257 if( bRTL )
258 // create a rect that can be compared to desktop coordinates
259 devRectRTL = pW->ImplOutputToUnmirroredAbsoluteScreenPixel( normRect );
260 if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
261 aScreenRect = Application::GetScreenPosSizePixel(
262 Application::GetBestScreen( bRTL ? devRectRTL : devRect ) );
264 FloatWinPopupFlags nArrangeAry[5];
265 Point e1,e2; // the common edge between the item rect and the floating window
267 if ( nFlags & FloatWinPopupFlags::Left )
269 nArrangeAry[0] = FloatWinPopupFlags::Left;
270 nArrangeAry[1] = FloatWinPopupFlags::Right;
271 nArrangeAry[2] = FloatWinPopupFlags::Up;
272 nArrangeAry[3] = FloatWinPopupFlags::Down;
273 nArrangeAry[4] = FloatWinPopupFlags::Left;
275 else if ( nFlags & FloatWinPopupFlags::Right )
277 nArrangeAry[0] = FloatWinPopupFlags::Right;
278 nArrangeAry[1] = FloatWinPopupFlags::Left;
279 nArrangeAry[2] = FloatWinPopupFlags::Up;
280 nArrangeAry[3] = FloatWinPopupFlags::Down;
281 nArrangeAry[4] = FloatWinPopupFlags::Right;
283 else if ( nFlags & FloatWinPopupFlags::Up )
285 nArrangeAry[0] = FloatWinPopupFlags::Up;
286 nArrangeAry[1] = FloatWinPopupFlags::Down;
287 nArrangeAry[2] = FloatWinPopupFlags::Right;
288 nArrangeAry[3] = FloatWinPopupFlags::Left;
289 nArrangeAry[4] = FloatWinPopupFlags::Up;
291 else
293 nArrangeAry[0] = FloatWinPopupFlags::Down;
294 nArrangeAry[1] = FloatWinPopupFlags::Up;
295 nArrangeAry[2] = FloatWinPopupFlags::Right;
296 nArrangeAry[3] = FloatWinPopupFlags::Left;
297 nArrangeAry[4] = FloatWinPopupFlags::Down;
300 sal_uInt16 nArrangeIndex = 0;
301 const bool bLOKActive = comphelper::LibreOfficeKit::isActive();
303 for ( ; nArrangeIndex < 5; nArrangeIndex++ )
305 bool bBreak = true;
306 switch ( nArrangeAry[nArrangeIndex] )
309 case FloatWinPopupFlags::Left:
310 aPos.setX( devRect.Left()-aSize.Width()+1 );
311 aPos.setY( devRect.Top() );
312 aPos.AdjustY( -(pWindow->mpWindowImpl->mnTopBorder) );
313 if( bRTL )
315 if( (devRectRTL.Right()+aSize.Width()) > aScreenRect.Right() )
316 bBreak = false;
318 else
320 if ( aPos.X() < aScreenRect.Left() )
321 bBreak = false;
323 if (bBreak || bLOKActive)
325 e1 = devRect.TopLeft();
326 e2 = devRect.BottomLeft();
327 // set non-zero width
328 e2.AdjustX( 1 );
329 // don't clip corners
330 e1.AdjustY( 1 );
331 e2.AdjustY( -1 );
333 break;
334 case FloatWinPopupFlags::Right:
335 aPos = devRect.TopRight();
336 aPos.AdjustY( -(pWindow->mpWindowImpl->mnTopBorder) );
337 if( bRTL )
339 if( (devRectRTL.Left() - aSize.Width()) < aScreenRect.Left() )
340 bBreak = false;
342 else
344 if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
345 bBreak = false;
347 if (bBreak || bLOKActive)
349 e1 = devRect.TopRight();
350 e2 = devRect.BottomRight();
351 // set non-zero width
352 e2.AdjustX( 1 );
353 // don't clip corners
354 e1.AdjustY( 1 );
355 e2.AdjustY( -1 );
357 break;
358 case FloatWinPopupFlags::Up:
359 aPos.setX( devRect.Left() );
360 aPos.setY( devRect.Top()-aSize.Height()+1 );
361 if ( aPos.Y() < aScreenRect.Top() )
362 bBreak = false;
363 if (bBreak || bLOKActive)
365 e1 = devRect.TopLeft();
366 e2 = devRect.TopRight();
367 // set non-zero height
368 e2.AdjustY( 1 );
369 // don't clip corners
370 e1.AdjustX( 1 );
371 e2.AdjustX( -1 );
373 break;
374 case FloatWinPopupFlags::Down:
375 aPos = devRect.BottomLeft();
376 if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
377 bBreak = false;
378 if (bBreak || bLOKActive)
380 e1 = devRect.BottomLeft();
381 e2 = devRect.BottomRight();
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 default: break;
392 // no further adjustment for LibreOfficeKit
393 if (bLOKActive)
394 break;
396 // adjust if necessary
397 if (bBreak)
399 if ( (nArrangeAry[nArrangeIndex] == FloatWinPopupFlags::Left) ||
400 (nArrangeAry[nArrangeIndex] == FloatWinPopupFlags::Right) )
402 if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
404 aPos.setY( devRect.Bottom()-aSize.Height()+1 );
405 if ( aPos.Y() < aScreenRect.Top() )
406 aPos.setY( aScreenRect.Top() );
409 else
411 if( bRTL )
413 if( devRectRTL.Right()-aSize.Width()+1 < aScreenRect.Left() )
414 aPos.AdjustX( -(aScreenRect.Left() - devRectRTL.Right() + aSize.Width() - 1) );
416 else if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
418 aPos.setX( devRect.Right()-aSize.Width()+1 );
419 if ( aPos.X() < aScreenRect.Left() )
420 aPos.setX( aScreenRect.Left() );
425 if ( bBreak )
426 break;
428 if ( nArrangeIndex > 4 )
429 nArrangeIndex = 4;
431 rArrangeIndex = nArrangeIndex;
433 aPos = pW->AbsoluteScreenToOutputPixel( aPos );
435 // store a cliprect that can be used to clip the common edge of the itemrect and the floating window
436 if( pFloatingWindow && pFloatingWindow->mpImplData->mpBox )
438 pFloatingWindow->mpImplData->maItemEdgeClipRect =
439 tools::Rectangle( e1, e2 );
442 if (bLOKActive && pLOKTwipsPos)
444 if (pW->IsMapModeEnabled() || pW->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
446 // if we use pW->LogicToLogic(aPos, pW->GetMapMode(), MapMode(MapUnit::MapTwip)),
447 // for pixel conversions when map mode is not enabled, we get
448 // a 20 twips per pixel conversion since LogicToLogic uses
449 // a fixed 72 dpi value, instead of a correctly computed output
450 // device dpi or at least the most commonly used 96 dpi value;
451 // and anyway the following is what we already do in
452 // ScGridWindow::LogicInvalidate when map mode is not enabled.
454 *pLOKTwipsPos = pW->PixelToLogic(aPos, MapMode(MapUnit::MapTwip));
456 else
458 *pLOKTwipsPos = OutputDevice::LogicToLogic(aPos, pW->GetMapMode(), MapMode(MapUnit::MapTwip));
462 // caller expects coordinates relative to top-level win
463 return pW->OutputToScreenPixel( aPos );
466 Point FloatingWindow::ImplConvertToAbsPos(vcl::Window* pReference, const Point& rPos)
468 Point aAbsolute( rPos );
470 const OutputDevice *pWindowOutDev = pReference->GetOutDev();
472 // compare coordinates in absolute screen coordinates
473 if( pReference->HasMirroredGraphics() )
475 if(!pReference->IsRTLEnabled() )
476 pWindowOutDev->ReMirror( aAbsolute );
478 tools::Rectangle aRect( pReference->ScreenToOutputPixel(aAbsolute), Size(1,1) ) ;
479 aRect = pReference->ImplOutputToUnmirroredAbsoluteScreenPixel( aRect );
480 aAbsolute = aRect.TopLeft();
482 else
483 aAbsolute = pReference->OutputToAbsoluteScreenPixel(
484 pReference->ScreenToOutputPixel(rPos) );
486 return aAbsolute;
489 tools::Rectangle FloatingWindow::ImplConvertToAbsPos(vcl::Window* pReference, const tools::Rectangle& rRect)
491 tools::Rectangle aFloatRect = rRect;
493 const OutputDevice *pParentWinOutDev = pReference->GetOutDev();
495 // compare coordinates in absolute screen coordinates
496 // Keep in sync with FloatingWindow::ImplFloatHitTest, e.g. fdo#33509
497 if( pReference->HasMirroredGraphics() )
499 if(!pReference->IsRTLEnabled() )
500 pParentWinOutDev->ReMirror(aFloatRect);
502 aFloatRect.SetPos(pReference->ScreenToOutputPixel(aFloatRect.TopLeft()));
503 aFloatRect = pReference->ImplOutputToUnmirroredAbsoluteScreenPixel(aFloatRect);
505 else
506 aFloatRect.SetPos(pReference->OutputToAbsoluteScreenPixel(pReference->ScreenToOutputPixel(rRect.TopLeft())));
507 return aFloatRect;
510 FloatingWindow* FloatingWindow::ImplFloatHitTest( vcl::Window* pReference, const Point& rPos, bool& rbHitTestInsideRect )
512 FloatingWindow* pWin = this;
513 rbHitTestInsideRect = false;
515 Point aAbsolute(FloatingWindow::ImplConvertToAbsPos(pReference, rPos));
519 // compute the floating window's size in absolute screen coordinates
521 // use the border window to have the exact position
522 vcl::Window *pBorderWin = pWin->GetWindow( GetWindowType::Border );
524 // the top-left corner in output coordinates ie (0,0)
525 tools::Rectangle devRect( pBorderWin->ImplOutputToUnmirroredAbsoluteScreenPixel( tools::Rectangle( Point(), pBorderWin->GetSizePixel()) ) ) ;
526 if ( devRect.IsInside( aAbsolute ) )
528 // inside the window
529 return pWin;
532 // test, if mouse is in rectangle, (this is typically the rect of the active
533 // toolbox item or similar)
534 // note: maFloatRect is set in FloatingWindow::StartPopupMode() and
535 // is already in absolute device coordinates
536 if ( pWin->maFloatRect.IsInside( aAbsolute ) )
538 rbHitTestInsideRect = true;
539 return pWin;
542 pWin = pWin->mpNextFloat;
544 while ( pWin );
546 return nullptr;
549 FloatingWindow* FloatingWindow::ImplFindLastLevelFloat()
551 FloatingWindow* pWin = this;
552 FloatingWindow* pLastFoundWin = pWin;
556 if ( pWin->GetPopupModeFlags() & FloatWinPopupFlags::NewLevel )
557 pLastFoundWin = pWin;
559 pWin = pWin->mpNextFloat;
561 while ( pWin );
563 return pLastFoundWin;
566 bool FloatingWindow::ImplIsFloatPopupModeWindow( const vcl::Window* pWindow )
568 FloatingWindow* pWin = this;
572 if ( pWin->mpFirstPopupModeWin == pWindow )
573 return true;
575 pWin = pWin->mpNextFloat;
577 while ( pWin );
579 return false;
582 IMPL_LINK_NOARG(FloatingWindow, ImplEndPopupModeHdl, void*, void)
584 VclPtr<FloatingWindow> pThis(this);
585 mnPostId = nullptr;
586 mnPopupModeFlags = FloatWinPopupFlags::NONE;
587 mbPopupMode = false;
588 PopupModeEnd();
591 bool FloatingWindow::EventNotify( NotifyEvent& rNEvt )
593 // call Base Class first for tab control
594 bool bRet = SystemWindow::EventNotify( rNEvt );
595 if ( !bRet )
597 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
599 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
600 vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
601 sal_uInt16 nKeyCode = aKeyCode.GetCode();
603 if ( (nKeyCode == KEY_ESCAPE) && (GetStyle() & WB_CLOSEABLE) )
605 Close();
606 return true;
611 return bRet;
614 void FloatingWindow::PixelInvalidate(const tools::Rectangle* /*pRectangle*/)
616 if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
618 std::vector<vcl::LOKPayloadItem> aPayload;
619 const tools::Rectangle aRect(Point(0,0), Size(GetSizePixel().Width()+1, GetSizePixel().Height()+1));
620 aPayload.push_back(std::make_pair(OString("rectangle"), aRect.toString()));
621 const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
622 pNotifier->notifyWindow(GetLOKWindowId(), "invalidate", aPayload);
626 void FloatingWindow::StateChanged( StateChangedType nType )
628 if (nType == StateChangedType::InitShow)
630 DoInitialLayout();
633 SystemWindow::StateChanged( nType );
635 VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier();
636 if (pParent)
638 if (nType == StateChangedType::InitShow)
640 std::vector<vcl::LOKPayloadItem> aItems;
641 if (pParent == this)
643 // we are a toplevel window, let's so far pretend to be a
644 // dialog - but maybe we'll need a separate type for this
645 // later
646 aItems.emplace_back("type", "dialog");
647 aItems.emplace_back("position", mpImplData->maLOKTwipsPos.toString()); // twips
649 else
651 SetLOKNotifier(pParent->GetLOKNotifier());
652 aItems.emplace_back("type", "child");
653 aItems.emplace_back("parentId", OString::number(pParent->GetLOKWindowId()));
654 aItems.emplace_back("position", mpImplData->maPos.toString()); // pixels
656 aItems.emplace_back("size", GetSizePixel().toString());
657 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "created", aItems);
659 else if (!IsVisible() && nType == StateChangedType::Visible)
661 assert(GetLOKNotifier());
662 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "close");
663 ReleaseLOKNotifier();
667 if ( nType == StateChangedType::ControlBackground )
669 ImplInitSettings();
670 Invalidate();
674 void FloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
676 SystemWindow::DataChanged( rDCEvt );
678 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
679 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
681 ImplInitSettings();
682 Invalidate();
686 void FloatingWindow::ImplCallPopupModeEnd()
688 // PopupMode is finished
689 mbInPopupMode = false;
691 // call Handler asynchronously.
692 if ( mpImplData && !mnPostId )
693 mnPostId = Application::PostUserEvent(LINK(this, FloatingWindow, ImplEndPopupModeHdl));
696 void FloatingWindow::PopupModeEnd()
698 maPopupModeEndHdl.Call( this );
701 void FloatingWindow::SetTitleType( FloatWinTitleType nTitle )
703 if ( (mnTitle != nTitle) && mpWindowImpl->mpBorderWindow )
705 mnTitle = nTitle;
706 Size aOutSize = GetOutputSizePixel();
707 BorderWindowTitleType nTitleStyle;
708 if ( nTitle == FloatWinTitleType::Normal )
709 nTitleStyle = BorderWindowTitleType::Small;
710 else if ( nTitle == FloatWinTitleType::TearOff )
711 nTitleStyle = BorderWindowTitleType::Tearoff;
712 else if ( nTitle == FloatWinTitleType::Popup )
713 nTitleStyle = BorderWindowTitleType::Popup;
714 else // nTitle == FloatWinTitleType::NONE
715 nTitleStyle = BorderWindowTitleType::NONE;
716 static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->SetTitleType( nTitleStyle, aOutSize );
717 static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
721 void FloatingWindow::StartPopupMode( const tools::Rectangle& rRect, FloatWinPopupFlags nFlags )
723 if ( IsRollUp() )
724 RollDown();
726 // remove title
727 mnOldTitle = mnTitle;
728 if ( ( mpWindowImpl->mnStyle & WB_POPUP ) && !GetText().isEmpty() )
729 SetTitleType( FloatWinTitleType::Popup );
730 else if ( nFlags & FloatWinPopupFlags::AllowTearOff )
731 SetTitleType( FloatWinTitleType::TearOff );
732 else
733 SetTitleType( FloatWinTitleType::NONE );
735 // avoid close on focus change for decorated floating windows only
736 if( mpWindowImpl->mbFrame && (GetStyle() & WB_MOVEABLE) )
737 nFlags |= FloatWinPopupFlags::NoAppFocusClose;
739 // compute window position according to flags and arrangement
740 sal_uInt16 nArrangeIndex;
741 DoInitialLayout();
742 mpImplData->maPos = ImplCalcPos(this, rRect, nFlags, nArrangeIndex, &mpImplData->maLOKTwipsPos);
743 SetPosPixel( mpImplData->maPos );
744 ImplGetFrame()->PositionByToolkit(rRect, nFlags);
746 // set data and display window
747 // convert maFloatRect to absolute device coordinates
748 // so they can be compared across different frames
749 // !!! rRect is expected to be in screen coordinates of the parent frame window !!!
750 maFloatRect = FloatingWindow::ImplConvertToAbsPos(GetParent(), rRect);
752 maFloatRect.AdjustLeft( -2 );
753 maFloatRect.AdjustTop( -2 );
754 maFloatRect.AdjustRight(2 );
755 maFloatRect.AdjustBottom(2 );
756 mnPopupModeFlags = nFlags;
757 mbInPopupMode = true;
758 mbPopupMode = true;
759 mbPopupModeCanceled = false;
760 mbPopupModeTearOff = false;
761 mbMouseDown = false;
763 // add FloatingWindow to list of windows that are in popup mode
764 ImplSVData* pSVData = ImplGetSVData();
765 mpNextFloat = pSVData->maWinData.mpFirstFloat;
766 pSVData->maWinData.mpFirstFloat = this;
767 if (nFlags & FloatWinPopupFlags::GrabFocus)
769 // force key input even without focus (useful for menus)
770 mbGrabFocus = true;
771 mxPrevFocusWin = Window::SaveFocus();
772 mpWindowImpl->mpFrameData->mbHasFocus = true;
773 GrabFocus();
775 Show( true, ShowFlags::NoActivate );
778 void FloatingWindow::StartPopupMode( ToolBox* pBox, FloatWinPopupFlags nFlags )
780 mpImplData->mpBox = pBox;
782 // get selected button
783 sal_uInt16 nItemId = pBox->GetDownItemId();
785 if ( nItemId )
786 pBox->ImplFloatControl( true, this );
788 // retrieve some data from the ToolBox
789 tools::Rectangle aRect = nItemId ? pBox->GetItemRect( nItemId ) : pBox->GetOverflowRect();
791 // convert to parent's screen coordinates
792 mpImplData->maPos = GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) ) );
793 aRect.SetPos( mpImplData->maPos );
795 nFlags |=
796 FloatWinPopupFlags::AllMouseButtonClose |
797 FloatWinPopupFlags::NoMouseUpClose;
799 // set Flags for positioning
800 if ( !(nFlags & (FloatWinPopupFlags::Down | FloatWinPopupFlags::Up |
801 FloatWinPopupFlags::Left | FloatWinPopupFlags::Right)) )
803 if ( pBox->IsHorizontal() )
804 nFlags |= FloatWinPopupFlags::Down;
805 else
806 nFlags |= FloatWinPopupFlags::Right;
809 // start FloatingMode
810 StartPopupMode( aRect, nFlags );
813 void FloatingWindow::ImplEndPopupMode( FloatWinPopupEndFlags nFlags, const VclPtr<vcl::Window>& xFocusId )
815 if ( !mbInPopupMode )
816 return;
818 ImplSVData* pSVData = ImplGetSVData();
820 mbInCleanUp = true; // prevent killing this window due to focus change while working with it
822 // stop the PopupMode also for all following PopupMode windows
823 while ( pSVData->maWinData.mpFirstFloat && pSVData->maWinData.mpFirstFloat.get() != this )
824 pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel );
826 // delete window from the list
827 pSVData->maWinData.mpFirstFloat = mpNextFloat;
828 mpNextFloat = nullptr;
830 FloatWinPopupFlags nPopupModeFlags = mnPopupModeFlags;
831 mbPopupModeTearOff = nFlags & FloatWinPopupEndFlags::TearOff &&
832 nPopupModeFlags & FloatWinPopupFlags::AllowTearOff;
834 // hide window again if it was not deleted
835 if (!mbPopupModeTearOff)
836 Show( false, ShowFlags::NoFocusChange );
838 if (HasChildPathFocus() && xFocusId != nullptr)
840 // restore focus to previous focus window if we still have the focus
841 Window::EndSaveFocus(xFocusId);
843 else if ( pSVData->maWinData.mpFocusWin && pSVData->maWinData.mpFirstFloat &&
844 ImplIsWindowOrChild( pSVData->maWinData.mpFocusWin ) )
846 // maybe pass focus on to a suitable FloatingWindow
847 pSVData->maWinData.mpFirstFloat->GrabFocus();
850 mbPopupModeCanceled = bool(nFlags & FloatWinPopupEndFlags::Cancel);
852 // redo title
853 SetTitleType( mnOldTitle );
855 // set ToolBox again to normal
856 if (mpImplData && mpImplData->mpBox)
858 mpImplData->mpBox->ImplFloatControl( false, this );
859 // if the parent ToolBox is in popup mode, it should be closed too.
860 if ( GetDockingManager()->IsInPopupMode( mpImplData->mpBox ) )
861 nFlags |= FloatWinPopupEndFlags::CloseAll;
863 mpImplData->mpBox = nullptr;
866 // call PopupModeEnd-Handler depending on parameter
867 if ( !(nFlags & FloatWinPopupEndFlags::DontCallHdl) )
868 ImplCallPopupModeEnd();
870 // close all other windows depending on parameter
871 if ( nFlags & FloatWinPopupEndFlags::CloseAll )
873 if ( !(nPopupModeFlags & FloatWinPopupFlags::NewLevel) )
875 if ( pSVData->maWinData.mpFirstFloat )
877 FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
878 pLastLevelFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
883 mbInCleanUp = false;
886 void FloatingWindow::EndPopupMode( FloatWinPopupEndFlags nFlags )
888 ImplEndPopupMode(nFlags, mxPrevFocusWin);
891 void FloatingWindow::AddPopupModeWindow(vcl::Window* pWindow)
893 // !!! up-to-now only 1 window and not yet a list
894 mpFirstPopupModeWin = pWindow;
896 bool FloatingWindow::UpdatePositionData()
898 auto pWin = ImplGetParent();
899 if (pWin)
901 // Simulate Move, so the relative position of the floating window will be recalculated
902 pWin->ImplCallMove();
903 return true;
906 return false;
909 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */