LibreOffice Module vcl (master) 1
bubblewindow.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <rtl/ustrbuf.hxx>
21#include <utility>
23#include <vcl/lineinfo.hxx>
24#include <vcl/settings.hxx>
25#include <vcl/svapp.hxx>
26#include <unotools/resmgr.hxx>
27#include <bubblewindow.hxx>
28#include <bitmaps.hlst>
29
30#define TIP_HEIGHT 15
31#define TIP_WIDTH 7
32#define TIP_RIGHT_OFFSET 18
33#define BUBBLE_BORDER 10
34#define TEXT_MAX_WIDTH 300
35#define TEXT_MAX_HEIGHT 200
36
37BubbleWindow::BubbleWindow( vcl::Window* pParent, OUString aTitle,
38 OUString aText, Image aImage )
42 )
43 , maBubbleTitle(std::move( aTitle ))
44 , maBubbleText(std::move( aText ))
45 , maBubbleImage(std::move( aImage ))
46 , maMaxTextSize( TEXT_MAX_WIDTH, TEXT_MAX_HEIGHT )
47 , mnTipOffset( 0 )
48{
49 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetHelpColor() ) );
50}
51
53{
55
56 Size aSize = GetSizePixel();
57
58 if ( ( aSize.Height() < 20 ) || ( aSize.Width() < 60 ) )
59 return;
60
61 tools::Rectangle aRect( 0, TIP_HEIGHT, aSize.Width(), aSize.Height() - TIP_HEIGHT );
62 maRectPoly = tools::Polygon( aRect, 6, 6 );
63 vcl::Region aRegion( maRectPoly );
64 tools::Long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;
65
66 Point aPointArr[4];
67 aPointArr[0] = Point( nTipOffset, TIP_HEIGHT );
68 aPointArr[1] = Point( nTipOffset, 0 );
69 aPointArr[2] = Point( nTipOffset + TIP_WIDTH , TIP_HEIGHT );
70 aPointArr[3] = Point( nTipOffset, TIP_HEIGHT );
71 maTriPoly = tools::Polygon( 4, aPointArr );
72 vcl::Region aTriRegion( maTriPoly );
73
74 aRegion.Union( aTriRegion);
75 maBounds = aRegion;
76
78}
79
80void BubbleWindow::SetTitleAndText( const OUString& rTitle,
81 const OUString& rText,
82 const Image& rImage )
83{
84 maBubbleTitle = rTitle;
85 maBubbleText = rText;
86 maBubbleImage = rImage;
87
88 Resize();
89}
90
91void BubbleWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
92{
93 LineInfo aThickLine( LineStyle::Solid, 2 );
94
95 rRenderContext.DrawPolyLine( maRectPoly, aThickLine );
96 rRenderContext.DrawPolyLine( maTriPoly );
97
98 Color aOldLine = rRenderContext.GetLineColor();
99 Size aSize = GetSizePixel();
100 tools::Long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;
101
102 rRenderContext.SetLineColor( GetSettings().GetStyleSettings().GetHelpColor() );
103 rRenderContext.DrawLine( Point( nTipOffset+2, TIP_HEIGHT ),
104 Point( nTipOffset + TIP_WIDTH -1 , TIP_HEIGHT ),
105 aThickLine );
106 rRenderContext.SetLineColor( aOldLine );
107
108 Size aImgSize = maBubbleImage.GetSizePixel();
109
111
112 vcl::Font aOldFont = GetFont();
113 vcl::Font aBoldFont = aOldFont;
114 aBoldFont.SetWeight( WEIGHT_BOLD );
115
116 SetFont( aBoldFont );
117 tools::Rectangle aTitleRect = maTitleRect;
118 aTitleRect.Move( aImgSize.Width(), 0 );
120
121 SetFont( aOldFont );
122 tools::Rectangle aTextRect = maTextRect;
123 aTextRect.Move( aImgSize.Width(), 0 );
125}
126
128{
129 Show( false );
130}
131
132void BubbleWindow::Show( bool bVisible )
133{
134 if ( !bVisible )
135 {
137 return;
138 }
139
140 // don't show bubbles without a text
141 if ( ( maBubbleTitle.isEmpty() ) && ( maBubbleText.isEmpty() ) )
142 return;
143
144 Size aWindowSize = GetSizePixel();
145
146 Size aImgSize = maBubbleImage.GetSizePixel();
147
149
150 aWindowSize.setHeight( maTitleRect.GetHeight() * 7 / 4+ maTextRect.GetHeight() +
152
154 aWindowSize.setWidth( maTitleRect.GetWidth() );
155 else
156 aWindowSize.setWidth( maTextRect.GetWidth() );
157
158 aWindowSize.setWidth( aWindowSize.Width() + 3 * BUBBLE_BORDER + aImgSize.Width() );
159
160 if ( aWindowSize.Height() < aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER )
161 aWindowSize.setHeight( aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER );
162
163 Point aPos;
164 aPos.setX( maTipPos.X() - aWindowSize.Width() + TIP_RIGHT_OFFSET );
165 aPos.setY( maTipPos.Y() );
166 Point aScreenPos = GetParent()->OutputToAbsoluteScreenPixel( aPos );
167 if ( aScreenPos.X() < 0 )
168 {
169 mnTipOffset = aScreenPos.X();
170 aPos.AdjustX( -mnTipOffset );
171 }
172 SetPosSizePixel( aPos, aWindowSize );
173
175}
176
178{
179 Size aTotalSize;
180 bool bFinished = false;
181 vcl::Font aOldFont = GetFont();
182 vcl::Font aBoldFont = aOldFont;
183
184 aBoldFont.SetWeight( WEIGHT_BOLD );
185
186 while ( !bFinished )
187 {
188 SetFont( aBoldFont );
189
193
194 SetFont( aOldFont );
198
199 if ( maTextRect.GetHeight() < 10 )
200 maTextRect.setHeight( 10 );
201
202 aTotalSize.setHeight( maTitleRect.GetHeight() +
203 aBoldFont.GetFontHeight() * 3 / 4 +
206 if ( aTotalSize.Height() > maMaxTextSize.Height() )
207 {
210 }
211 else
212 bFinished = true;
213 }
216}
217
219 : maTimeoutTimer("MenuBarUpdateIconManager")
220 , maWaitIdle("vcl MenuBarUpdateIconManager maWaitIdle")
221 , mnIconID (0)
222 , mbShowMenuIcon(false)
223 , mbShowBubble(false)
224 , mbBubbleChanged( false )
225{
226 maTimeoutTimer.SetTimeout( 10000 );
228
231
232 maApplicationEventHdl = LINK(this, MenuBarUpdateIconManager, ApplicationEventHdl);
234
235 maWindowEventHdl = LINK(this, MenuBarUpdateIconManager, WindowEventHdl);
236}
237
239{
240 if ( !mpIconSysWin )
241 return nullptr;
242
244 if( aIconRect.IsEmpty() )
245 return nullptr;
246
247 auto pBubbleWin = mpBubbleWin;
248
249 if ( !pBubbleWin ) {
252 mbBubbleChanged = false;
253 }
254 else if ( mbBubbleChanged ) {
255 pBubbleWin->SetTitleAndText( maBubbleTitle, maBubbleText,
257 mbBubbleChanged = false;
258 }
259
260 Point aWinPos = aIconRect.BottomCenter();
261
262 pBubbleWin->SetTipPosPixel( aWinPos );
263
264 return pBubbleWin;
265}
266
268{
269 RemoveBubbleWindow( false );
270}
271
272IMPL_LINK(MenuBarUpdateIconManager, WindowEventHdl, VclWindowEvent&, rEvent, void)
273{
274 VclEventId nEventID = rEvent.GetId();
275
276 if ( VclEventId::ObjectDying == nEventID )
277 {
278 if ( mpIconSysWin == rEvent.GetWindow() )
279 {
280 mpIconSysWin->RemoveEventListener( maWindowEventHdl );
281 RemoveBubbleWindow( true );
282 }
283 }
284 else if ( VclEventId::WindowMenubarAdded == nEventID )
285 {
286 vcl::Window *pWindow = rEvent.GetWindow();
287 if ( pWindow )
288 {
289 SystemWindow *pSysWin = pWindow->GetSystemWindow();
290 if ( pSysWin )
291 {
292 AddMenuBarIcon( pSysWin, false );
293 }
294 }
295 }
296 else if ( VclEventId::WindowMenubarRemoved == nEventID )
297 {
298 MenuBar *pMBar = static_cast<MenuBar*>(rEvent.GetData());
299 if ( pMBar && ( pMBar == mpIconMBar ) )
300 RemoveBubbleWindow( true );
301 }
302 else if ( ( nEventID == VclEventId::WindowMove ) ||
303 ( nEventID == VclEventId::WindowResize ) )
304 {
305 if ( ( mpIconSysWin == rEvent.GetWindow() ) &&
306 mpBubbleWin && ( mpIconMBar != nullptr ) )
307 {
308 tools::Rectangle aIconRect = mpIconMBar->GetMenuBarButtonRectPixel( mnIconID );
309 Point aWinPos = aIconRect.BottomCenter();
310 mpBubbleWin->SetTipPosPixel( aWinPos );
311 if ( mpBubbleWin->IsVisible() )
312 mpBubbleWin->Show(); // This will recalc the screen position of the bubble
313 }
314 }
315}
316
317IMPL_LINK(MenuBarUpdateIconManager, ApplicationEventHdl, VclSimpleEvent&, rEvent, void)
318{
319 switch (rEvent.GetId())
320 {
324
325 vcl::Window *pWindow = static_cast< VclWindowEvent * >(&rEvent)->GetWindow();
326 if ( pWindow && pWindow->IsTopWindow() )
327 {
328 SystemWindow *pSysWin = pWindow->GetSystemWindow();
329 MenuBar *pMBar = pSysWin ? pSysWin->GetMenuBar() : nullptr;
330 if (pMBar)
331 {
332 AddMenuBarIcon( pSysWin, true );
333 }
334 }
335 break;
336 }
337 default: break;
338 }
339}
340
341IMPL_LINK_NOARG(MenuBarUpdateIconManager, UserEventHdl, void*, void)
342{
345 SystemWindow *pActiveSysWin = nullptr;
346
347 vcl::Window *pBubbleWin = nullptr;
348 if ( mpBubbleWin )
349 pBubbleWin = mpBubbleWin;
350
351 if ( pActiveWin && ( pActiveWin != pBubbleWin ) && pActiveWin->IsTopWindow() )
352 pActiveSysWin = pActiveWin->GetSystemWindow();
353
354 if ( pActiveWin == pBubbleWin )
355 pActiveSysWin = nullptr;
356
357 while ( !pActiveSysWin && pTopWin )
358 {
359 if ( ( pTopWin != pBubbleWin ) && pTopWin->IsTopWindow() )
360 pActiveSysWin = pTopWin->GetSystemWindow();
361 if ( !pActiveSysWin )
362 pTopWin = Application::GetNextTopLevelWindow( pTopWin );
363 }
364
365 if ( pActiveSysWin )
366 AddMenuBarIcon( pActiveSysWin, true );
367}
368
370{
371 maWaitIdle.Stop();
372 if ( mpBubbleWin )
373 mpBubbleWin->Show( false );
374
375 maClickHdl.Call(nullptr);
376
377 return false;
378}
379
381{
382 if ( rData.bHighlight )
383 maWaitIdle.Start();
384 else
385 RemoveBubbleWindow(false);
386
387 return false;
388}
389
391{
392 mpBubbleWin = GetBubbleWindow();
393
394 if ( mpBubbleWin )
395 {
396 mpBubbleWin->Show();
397 }
398}
399
401{
403
404 RemoveBubbleWindow(true);
405}
406
408{
409 if ( bShowMenuIcon != mbShowMenuIcon )
410 {
411 mbShowMenuIcon = bShowMenuIcon;
412 if ( bShowMenuIcon )
414 else
415 RemoveBubbleWindow( true );
416 }
417}
418
420{
421 mbShowBubble = bShowBubble;
422 if ( mbShowBubble )
424 else if ( mpBubbleWin )
425 mpBubbleWin->Show( false );
426}
427
429{
430 mbBubbleChanged = true;
432 mpBubbleWin->Show( false );
433}
434
436{
437 maBubbleImage = rImage;
439}
440
442{
443 if (rTitle != maBubbleTitle)
444 {
445 maBubbleTitle = rTitle;
447 }
448}
449
451{
452 if (rText != maBubbleText)
453 {
454 maBubbleText = rText;
456 }
457}
458
459namespace {
460Image GetMenuBarIcon( MenuBar const * pMBar )
461{
462 OUString sResID;
463 vcl::Window *pMBarWin = pMBar->GetWindow();
464 sal_uInt32 nMBarHeight = 20;
465
466 if ( pMBarWin )
467 nMBarHeight = pMBarWin->GetOutputSizePixel().getHeight();
468
469 if (nMBarHeight >= 35)
470 sResID = RID_UPDATE_AVAILABLE_26;
471 else
472 sResID = RID_UPDATE_AVAILABLE_16;
473
474 return Image(StockImage::Yes, sResID);
475}
476}
477
479{
480 if ( ! mbShowMenuIcon )
481 return;
482
483 MenuBar *pActiveMBar = pSysWin->GetMenuBar();
484 if ( ( pSysWin != mpIconSysWin ) || ( pActiveMBar != mpIconMBar ) )
485 {
486 if ( bAddEventHdl && mpIconSysWin )
488
489 RemoveBubbleWindow( true );
490
491 if ( pActiveMBar )
492 {
493 OUStringBuffer aBuf;
494 if( !maBubbleTitle.isEmpty() )
495 aBuf.append( maBubbleTitle );
496 if( !maBubbleText.isEmpty() )
497 {
498 if( !maBubbleTitle.isEmpty() )
499 aBuf.append( "\n\n" );
500 aBuf.append( maBubbleText );
501 }
502
503 Image aImage = GetMenuBarIcon( pActiveMBar );
504 mnIconID = pActiveMBar->AddMenuBarButton( aImage,
505 LINK( this, MenuBarUpdateIconManager, ClickHdl ),
506 aBuf.makeStringAndClear()
507 );
509 LINK( this, MenuBarUpdateIconManager, HighlightHdl ) );
510 }
511 mpIconMBar = pActiveMBar;
512 mpIconSysWin = pSysWin;
513 if ( bAddEventHdl && mpIconSysWin )
515 }
516
517 if ( mbShowBubble && pActiveMBar )
518 {
520 if ( mpBubbleWin )
521 {
522 mpBubbleWin->Show();
524 }
525 mbShowBubble = false;
526 }
527}
528
530{
533
534 if ( mpBubbleWin )
535 {
537 }
538
539 if ( !bRemoveIcon )
540 return;
541
542 try {
543 if ( mpIconMBar && ( mnIconID != 0 ) )
544 {
546 mpIconMBar = nullptr;
547 mnIconID = 0;
548 }
549 }
550 catch ( ... ) {
551 mpIconMBar = nullptr;
552 mnIconID = 0;
553 }
554
555 mpIconSysWin = nullptr;
556}
557
558/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define TIP_RIGHT_OFFSET
#define TIP_HEIGHT
IMPL_LINK_NOARG(MenuBarUpdateIconManager, TimeOutHdl, Timer *, void)
#define BUBBLE_BORDER
#define TIP_WIDTH
IMPL_LINK(MenuBarUpdateIconManager, WindowEventHdl, VclWindowEvent &, rEvent, void)
#define TEXT_MAX_WIDTH
#define TEXT_MAX_HEIGHT
static void AddEventListener(const Link< VclSimpleEvent &, void > &rEventListener)
Add a VCL event listener to the application.
Definition: svapp.cxx:821
static vcl::Window * GetNextTopLevelWindow(vcl::Window const *pWindow)
Get the next top level window.
Definition: svapp.cxx:1177
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
Post a user event to the default window.
Definition: svapp.cxx:1122
static void RemoveEventListener(const Link< VclSimpleEvent &, void > &rEventListener)
Remove a VCL event listener from the application.
Definition: svapp.cxx:827
static vcl::Window * GetActiveTopWindow()
Get the "active" top window.
Definition: svapp.cxx:1215
static vcl::Window * GetFirstTopLevelWindow()
Get the first top-level window of the application.
Definition: svapp.cxx:1171
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
void Show(bool bVisible=true)
vcl::Region maBounds
OUString maBubbleTitle
BubbleWindow(vcl::Window *pParent, OUString aTitle, OUString aText, Image aImage)
tools::Long mnTipOffset
void RecalcTextRects()
tools::Rectangle maTextRect
tools::Polygon maTriPoly
void Resize() override
void SetTitleAndText(const OUString &rTitle, const OUString &rText, const Image &rImage)
tools::Rectangle maTitleRect
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
OUString maBubbleText
tools::Polygon maRectPoly
Image maBubbleImage
Definition: image.hxx:40
Size GetSizePixel() const
Definition: Image.cxx:86
Link< VclSimpleEvent &, void > maApplicationEventHdl
void SetShowBubble(bool bShowBubble)
VclPtr< MenuBar > mpIconMBar
Link< VclWindowEvent &, void > maWindowEventHdl
void RemoveBubbleWindow(bool bRemoveIcon)
void SetBubbleImage(const Image &rImage)
void SetBubbleText(const OUString &rText)
void AddMenuBarIcon(SystemWindow *pSysWin, bool bAddEventHdl)
VclPtr< SystemWindow > mpIconSysWin
void SetBubbleTitle(const OUString &rTitle)
void SetShowMenuIcon(bool bShowMenuIcon)
VclPtr< BubbleWindow > GetBubbleWindow()
VclPtr< BubbleWindow > mpBubbleWin
sal_uInt16 AddMenuBarButton(const Image &, const Link< MenuBarButtonCallbackArg &, bool > &, const OUString &)
Definition: menu.cxx:2607
tools::Rectangle GetMenuBarButtonRectPixel(sal_uInt16 nId)
Definition: menu.cxx:2629
void SetMenuBarButtonHighlightHdl(sal_uInt16 nId, const Link< MenuBarButtonCallbackArg &, bool > &)
Definition: menu.cxx:2613
void RemoveMenuBarButton(sal_uInt16 nId)
Definition: menu.cxx:2621
vcl::Window * GetWindow() const
Definition: menu.hxx:372
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:171
void DrawPolyLine(const tools::Polygon &rPoly)
Render the given polygon as a line stroke.
Definition: polyline.cxx:33
void DrawLine(const Point &rStartPt, const Point &rEndPt)
Definition: line.cxx:161
void SetLineColor()
Definition: line.cxx:37
void DrawImage(const Point &rPos, const Image &rImage, DrawImageFlags nStyle=DrawImageFlags::NONE)
This is an overloaded member function, provided for convenience. It differs from the above function o...
const Color & GetLineColor() const
Definition: outdev.hxx:511
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
Definition: text.cxx:797
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
MenuBar * GetMenuBar() const
Definition: syswin.hxx:183
virtual void Resize() override
Definition: syswin.cxx:999
void SetPriority(TaskPriority ePriority)
Definition: scheduler.cxx:597
void Stop()
Definition: scheduler.cxx:590
Definition: timer.hxx:27
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
void disposeAndClear()
Definition: vclptr.hxx:200
static VclPtr< reference_type > Create(Arg &&... arg)
A construction helper for VclPtr.
Definition: vclptr.hxx:127
constexpr tools::Long GetWidth() const
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
constexpr Point BottomCenter() const
constexpr tools::Long GetHeight() const
void setHeight(tools::Long n)
constexpr bool IsEmpty() const
tools::Long GetFontHeight() const
Definition: font/font.cxx:933
void SetWeight(FontWeight)
Definition: font/font.cxx:266
void Union(const tools::Rectangle &rRegion)
Definition: region.cxx:507
tools::Rectangle GetTextRect(const tools::Rectangle &rRect, const OUString &rStr, DrawTextFlags nStyle=DrawTextFlags::WordBreak, TextRectInfo *pInfo=nullptr, const vcl::ITextLayout *_pTextLayout=nullptr) const
Definition: window3.cxx:201
void SetFont(const vcl::Font &rNewFont)
Definition: window3.cxx:59
vcl::Window * GetParent() const
Definition: window2.cxx:1121
void RemoveEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:308
vcl::Window * GetWindow(GetWindowType nType) const
Definition: stacking.cxx:1035
const AllSettings & GetSettings() const
Definition: window3.cxx:129
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
Definition: window.cxx:2189
const vcl::Font & GetFont() const
Definition: window3.cxx:58
SystemWindow * GetSystemWindow() const
Definition: stacking.cxx:806
void AddEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:303
virtual Size GetSizePixel() const
Definition: window.cxx:2404
Size GetOutputSizePixel() const
Definition: window3.cxx:89
void SetWindowRegionPixel()
Definition: paint.cxx:1037
bool IsTopWindow() const
Definition: stacking.cxx:608
Point OutputToAbsoluteScreenPixel(const Point &rPos) const
Definition: window.cxx:2857
virtual void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize)
Definition: window2.cxx:1292
void SetBackground()
Definition: window3.cxx:100
WEIGHT_BOLD
aBuf
long Long
@ LOWEST
Low, very idle cleanup tasks.
bool bVisible
VclEventId
Definition: vclevent.hxx:38
@ WindowMenubarAdded
@ WindowMenubarRemoved
WinBits const WB_OWNERDRAWDECORATION
Definition: wintypes.hxx:173
WinBits const WB_SYSTEMWINDOW
Definition: wintypes.hxx:126
WinBits const WB_NOBORDER
Definition: wintypes.hxx:116