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>
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
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()
52 tools::Rectangle
& FloatingWindow::ImplGetItemEdgeClipRect()
54 return mpImplData
->maItemEdgeClipRect
;
57 void FloatingWindow::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
59 mpImplData
.reset(new ImplData
);
61 mpWindowImpl
->mbFloatWin
= true;
65 SAL_WARN_IF(!pParent
, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL!");
68 pParent
= ImplGetSVData()->maFrameData
.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
75 mpWindowImpl
->mbOverlapWin
= true;
76 nStyle
|= WB_DIALOGCONTROL
;
77 SystemWindow::ImplInit(pParent
, nStyle
, nullptr);
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 SystemWindow::ImplInit(pParent
, nFloatWinStyle
& ~WB_BORDER
, nullptr);
96 VclPtr
<ImplBorderWindow
> pBorderWin
;
97 BorderWindowStyle nBorderStyle
= BorderWindowStyle::Border
| BorderWindowStyle::Float
;
99 if (nStyle
& WB_OWNERDRAWDECORATION
)
100 nBorderStyle
|= BorderWindowStyle::Frame
;
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 SystemWindow::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;
124 mnTitle
= (nStyle
& (WB_MOVEABLE
| WB_POPUP
)) ? FloatWinTitleType::Normal
: FloatWinTitleType::NONE
;
125 mnOldTitle
= mnTitle
;
126 mnPopupModeFlags
= FloatWinPopupFlags::NONE
;
127 mbInPopupMode
= false;
129 mbPopupModeCanceled
= false;
130 mbPopupModeTearOff
= false;
136 void FloatingWindow::ImplInitSettings()
138 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
141 if (IsControlBackground())
142 aColor
= GetControlBackground();
143 else if (Window::GetStyle() & WB_3DLOOK
)
144 aColor
= rStyleSettings
.GetFaceColor();
146 aColor
= rStyleSettings
.GetWindowColor();
147 SetBackground(aColor
);
150 FloatingWindow::FloatingWindow(vcl::Window
* pParent
, WinBits nStyle
) :
151 SystemWindow(WindowType::FLOATINGWINDOW
)
153 ImplInit(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)
161 , mnPopupModeFlags(FloatWinPopupFlags::NONE
)
162 , mnTitle(FloatWinTitleType::Unknown
)
163 , mnOldTitle(FloatWinTitleType::Unknown
)
164 , mbInPopupMode(false)
166 , mbPopupModeCanceled(false)
167 , mbPopupModeTearOff(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 ImplInit(pParent
, nBits
);
181 mbIsDeferredInit
= false;
184 void FloatingWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
186 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
189 if (Window::GetStyle() & WB_3DLOOK
)
190 aColor
= rStyleSettings
.GetFaceColor();
192 aColor
= rStyleSettings
.GetWindowColor();
194 ApplyControlBackground(rRenderContext
, aColor
);
197 FloatingWindow::~FloatingWindow()
203 void FloatingWindow::dispose()
205 ReleaseLOKNotifier();
209 if( mbPopupModeCanceled
)
210 // indicates that ESC key was pressed
211 // will be handled in Window::ImplGrabFocus()
212 SetDialogControlFlags( GetDialogControlFlags() | DialogControlFlags::FloatWinPopupModeEndCancel
);
214 if ( IsInPopupMode() )
215 EndPopupMode( FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
| FloatWinPopupEndFlags::DontCallHdl
);
218 Application::RemoveUserEvent( mnPostId
);
225 mpFirstPopupModeWin
.clear();
226 mxPrevFocusWin
.clear();
227 SystemWindow::dispose();
230 Point
FloatingWindow::CalcFloatingPosition( vcl::Window
* pWindow
, const tools::Rectangle
& rRect
, FloatWinPopupFlags nFlags
, sal_uInt16
& rArrangeIndex
)
232 return ImplCalcPos( pWindow
, rRect
, nFlags
, rArrangeIndex
);
235 Point
FloatingWindow::ImplCalcPos(vcl::Window
* pWindow
,
236 const tools::Rectangle
& rRect
, FloatWinPopupFlags nFlags
,
237 sal_uInt16
& rArrangeIndex
, Point
* pLOKTwipsPos
)
239 // get window position
241 Size aSize
= ::isLayoutEnabled(pWindow
) ? pWindow
->get_preferred_size() : pWindow
->GetSizePixel();
242 tools::Rectangle aScreenRect
= pWindow
->ImplGetFrameWindow()->GetDesktopRectPixel();
243 FloatingWindow
*pFloatingWindow
= dynamic_cast<FloatingWindow
*>( pWindow
);
246 vcl::Window
* pW
= pWindow
;
247 if ( pW
->mpWindowImpl
->mpRealParent
)
248 pW
= pW
->mpWindowImpl
->mpRealParent
;
250 tools::Rectangle
normRect( rRect
); // rRect is already relative to top-level window
251 normRect
.SetPos( pW
->ScreenToOutputPixel( normRect
.TopLeft() ) );
253 bool bRTL
= AllSettings::GetLayoutRTL();
255 tools::Rectangle
devRect( pW
->OutputToAbsoluteScreenPixel( normRect
.TopLeft() ),
256 pW
->OutputToAbsoluteScreenPixel( normRect
.BottomRight() ) );
258 tools::Rectangle
devRectRTL( devRect
);
260 // create a rect that can be compared to desktop coordinates
261 devRectRTL
= pW
->ImplOutputToUnmirroredAbsoluteScreenPixel( normRect
);
262 if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
263 aScreenRect
= Application::GetScreenPosSizePixel(
264 Application::GetBestScreen( bRTL
? devRectRTL
: devRect
) );
266 FloatWinPopupFlags nArrangeAry
[5];
267 Point e1
,e2
; // the common edge between the item rect and the floating window
269 if ( nFlags
& FloatWinPopupFlags::Left
)
271 nArrangeAry
[0] = FloatWinPopupFlags::Left
;
272 nArrangeAry
[1] = FloatWinPopupFlags::Right
;
273 nArrangeAry
[2] = FloatWinPopupFlags::Up
;
274 nArrangeAry
[3] = FloatWinPopupFlags::Down
;
275 nArrangeAry
[4] = FloatWinPopupFlags::Left
;
277 else if ( nFlags
& FloatWinPopupFlags::Right
)
279 nArrangeAry
[0] = FloatWinPopupFlags::Right
;
280 nArrangeAry
[1] = FloatWinPopupFlags::Left
;
281 nArrangeAry
[2] = FloatWinPopupFlags::Up
;
282 nArrangeAry
[3] = FloatWinPopupFlags::Down
;
283 nArrangeAry
[4] = FloatWinPopupFlags::Right
;
285 else if ( nFlags
& FloatWinPopupFlags::Up
)
287 nArrangeAry
[0] = FloatWinPopupFlags::Up
;
288 nArrangeAry
[1] = FloatWinPopupFlags::Down
;
289 nArrangeAry
[2] = FloatWinPopupFlags::Right
;
290 nArrangeAry
[3] = FloatWinPopupFlags::Left
;
291 nArrangeAry
[4] = FloatWinPopupFlags::Up
;
295 nArrangeAry
[0] = FloatWinPopupFlags::Down
;
296 nArrangeAry
[1] = FloatWinPopupFlags::Up
;
297 nArrangeAry
[2] = FloatWinPopupFlags::Right
;
298 nArrangeAry
[3] = FloatWinPopupFlags::Left
;
299 nArrangeAry
[4] = FloatWinPopupFlags::Down
;
302 sal_uInt16 nArrangeIndex
= 0;
303 const bool bLOKActive
= comphelper::LibreOfficeKit::isActive();
305 for ( ; nArrangeIndex
< 5; nArrangeIndex
++ )
308 switch ( nArrangeAry
[nArrangeIndex
] )
311 case FloatWinPopupFlags::Left
:
312 aPos
.setX( devRect
.Left()-aSize
.Width()+1 );
313 aPos
.setY( devRect
.Top() );
314 aPos
.AdjustY( -(pWindow
->mpWindowImpl
->mnTopBorder
) );
317 if( (devRectRTL
.Right()+aSize
.Width()) > aScreenRect
.Right() )
322 if ( aPos
.X() < aScreenRect
.Left() )
325 if (bBreak
|| bLOKActive
)
327 e1
= devRect
.TopLeft();
328 e2
= devRect
.BottomLeft();
329 // set non-zero width
331 // don't clip corners
336 case FloatWinPopupFlags::Right
:
337 aPos
= devRect
.TopRight();
338 aPos
.AdjustY( -(pWindow
->mpWindowImpl
->mnTopBorder
) );
341 if( (devRectRTL
.Left() - aSize
.Width()) < aScreenRect
.Left() )
346 if ( aPos
.X()+aSize
.Width() > aScreenRect
.Right() )
349 if (bBreak
|| bLOKActive
)
351 e1
= devRect
.TopRight();
352 e2
= devRect
.BottomRight();
353 // set non-zero width
355 // don't clip corners
360 case FloatWinPopupFlags::Up
:
361 aPos
.setX( devRect
.Left() );
362 aPos
.setY( devRect
.Top()-aSize
.Height()+1 );
363 if ( aPos
.Y() < aScreenRect
.Top() )
365 if (bBreak
|| bLOKActive
)
367 e1
= devRect
.TopLeft();
368 e2
= devRect
.TopRight();
369 // set non-zero height
371 // don't clip corners
376 case FloatWinPopupFlags::Down
:
377 aPos
= devRect
.BottomLeft();
378 if ( aPos
.Y()+aSize
.Height() > aScreenRect
.Bottom() )
380 if (bBreak
|| bLOKActive
)
382 e1
= devRect
.BottomLeft();
383 e2
= devRect
.BottomRight();
384 // set non-zero height
386 // don't clip corners
394 // no further adjustement for LibreOfficeKit
398 // adjust if necessary
401 if ( (nArrangeAry
[nArrangeIndex
] == FloatWinPopupFlags::Left
) ||
402 (nArrangeAry
[nArrangeIndex
] == FloatWinPopupFlags::Right
) )
404 if ( aPos
.Y()+aSize
.Height() > aScreenRect
.Bottom() )
406 aPos
.setY( devRect
.Bottom()-aSize
.Height()+1 );
407 if ( aPos
.Y() < aScreenRect
.Top() )
408 aPos
.setY( aScreenRect
.Top() );
415 if( devRectRTL
.Right()-aSize
.Width()+1 < aScreenRect
.Left() )
416 aPos
.AdjustX( -(aScreenRect
.Left() - devRectRTL
.Right() + aSize
.Width() - 1) );
418 else if ( aPos
.X()+aSize
.Width() > aScreenRect
.Right() )
420 aPos
.setX( devRect
.Right()-aSize
.Width()+1 );
421 if ( aPos
.X() < aScreenRect
.Left() )
422 aPos
.setX( aScreenRect
.Left() );
430 if ( nArrangeIndex
> 4 )
433 rArrangeIndex
= nArrangeIndex
;
435 aPos
= pW
->AbsoluteScreenToOutputPixel( aPos
);
437 // store a cliprect that can be used to clip the common edge of the itemrect and the floating window
438 if( pFloatingWindow
&& pFloatingWindow
->mpImplData
->mpBox
)
440 pFloatingWindow
->mpImplData
->maItemEdgeClipRect
=
441 tools::Rectangle( e1
, e2
);
444 if (bLOKActive
&& pLOKTwipsPos
)
446 if (pW
->IsMapModeEnabled() || pW
->GetMapMode().GetMapUnit() == MapUnit::MapPixel
)
448 // if we use pW->LogicToLogic(aPos, pW->GetMapMode(), MapMode(MapUnit::MapTwip)),
449 // for pixel conversions when map mode is not enabled, we gets
450 // a 20 twips per pixel conversion since LogicToLogic uses
451 // a fixed 72 dpi value, instead of a correctly computed output
452 // device dpi or at least the most commonly used 96 dpi value;
453 // and anyway the following is what we already do in
454 // ScGridWindow::LogicInvalidate when map mode is not enabled.
456 *pLOKTwipsPos
= pW
->PixelToLogic(aPos
, MapMode(MapUnit::MapTwip
));
460 *pLOKTwipsPos
= OutputDevice::LogicToLogic(aPos
, pW
->GetMapMode(), MapMode(MapUnit::MapTwip
));
464 // caller expects coordinates relative to top-level win
465 return pW
->OutputToScreenPixel( aPos
);
468 Point
FloatingWindow::ImplConvertToAbsPos(vcl::Window
* pReference
, const Point
& rPos
)
470 Point
aAbsolute( rPos
);
472 const OutputDevice
*pWindowOutDev
= pReference
->GetOutDev();
474 // compare coordinates in absolute screen coordinates
475 if( pReference
->HasMirroredGraphics() )
477 if(!pReference
->IsRTLEnabled() )
478 pWindowOutDev
->ReMirror( aAbsolute
);
480 tools::Rectangle
aRect( pReference
->ScreenToOutputPixel(aAbsolute
), Size(1,1) ) ;
481 aRect
= pReference
->ImplOutputToUnmirroredAbsoluteScreenPixel( aRect
);
482 aAbsolute
= aRect
.TopLeft();
485 aAbsolute
= pReference
->OutputToAbsoluteScreenPixel(
486 pReference
->ScreenToOutputPixel(rPos
) );
491 tools::Rectangle
FloatingWindow::ImplConvertToAbsPos(vcl::Window
* pReference
, const tools::Rectangle
& rRect
)
493 tools::Rectangle aFloatRect
= rRect
;
495 const OutputDevice
*pParentWinOutDev
= pReference
->GetOutDev();
497 // compare coordinates in absolute screen coordinates
498 // Keep in sync with FloatingWindow::ImplFloatHitTest, e.g. fdo#33509
499 if( pReference
->HasMirroredGraphics() )
501 if(!pReference
->IsRTLEnabled() )
502 pParentWinOutDev
->ReMirror(aFloatRect
);
504 aFloatRect
.SetPos(pReference
->ScreenToOutputPixel(aFloatRect
.TopLeft()));
505 aFloatRect
= pReference
->ImplOutputToUnmirroredAbsoluteScreenPixel(aFloatRect
);
508 aFloatRect
.SetPos(pReference
->OutputToAbsoluteScreenPixel(pReference
->ScreenToOutputPixel(rRect
.TopLeft())));
512 FloatingWindow
* FloatingWindow::ImplFloatHitTest( vcl::Window
* pReference
, const Point
& rPos
, HitTest
& rHitTest
)
514 FloatingWindow
* pWin
= this;
516 Point
aAbsolute(FloatingWindow::ImplConvertToAbsPos(pReference
, rPos
));
520 // compute the floating window's size in absolute screen coordinates
522 // use the border window to have the exact position
523 vcl::Window
*pBorderWin
= pWin
->GetWindow( GetWindowType::Border
);
525 // the top-left corner in output coordinates ie (0,0)
526 tools::Rectangle
devRect( pBorderWin
->ImplOutputToUnmirroredAbsoluteScreenPixel( tools::Rectangle( Point(), pBorderWin
->GetSizePixel()) ) ) ;
527 if ( devRect
.IsInside( aAbsolute
) )
529 rHitTest
= HITTEST_WINDOW
;
533 // test, if mouse is in rectangle, (this is typically the rect of the active
534 // toolbox item or similar)
535 // note: maFloatRect is set in FloatingWindow::StartPopupMode() and
536 // is already in absolute device coordinates
537 if ( pWin
->maFloatRect
.IsInside( aAbsolute
) )
539 rHitTest
= HITTEST_RECT
;
543 pWin
= pWin
->mpNextFloat
;
547 rHitTest
= HITTEST_OUTSIDE
;
551 FloatingWindow
* FloatingWindow::ImplFindLastLevelFloat()
553 FloatingWindow
* pWin
= this;
554 FloatingWindow
* pLastFoundWin
= pWin
;
558 if ( pWin
->GetPopupModeFlags() & FloatWinPopupFlags::NewLevel
)
559 pLastFoundWin
= pWin
;
561 pWin
= pWin
->mpNextFloat
;
565 return pLastFoundWin
;
568 bool FloatingWindow::ImplIsFloatPopupModeWindow( const vcl::Window
* pWindow
)
570 FloatingWindow
* pWin
= this;
574 if ( pWin
->mpFirstPopupModeWin
== pWindow
)
577 pWin
= pWin
->mpNextFloat
;
584 IMPL_LINK_NOARG(FloatingWindow
, ImplEndPopupModeHdl
, void*, void)
586 VclPtr
<FloatingWindow
> pThis(this);
588 mnPopupModeFlags
= FloatWinPopupFlags::NONE
;
593 bool FloatingWindow::EventNotify( NotifyEvent
& rNEvt
)
595 // call Base Class first for tab control
596 bool bRet
= SystemWindow::EventNotify( rNEvt
);
599 if ( rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
601 const KeyEvent
* pKEvt
= rNEvt
.GetKeyEvent();
602 vcl::KeyCode aKeyCode
= pKEvt
->GetKeyCode();
603 sal_uInt16 nKeyCode
= aKeyCode
.GetCode();
605 if ( (nKeyCode
== KEY_ESCAPE
) && (GetStyle() & WB_CLOSEABLE
) )
616 void FloatingWindow::PixelInvalidate(const tools::Rectangle
* /*pRectangle*/)
618 if (VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier())
620 std::vector
<vcl::LOKPayloadItem
> aPayload
;
621 const tools::Rectangle
aRect(Point(0,0), Size(GetSizePixel().Width()+1, GetSizePixel().Height()+1));
622 aPayload
.push_back(std::make_pair(OString("rectangle"), aRect
.toString()));
623 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pParent
->GetLOKNotifier();
624 pNotifier
->notifyWindow(GetLOKWindowId(), "invalidate", aPayload
);
628 void FloatingWindow::StateChanged( StateChangedType nType
)
630 if (nType
== StateChangedType::InitShow
)
635 SystemWindow::StateChanged( nType
);
637 VclPtr
<vcl::Window
> pParent
= GetParentWithLOKNotifier();
640 if (nType
== StateChangedType::InitShow
)
642 std::vector
<vcl::LOKPayloadItem
> aItems
;
645 // we are a toplevel window, let's so far pretend to be a
646 // dialog - but maybe we'll need a separate type for this
648 aItems
.emplace_back("type", "dialog");
649 aItems
.emplace_back("position", mpImplData
->maLOKTwipsPos
.toString()); // twips
653 SetLOKNotifier(pParent
->GetLOKNotifier());
654 aItems
.emplace_back("type", "child");
655 aItems
.emplace_back("parentId", OString::number(pParent
->GetLOKWindowId()));
657 aItems
.emplace_back("position", mpImplData
->maPos
.toString()); // pixels
658 else // mpImplData->maPos is not set
659 aItems
.emplace_back("position", GetPosPixel().toString());
662 aItems
.emplace_back("size", GetSizePixel().toString());
663 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "created", aItems
);
665 else if (!IsVisible() && nType
== StateChangedType::Visible
)
667 assert(GetLOKNotifier());
668 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "close");
669 ReleaseLOKNotifier();
673 if ( nType
== StateChangedType::ControlBackground
)
680 void FloatingWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
682 SystemWindow::DataChanged( rDCEvt
);
684 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
685 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
) )
692 void FloatingWindow::ImplCallPopupModeEnd()
694 // PopupMode is finished
695 mbInPopupMode
= false;
697 // call Handler asynchronously.
698 if ( mpImplData
&& !mnPostId
)
699 mnPostId
= Application::PostUserEvent(LINK(this, FloatingWindow
, ImplEndPopupModeHdl
));
702 void FloatingWindow::PopupModeEnd()
704 maPopupModeEndHdl
.Call( this );
707 void FloatingWindow::SetTitleType( FloatWinTitleType nTitle
)
709 if ( (mnTitle
!= nTitle
) && mpWindowImpl
->mpBorderWindow
)
712 Size aOutSize
= GetOutputSizePixel();
713 BorderWindowTitleType nTitleStyle
;
714 if ( nTitle
== FloatWinTitleType::Normal
)
715 nTitleStyle
= BorderWindowTitleType::Small
;
716 else if ( nTitle
== FloatWinTitleType::TearOff
)
717 nTitleStyle
= BorderWindowTitleType::Tearoff
;
718 else if ( nTitle
== FloatWinTitleType::Popup
)
719 nTitleStyle
= BorderWindowTitleType::Popup
;
720 else // nTitle == FloatWinTitleType::NONE
721 nTitleStyle
= BorderWindowTitleType::NONE
;
722 static_cast<ImplBorderWindow
*>(mpWindowImpl
->mpBorderWindow
.get())->SetTitleType( nTitleStyle
, aOutSize
);
723 static_cast<ImplBorderWindow
*>(mpWindowImpl
->mpBorderWindow
.get())->GetBorder( mpWindowImpl
->mnLeftBorder
, mpWindowImpl
->mnTopBorder
, mpWindowImpl
->mnRightBorder
, mpWindowImpl
->mnBottomBorder
);
727 void FloatingWindow::StartPopupMode( const tools::Rectangle
& rRect
, FloatWinPopupFlags nFlags
)
733 mnOldTitle
= mnTitle
;
734 if ( ( mpWindowImpl
->mnStyle
& WB_POPUP
) && !GetText().isEmpty() )
735 SetTitleType( FloatWinTitleType::Popup
);
736 else if ( nFlags
& FloatWinPopupFlags::AllowTearOff
)
737 SetTitleType( FloatWinTitleType::TearOff
);
739 SetTitleType( FloatWinTitleType::NONE
);
741 // avoid close on focus change for decorated floating windows only
742 if( mpWindowImpl
->mbFrame
&& (GetStyle() & WB_MOVEABLE
) )
743 nFlags
|= FloatWinPopupFlags::NoAppFocusClose
;
745 // compute window position according to flags and arrangement
746 sal_uInt16 nArrangeIndex
;
748 mpImplData
->maPos
= ImplCalcPos(this, rRect
, nFlags
, nArrangeIndex
, &mpImplData
->maLOKTwipsPos
);
749 SetPosPixel( mpImplData
->maPos
);
750 ImplGetFrame()->PositionByToolkit(rRect
, nFlags
);
752 // set data and display window
753 // convert maFloatRect to absolute device coordinates
754 // so they can be compared across different frames
755 // !!! rRect is expected to be in screen coordinates of the parent frame window !!!
756 maFloatRect
= FloatingWindow::ImplConvertToAbsPos(GetParent(), rRect
);
758 maFloatRect
.AdjustLeft( -2 );
759 maFloatRect
.AdjustTop( -2 );
760 maFloatRect
.AdjustRight(2 );
761 maFloatRect
.AdjustBottom(2 );
762 mnPopupModeFlags
= nFlags
;
763 mbInPopupMode
= true;
765 mbPopupModeCanceled
= false;
766 mbPopupModeTearOff
= false;
769 // add FloatingWindow to list of windows that are in popup mode
770 ImplSVData
* pSVData
= ImplGetSVData();
771 mpNextFloat
= pSVData
->mpWinData
->mpFirstFloat
;
772 pSVData
->mpWinData
->mpFirstFloat
= this;
773 if (nFlags
& FloatWinPopupFlags::GrabFocus
)
775 // force key input even without focus (useful for menus)
777 mxPrevFocusWin
= Window::SaveFocus();
778 mpWindowImpl
->mpFrameData
->mbHasFocus
= true;
781 Show( true, ShowFlags::NoActivate
);
784 void FloatingWindow::StartPopupMode( ToolBox
* pBox
, FloatWinPopupFlags nFlags
)
786 mpImplData
->mpBox
= pBox
;
788 // get selected button
789 sal_uInt16 nItemId
= pBox
->GetDownItemId();
792 pBox
->ImplFloatControl( true, this );
794 // retrieve some data from the ToolBox
795 tools::Rectangle aRect
= nItemId
? pBox
->GetItemRect( nItemId
) : pBox
->GetOverflowRect();
797 // convert to parent's screen coordinates
798 mpImplData
->maPos
= GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox
->OutputToAbsoluteScreenPixel( aRect
.TopLeft() ) ) );
799 aRect
.SetPos( mpImplData
->maPos
);
802 FloatWinPopupFlags::AllMouseButtonClose
|
803 FloatWinPopupFlags::NoMouseUpClose
;
805 // set Flags for positioning
806 if ( !(nFlags
& (FloatWinPopupFlags::Down
| FloatWinPopupFlags::Up
|
807 FloatWinPopupFlags::Left
| FloatWinPopupFlags::Right
)) )
809 if ( pBox
->IsHorizontal() )
810 nFlags
|= FloatWinPopupFlags::Down
;
812 nFlags
|= FloatWinPopupFlags::Right
;
815 // start FloatingMode
816 StartPopupMode( aRect
, nFlags
);
819 void FloatingWindow::ImplEndPopupMode( FloatWinPopupEndFlags nFlags
, const VclPtr
<vcl::Window
>& xFocusId
)
821 if ( !mbInPopupMode
)
824 ImplSVData
* pSVData
= ImplGetSVData();
826 mbInCleanUp
= true; // prevent killing this window due to focus change while working with it
828 if (!(nFlags
& FloatWinPopupEndFlags::NoCloseChildren
))
830 // stop the PopupMode also for all PopupMode windows created after us
831 std::vector
<VclPtr
<FloatingWindow
>> aCancelFloats
;
832 // stop the PopupMode also for all following PopupMode windows
833 for (auto pFloat
= pSVData
->mpWinData
->mpFirstFloat
;
834 pFloat
!= nullptr && pFloat
!= this;
835 pFloat
= pFloat
->mpNextFloat
)
836 aCancelFloats
.push_back(pFloat
);
837 for (auto it
: aCancelFloats
)
838 it
->EndPopupMode(FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::NoCloseChildren
);
841 // delete window from the list
842 pSVData
->mpWinData
->mpFirstFloat
= mpNextFloat
;
843 mpNextFloat
= nullptr;
845 FloatWinPopupFlags nPopupModeFlags
= mnPopupModeFlags
;
846 mbPopupModeTearOff
= nFlags
& FloatWinPopupEndFlags::TearOff
&&
847 nPopupModeFlags
& FloatWinPopupFlags::AllowTearOff
;
849 // hide window again if it was not deleted
850 if (!mbPopupModeTearOff
)
851 Show( false, ShowFlags::NoFocusChange
);
853 if (HasChildPathFocus() && xFocusId
!= nullptr)
855 // restore focus to previous focus window if we still have the focus
856 Window::EndSaveFocus(xFocusId
);
858 else if ( pSVData
->mpWinData
->mpFocusWin
&& pSVData
->mpWinData
->mpFirstFloat
&&
859 ImplIsWindowOrChild( pSVData
->mpWinData
->mpFocusWin
) )
861 // maybe pass focus on to a suitable FloatingWindow
862 pSVData
->mpWinData
->mpFirstFloat
->GrabFocus();
865 mbPopupModeCanceled
= bool(nFlags
& FloatWinPopupEndFlags::Cancel
);
868 SetTitleType( mnOldTitle
);
870 // set ToolBox again to normal
871 if (mpImplData
&& mpImplData
->mpBox
)
873 mpImplData
->mpBox
->ImplFloatControl( false, this );
874 // if the parent ToolBox is in popup mode, it should be closed too.
875 if ( GetDockingManager()->IsInPopupMode( mpImplData
->mpBox
) )
876 nFlags
|= FloatWinPopupEndFlags::CloseAll
;
878 mpImplData
->mpBox
= nullptr;
881 // call PopupModeEnd-Handler depending on parameter
882 if ( !(nFlags
& FloatWinPopupEndFlags::DontCallHdl
) )
883 ImplCallPopupModeEnd();
885 // close all other windows depending on parameter
886 if ( nFlags
& FloatWinPopupEndFlags::CloseAll
)
888 if ( !(nPopupModeFlags
& FloatWinPopupFlags::NewLevel
) )
890 if (pSVData
->mpWinData
->mpFirstFloat
)
892 FloatingWindow
* pLastLevelFloat
= pSVData
->mpWinData
->mpFirstFloat
->ImplFindLastLevelFloat();
893 pLastLevelFloat
->EndPopupMode( FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
901 void FloatingWindow::EndPopupMode( FloatWinPopupEndFlags nFlags
)
903 ImplEndPopupMode(nFlags
, mxPrevFocusWin
);
906 void FloatingWindow::AddPopupModeWindow( vcl::Window
* pWindow
)
908 // !!! up-to-now only 1 window and not yet a list
909 mpFirstPopupModeWin
= pWindow
;
912 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */