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 .
20 #include <tools/debug.hxx>
23 #include <vcl/event.hxx>
24 #include <vcl/decoview.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/help.hxx>
27 #include <vcl/status.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/settings.hxx>
30 #include <config_features.h>
31 #if HAVE_FEATURE_OPENGL
32 #include <vcl/opengl/OpenGLWrapper.hxx>
37 #define STATUSBAR_OFFSET_X STATUSBAR_OFFSET
38 #define STATUSBAR_OFFSET_Y 2
39 #define STATUSBAR_OFFSET_TEXTY 3
41 #define STATUSBAR_PRGS_OFFSET 3
42 #define STATUSBAR_PRGS_COUNT 100
43 #define STATUSBAR_PRGS_MIN 5
45 class StatusBar::ImplData
50 VclPtr
<VirtualDevice
> mpVirDev
;
51 long mnItemBorderWidth
;
52 bool mbDrawItemFrames
:1;
55 StatusBar::ImplData::ImplData()
58 mbDrawItemFrames
= false;
59 mnItemBorderWidth
= 0;
65 StatusBarItemBits mnBits
;
72 OUString maQuickHelpText
;
76 OUString maAccessibleName
;
80 inline long ImplCalcProgessWidth( sal_uInt16 nMax
, long nSize
)
82 return ((nMax
*(nSize
+(nSize
/2)))-(nSize
/2)+(STATUSBAR_PRGS_OFFSET
*2));
85 static Point
ImplGetItemTextPos( const Size
& rRectSize
, const Size
& rTextSize
,
86 StatusBarItemBits nStyle
)
90 long delta
= (rTextSize
.Height()/4) + 1;
91 if( delta
+ rTextSize
.Width() > rRectSize
.Width() )
94 if ( nStyle
& StatusBarItemBits::Left
)
96 else if ( nStyle
& StatusBarItemBits::Right
)
97 nX
= rRectSize
.Width()-rTextSize
.Width()-delta
;
98 else // StatusBarItemBits::Center
99 nX
= (rRectSize
.Width()-rTextSize
.Width())/2;
100 nY
= (rRectSize
.Height()-rTextSize
.Height())/2 + 1;
101 return Point( nX
, nY
);
104 bool StatusBar::ImplIsItemUpdate()
106 if ( !mbProgressMode
&& mbVisibleItems
&& IsReallyVisible() && IsUpdateMode() )
112 void StatusBar::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
114 mpImplData
= new ImplData
;
116 // default: RightAlign
117 if ( !(nStyle
& (WB_LEFT
| WB_RIGHT
)) )
120 Window::ImplInit( pParent
, nStyle
& ~WB_BORDER
, nullptr );
123 mpImplData
->mpVirDev
= VclPtr
<VirtualDevice
>::Create( *this );
126 mbVisibleItems
= true;
127 mbProgressMode
= false;
128 mbInUserDraw
= false;
129 mbAdjustHiDPI
= false;
130 mnItemsWidth
= STATUSBAR_OFFSET_X
;
134 mnItemY
= STATUSBAR_OFFSET_Y
;
135 mnTextY
= STATUSBAR_OFFSET_TEXTY
;
139 SetOutputSizePixel( CalcWindowSizePixel() );
142 StatusBar::StatusBar( vcl::Window
* pParent
, WinBits nStyle
) :
143 Window( WINDOW_STATUSBAR
)
145 ImplInit( pParent
, nStyle
);
148 StatusBar::~StatusBar()
153 void StatusBar::dispose()
156 for (ImplStatusItem
* i
: mpItemList
) {
161 // delete VirtualDevice
162 mpImplData
->mpVirDev
.disposeAndClear();
167 void StatusBar::AdjustItemWidthsForHiDPI()
169 mbAdjustHiDPI
= true;
172 void StatusBar::ApplySettings(vcl::RenderContext
& rRenderContext
)
174 rRenderContext
.SetLineColor();
176 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
177 vcl::Font aFont
= rStyleSettings
.GetToolFont();
179 aFont
.Merge(GetControlFont());
180 SetZoomedPointFont(rRenderContext
, aFont
);
183 if (IsControlForeground())
184 aColor
= GetControlForeground();
185 else if (GetStyle() & WB_3DLOOK
)
186 aColor
= rStyleSettings
.GetButtonTextColor();
188 aColor
= rStyleSettings
.GetWindowTextColor();
190 rRenderContext
.SetTextColor(aColor
);
191 rRenderContext
.SetTextFillColor();
193 if (IsControlBackground())
194 aColor
= GetControlBackground();
195 else if (GetStyle() & WB_3DLOOK
)
196 aColor
= rStyleSettings
.GetFaceColor();
198 aColor
= rStyleSettings
.GetWindowColor();
199 rRenderContext
.SetBackground(aColor
);
202 if (!IsControlBackground() &&
203 rRenderContext
.IsNativeControlSupported(ControlType::WindowBackground
, ControlPart::BackgroundWindow
))
205 ImplGetWindowImpl()->mnNativeBackground
= ControlPart::BackgroundWindow
;
206 EnableChildTransparentMode();
210 void StatusBar::ImplInitSettings()
212 ApplySettings(*this);
214 mpImplData
->mpVirDev
->SetFont(GetFont());
215 mpImplData
->mpVirDev
->SetTextColor(GetTextColor());
216 mpImplData
->mpVirDev
->SetTextAlign(GetTextAlign());
217 mpImplData
->mpVirDev
->SetTextFillColor();
218 mpImplData
->mpVirDev
->SetBackground(GetBackground());
221 void StatusBar::ImplFormat()
223 ImplStatusItem
* pItem
;
227 sal_uInt16 nAutoSizeItems
= 0;
230 mnItemsWidth
= STATUSBAR_OFFSET_X
;
232 for (ImplStatusItem
* i
: mpItemList
) {
234 if ( pItem
->mbVisible
)
236 if ( pItem
->mnBits
& StatusBarItemBits::AutoSize
) {
240 mnItemsWidth
+= pItem
->mnWidth
+ nOffset
;
241 nOffset
= pItem
->mnOffset
;
245 if ( GetStyle() & WB_RIGHT
)
247 // AutoSize isn't computed for right-alignment,
248 // because we show the text that is declared by SetText on the left side
249 nX
= mnDX
- mnItemsWidth
;
255 mnItemsWidth
+= STATUSBAR_OFFSET_X
;
257 // calling AutoSize is potentially necessary for left-aligned text,
258 if ( nAutoSizeItems
&& (mnDX
> (mnItemsWidth
- STATUSBAR_OFFSET
)) )
260 nExtraWidth
= (mnDX
- mnItemsWidth
- 1) / nAutoSizeItems
;
261 nExtraWidth2
= (mnDX
- mnItemsWidth
- 1) % nAutoSizeItems
;
268 nX
= STATUSBAR_OFFSET_X
;
270 if( HasMirroredGraphics() && IsRTLEnabled() )
271 nX
+= ImplGetSVData()->maNWFData
.mnStatusBarLowerRightOffset
;
274 for (ImplStatusItem
* i
: mpItemList
) {
276 if ( pItem
->mbVisible
) {
277 if ( pItem
->mnBits
& StatusBarItemBits::AutoSize
) {
278 pItem
->mnExtraWidth
= nExtraWidth
;
279 if ( nExtraWidth2
) {
280 pItem
->mnExtraWidth
++;
284 pItem
->mnExtraWidth
= 0;
288 nX
+= pItem
->mnWidth
+ pItem
->mnExtraWidth
+ pItem
->mnOffset
;
295 Rectangle
StatusBar::ImplGetItemRectPos( sal_uInt16 nPos
) const
298 ImplStatusItem
* pItem
;
299 pItem
= ( nPos
< mpItemList
.size() ) ? mpItemList
[ nPos
] : nullptr;
302 if ( pItem
->mbVisible
)
304 aRect
.Left() = pItem
->mnX
;
305 aRect
.Right() = aRect
.Left() + pItem
->mnWidth
+ pItem
->mnExtraWidth
;
306 aRect
.Top() = mnItemY
;
307 aRect
.Bottom() = mnCalcHeight
- STATUSBAR_OFFSET_Y
;
314 sal_uInt16
StatusBar::ImplGetFirstVisiblePos() const
316 for( size_t nPos
= 0; nPos
< mpItemList
.size(); nPos
++ )
318 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
321 if ( pItem
->mbVisible
)
322 return sal_uInt16(nPos
);
326 return SAL_MAX_UINT16
;
329 void StatusBar::ImplDrawText(vcl::RenderContext
& rRenderContext
)
331 // prevent item box from being overwritten
333 aTextRect
.Left() = STATUSBAR_OFFSET_X
+ 1;
334 aTextRect
.Top() = mnTextY
;
335 if (mbVisibleItems
&& (GetStyle() & WB_RIGHT
))
336 aTextRect
.Right() = mnDX
- mnItemsWidth
- 1;
338 aTextRect
.Right() = mnDX
- 1;
339 if (aTextRect
.Right() > aTextRect
.Left())
342 OUString aStr
= GetText();
343 sal_Int32 nPos
= aStr
.indexOf('\n');
345 aStr
= aStr
.copy(0, nPos
);
347 aTextRect
.Bottom() = aTextRect
.Top()+GetTextHeight()+1;
349 rRenderContext
.DrawText(aTextRect
, aStr
, DrawTextFlags::Left
| DrawTextFlags::Top
| DrawTextFlags::Clip
| DrawTextFlags::EndEllipsis
);
353 void StatusBar::ImplDrawItem(vcl::RenderContext
& rRenderContext
, bool bOffScreen
, sal_uInt16 nPos
)
355 Rectangle aRect
= ImplGetItemRectPos(nPos
);
360 // compute output region
361 ImplStatusItem
* pItem
= mpItemList
[nPos
];
362 long nW
= mpImplData
->mnItemBorderWidth
+ 1;
363 Rectangle
aTextRect(aRect
.Left() + nW
, aRect
.Top() + nW
,
364 aRect
.Right() - nW
, aRect
.Bottom() - nW
);
366 Size
aTextRectSize(aTextRect
.GetSize());
370 mpImplData
->mpVirDev
->SetOutputSizePixel(aTextRectSize
);
374 vcl::Region
aRegion(aTextRect
);
375 rRenderContext
.SetClipRegion(aRegion
);
379 Size
aTextSize(rRenderContext
.GetTextWidth(pItem
->maText
), rRenderContext
.GetTextHeight());
380 Point aTextPos
= ImplGetItemTextPos(aTextRectSize
, aTextSize
, pItem
->mnBits
);
383 mpImplData
->mpVirDev
->DrawText(aTextPos
, pItem
->maText
);
387 aTextPos
.X() += aTextRect
.Left();
388 aTextPos
.Y() += aTextRect
.Top();
389 rRenderContext
.DrawText(aTextPos
, pItem
->maText
);
392 // call DrawItem if necessary
393 if (pItem
->mnBits
& StatusBarItemBits::UserDraw
)
398 mpImplData
->mpVirDev
->EnableRTL( IsRTLEnabled() );
399 UserDrawEvent
aODEvt(this, mpImplData
->mpVirDev
, Rectangle(Point(), aTextRectSize
), pItem
->mnId
);
401 mpImplData
->mpVirDev
->EnableRTL(false);
402 mbInUserDraw
= false;
406 UserDrawEvent
aODEvt(this, &rRenderContext
, aTextRect
, pItem
->mnId
);
412 rRenderContext
.DrawOutDev(aTextRect
.TopLeft(), aTextRectSize
, Point(), aTextRectSize
, *mpImplData
->mpVirDev
);
414 rRenderContext
.SetClipRegion();
417 if (mpImplData
->mbDrawItemFrames
)
419 if (!(pItem
->mnBits
& StatusBarItemBits::Flat
))
421 DrawFrameStyle nStyle
;
423 if (pItem
->mnBits
& StatusBarItemBits::In
)
424 nStyle
= DrawFrameStyle::In
;
426 nStyle
= DrawFrameStyle::Out
;
428 DecorationView
aDecoView(&rRenderContext
);
429 aDecoView
.DrawFrame(aRect
, nStyle
);
432 else if (nPos
!= ImplGetFirstVisiblePos())
435 Point
aFrom(aRect
.TopLeft());
438 Point
aTo(aRect
.BottomLeft());
442 DecorationView
aDecoView(&rRenderContext
);
443 aDecoView
.DrawSeparator(aFrom
, aTo
);
446 if (!rRenderContext
.ImplIsRecordLayout())
447 CallEventListeners(VCLEVENT_STATUSBAR_DRAWITEM
, reinterpret_cast<void*>(pItem
->mnId
));
450 void DrawProgress(vcl::Window
* pWindow
, vcl::RenderContext
& rRenderContext
, const Point
& rPos
,
451 long nOffset
, long nPrgsWidth
, long nPrgsHeight
,
452 sal_uInt16 nPercent1
, sal_uInt16 nPercent2
, sal_uInt16 nPercentCount
,
453 const Rectangle
& rFramePosSize
)
455 if (rRenderContext
.IsNativeControlSupported(ControlType::Progress
, ControlPart::Entire
))
457 bool bNeedErase
= ImplGetSVData()->maNWFData
.mbProgressNeedsErase
;
459 long nFullWidth
= (nPrgsWidth
+ nOffset
) * (10000 / nPercentCount
);
460 long nPerc
= (nPercent2
> 10000) ? 10000 : nPercent2
;
461 ImplControlValue
aValue(nFullWidth
* long(nPerc
) / 10000);
462 Rectangle
aDrawRect(rPos
, Size(nFullWidth
, nPrgsHeight
));
463 Rectangle
aControlRegion(aDrawRect
);
467 vcl::Window
* pEraseWindow
= pWindow
;
468 while (pEraseWindow
->IsPaintTransparent() && !pEraseWindow
->ImplGetWindowImpl()->mbFrame
)
470 pEraseWindow
= pEraseWindow
->ImplGetWindowImpl()->mpParent
;
473 if (pEraseWindow
== pWindow
)
475 // restore background of pWindow
476 rRenderContext
.Erase(rFramePosSize
);
480 // restore transparent background
481 Point
aTL(pWindow
->OutputToAbsoluteScreenPixel(rFramePosSize
.TopLeft()));
482 aTL
= pEraseWindow
->AbsoluteScreenToOutputPixel(aTL
);
483 Rectangle
aRect(aTL
, rFramePosSize
.GetSize());
484 pEraseWindow
->Invalidate(aRect
, InvalidateFlags::NoChildren
|
485 InvalidateFlags::NoClipChildren
|
486 InvalidateFlags::Transparent
);
487 pEraseWindow
->Update();
489 rRenderContext
.Push(PushFlags::CLIPREGION
);
490 rRenderContext
.IntersectClipRegion(rFramePosSize
);
493 bool bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Progress
, ControlPart::Entire
, aControlRegion
,
494 ControlState::ENABLED
, aValue
, OUString());
496 rRenderContext
.Pop();
502 sal_uInt16 nPerc1
= nPercent1
/ nPercentCount
;
503 sal_uInt16 nPerc2
= nPercent2
/ nPercentCount
;
507 // support progress that can also decrease
510 long nDX
= nPrgsWidth
+ nOffset
;
511 long nLeft
= rPos
.X() + ((nPerc1
- 1) * nDX
);
512 Rectangle
aRect(nLeft
, rPos
.Y(), nLeft
+ nPrgsWidth
, rPos
.Y() + nPrgsHeight
);
516 rRenderContext
.Erase(aRect
);
518 aRect
.Right() -= nDX
;
521 while (nPerc1
> nPerc2
);
523 else if (nPerc1
< nPerc2
)
525 // draw Percent rectangle
526 // if Percent2 greater than 100%, adapt values
527 if (nPercent2
> 10000)
529 nPerc2
= 10000 / nPercentCount
;
530 if (nPerc1
>= nPerc2
)
535 long nDX
= nPrgsWidth
+ nOffset
;
536 long nLeft
= rPos
.X() + (nPerc1
* nDX
);
537 Rectangle
aRect(nLeft
, rPos
.Y(), nLeft
+ nPrgsWidth
, rPos
.Y() + nPrgsHeight
);
541 rRenderContext
.DrawRect(aRect
);
543 aRect
.Right() += nDX
;
546 while (nPerc1
< nPerc2
);
548 // if greater than 100%, set rectangle to blink
549 if (nPercent2
> 10000)
551 // define on/off status
552 if (((nPercent2
/ nPercentCount
) & 0x01) == (nPercentCount
& 0x01))
555 aRect
.Right() -= nDX
;
556 rRenderContext
.Erase(aRect
);
562 void StatusBar::ImplDrawProgress(vcl::RenderContext
& rRenderContext
, sal_uInt16 nPercent2
)
564 bool bNative
= rRenderContext
.IsNativeControlSupported(ControlType::Progress
, ControlPart::Entire
);
565 // bPaint: draw text also, else only update progress
566 rRenderContext
.DrawText(maPrgsTxtPos
, maPrgsTxt
);
569 DecorationView
aDecoView(&rRenderContext
);
570 aDecoView
.DrawFrame(maPrgsFrameRect
, DrawFrameStyle::In
);
573 Point
aPos(maPrgsFrameRect
.Left() + STATUSBAR_PRGS_OFFSET
,
574 maPrgsFrameRect
.Top() + STATUSBAR_PRGS_OFFSET
);
575 long nPrgsHeight
= mnPrgsSize
;
578 aPos
= maPrgsFrameRect
.TopLeft();
579 nPrgsHeight
= maPrgsFrameRect
.GetHeight();
581 DrawProgress(this, rRenderContext
, aPos
, mnPrgsSize
/ 2, mnPrgsSize
, nPrgsHeight
,
582 0, nPercent2
* 100, mnPercentCount
, maPrgsFrameRect
);
585 void StatusBar::ImplCalcProgressRect()
587 // calculate text size
588 Size
aPrgsTxtSize( GetTextWidth( maPrgsTxt
), GetTextHeight() );
589 maPrgsTxtPos
.X() = STATUSBAR_OFFSET_X
+1;
591 // calculate progress frame
592 maPrgsFrameRect
.Left() = maPrgsTxtPos
.X()+aPrgsTxtSize
.Width()+STATUSBAR_OFFSET
;
593 maPrgsFrameRect
.Top() = mnItemY
;
594 maPrgsFrameRect
.Bottom() = mnCalcHeight
- STATUSBAR_OFFSET_Y
;
596 // calculate size of progress rects
597 mnPrgsSize
= maPrgsFrameRect
.Bottom()-maPrgsFrameRect
.Top()-(STATUSBAR_PRGS_OFFSET
*2);
598 sal_uInt16 nMaxPercent
= STATUSBAR_PRGS_COUNT
;
600 long nMaxWidth
= mnDX
-STATUSBAR_OFFSET
-1;
602 // make smaller if there are too many rects
603 while ( maPrgsFrameRect
.Left()+ImplCalcProgessWidth( nMaxPercent
, mnPrgsSize
) > nMaxWidth
)
606 if ( nMaxPercent
<= STATUSBAR_PRGS_MIN
)
609 maPrgsFrameRect
.Right() = maPrgsFrameRect
.Left() + ImplCalcProgessWidth( nMaxPercent
, mnPrgsSize
);
611 // save the divisor for later
612 mnPercentCount
= 10000 / nMaxPercent
;
613 bool bNativeOK
= false;
614 if( IsNativeControlSupported( ControlType::Progress
, ControlPart::Entire
) )
616 ImplControlValue aValue
;
617 Rectangle
aControlRegion( Rectangle( (const Point
&)Point(), maPrgsFrameRect
.GetSize() ) );
618 Rectangle aNativeControlRegion
, aNativeContentRegion
;
619 if( (bNativeOK
= GetNativeControlRegion( ControlType::Progress
, ControlPart::Entire
, aControlRegion
,
620 ControlState::ENABLED
, aValue
, OUString(),
621 aNativeControlRegion
, aNativeContentRegion
) ) )
623 long nProgressHeight
= aNativeControlRegion
.GetHeight();
624 if( nProgressHeight
> maPrgsFrameRect
.GetHeight() )
626 long nDelta
= nProgressHeight
- maPrgsFrameRect
.GetHeight();
627 maPrgsFrameRect
.Top() -= (nDelta
- nDelta
/2);
628 maPrgsFrameRect
.Bottom() += nDelta
/2;
630 maPrgsTxtPos
.Y() = maPrgsFrameRect
.Top() + (nProgressHeight
- GetTextHeight())/2;
634 maPrgsTxtPos
.Y() = mnTextY
;
637 void StatusBar::MouseButtonDown( const MouseEvent
& rMEvt
)
639 // trigger toolbox only for left mouse button
640 if ( rMEvt
.IsLeft() )
642 if ( mbVisibleItems
)
644 Point aMousePos
= rMEvt
.GetPosPixel();
646 // search for clicked item
647 for ( size_t i
= 0; i
< mpItemList
.size(); ++i
)
649 ImplStatusItem
* pItem
= mpItemList
[ i
];
650 // check item for being clicked
651 if ( ImplGetItemRectPos( sal_uInt16(i
) ).IsInside( aMousePos
) )
653 mnCurItemId
= pItem
->mnId
;
654 if ( rMEvt
.GetClicks() == 2 )
666 // if there's no item, trigger Click or DoubleClick
667 if ( rMEvt
.GetClicks() == 2 )
674 void StatusBar::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
679 sal_uInt16 nItemCount
= sal_uInt16( mpItemList
.size() );
683 rRenderContext
.Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
685 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
686 Color aProgressColor
= rStyleSettings
.GetHighlightColor();
687 if (aProgressColor
== rStyleSettings
.GetFaceColor())
688 aProgressColor
= rStyleSettings
.GetDarkShadowColor();
689 rRenderContext
.SetLineColor();
690 rRenderContext
.SetFillColor(aProgressColor
);
692 ImplDrawProgress(rRenderContext
, mnPercent
);
694 rRenderContext
.Pop();
699 if (!mbVisibleItems
|| (GetStyle() & WB_RIGHT
))
700 ImplDrawText(rRenderContext
);
705 // Do offscreen only when we are not recording layout..
706 bool bOffscreen
= !rRenderContext
.ImplIsRecordLayout();
708 // tdf#94213 - un-necessary virtual-device in GL mode
709 // causes context switch & hence flicker during sizing.
710 #if HAVE_FEATURE_OPENGL
711 if( OpenGLWrapper::isVCLOpenGLEnabled() )
716 rRenderContext
.Erase(rRect
);
718 for (sal_uInt16 i
= 0; i
< nItemCount
; i
++)
719 ImplDrawItem(rRenderContext
, bOffscreen
, i
);
723 // draw line at the top of the status bar (to visually distinguish it from
724 // shell / docking area)
725 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
726 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
727 rRenderContext
.DrawLine(Point(0, 0), Point(mnDX
-1, 0));
730 void StatusBar::Resize()
732 // save width and height
733 Size aSize
= GetOutputSizePixel();
734 mnDX
= aSize
.Width() - ImplGetSVData()->maNWFData
.mnStatusBarLowerRightOffset
;
735 mnDY
= aSize
.Height();
738 mnItemY
= STATUSBAR_OFFSET_Y
;
739 mnTextY
= (mnCalcHeight
-GetTextHeight())/2;
741 // provoke re-formatting
744 if ( mbProgressMode
)
745 ImplCalcProgressRect();
750 void StatusBar::RequestHelp( const HelpEvent
& rHEvt
)
752 // no keyboard help in status bar
753 if( rHEvt
.KeyboardActivated() )
756 sal_uInt16 nItemId
= GetItemId( ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ) );
760 Rectangle aItemRect
= GetItemRect( nItemId
);
761 Point aPt
= OutputToScreenPixel( aItemRect
.TopLeft() );
762 aItemRect
.Left() = aPt
.X();
763 aItemRect
.Top() = aPt
.Y();
764 aPt
= OutputToScreenPixel( aItemRect
.BottomRight() );
765 aItemRect
.Right() = aPt
.X();
766 aItemRect
.Bottom() = aPt
.Y();
768 if ( rHEvt
.GetMode() & HelpEventMode::BALLOON
)
770 OUString aStr
= GetHelpText( nItemId
);
771 Help::ShowBalloon( this, aItemRect
.Center(), aItemRect
, aStr
);
774 else if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
776 OUString
aStr(GetQuickHelpText(nItemId
));
777 // show quickhelp if available
780 Help::ShowQuickHelp( this, aItemRect
, aStr
);
783 aStr
= GetItemText( nItemId
);
784 // show a quick help if item text doesn't fit
785 if ( GetTextWidth( aStr
) > aItemRect
.GetWidth() )
787 Help::ShowQuickHelp( this, aItemRect
, aStr
);
791 else if ( rHEvt
.GetMode() & HelpEventMode::EXTENDED
)
793 OUString aCommand
= GetItemCommand( nItemId
);
794 OString
aHelpId( GetHelpId( nItemId
) );
796 if ( !aCommand
.isEmpty() || !aHelpId
.isEmpty() )
798 // show help text if there is one
799 Help
* pHelp
= Application::GetHelp();
802 if ( !aCommand
.isEmpty() )
803 pHelp
->Start( aCommand
, this );
804 else if ( !aHelpId
.isEmpty() )
805 pHelp
->Start( OStringToOUString( aHelpId
, RTL_TEXTENCODING_UTF8
), this );
812 Window::RequestHelp( rHEvt
);
815 void StatusBar::StateChanged( StateChangedType nType
)
817 Window::StateChanged( nType
);
819 if ( nType
== StateChangedType::InitShow
)
821 else if ( nType
== StateChangedType::UpdateMode
)
823 else if ( (nType
== StateChangedType::Zoom
) ||
824 (nType
== StateChangedType::ControlFont
) )
830 else if ( nType
== StateChangedType::ControlForeground
)
835 else if ( nType
== StateChangedType::ControlBackground
)
842 void StatusBar::DataChanged( const DataChangedEvent
& rDCEvt
)
844 Window::DataChanged( rDCEvt
);
846 if ( (rDCEvt
.GetType() == DataChangedEventType::DISPLAY
)
847 || (rDCEvt
.GetType() == DataChangedEventType::FONTS
)
848 || (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
)
849 || ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
)
850 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)
856 long nFudge
= GetTextHeight() / 4;
857 for (ImplStatusItem
* pItem
: mpItemList
)
859 long nWidth
= GetTextWidth( pItem
->maText
) + nFudge
;
860 if( nWidth
> pItem
->mnWidth
+ STATUSBAR_OFFSET
)
861 pItem
->mnWidth
= nWidth
+ STATUSBAR_OFFSET
;
863 Size aSize
= GetSizePixel();
864 // do not disturb current width, since
865 // CalcWindowSizePixel calculates a minimum width
866 aSize
.Height() = CalcWindowSizePixel().Height();
867 SetSizePixel( aSize
);
872 void StatusBar::Click()
874 CallEventListeners( VCLEVENT_STATUSBAR_CLICK
);
875 maClickHdl
.Call( this );
878 void StatusBar::DoubleClick()
880 CallEventListeners( VCLEVENT_STATUSBAR_DOUBLECLICK
);
881 maDoubleClickHdl
.Call( this );
884 void StatusBar::UserDraw( const UserDrawEvent
& )
888 void StatusBar::InsertItem( sal_uInt16 nItemId
, sal_uLong nWidth
,
889 StatusBarItemBits nBits
,
890 long nOffset
, sal_uInt16 nPos
)
892 SAL_WARN_IF( !nItemId
, "vcl", "StatusBar::InsertItem(): ItemId == 0" );
893 SAL_WARN_IF( GetItemPos( nItemId
) != STATUSBAR_ITEM_NOTFOUND
, "vcl",
894 "StatusBar::InsertItem(): ItemId already exists" );
896 // default: IN and CENTER
897 if ( !(nBits
& (StatusBarItemBits::In
| StatusBarItemBits::Out
| StatusBarItemBits::Flat
)) )
898 nBits
|= StatusBarItemBits::In
;
899 if ( !(nBits
& (StatusBarItemBits::Left
| StatusBarItemBits::Right
| StatusBarItemBits::Center
)) )
900 nBits
|= StatusBarItemBits::Center
;
905 nWidth
*= GetDPIScaleFactor();
907 long nFudge
= GetTextHeight()/4;
908 ImplStatusItem
* pItem
= new ImplStatusItem
;
909 pItem
->mnId
= nItemId
;
910 pItem
->mnBits
= nBits
;
911 pItem
->mnWidth
= (long)nWidth
+nFudge
+STATUSBAR_OFFSET
;
912 pItem
->mnOffset
= nOffset
;
913 pItem
->mpUserData
= nullptr;
914 pItem
->mbVisible
= true;
917 if ( nPos
< mpItemList
.size() ) {
918 mpItemList
.insert( mpItemList
.begin() + nPos
, pItem
);
920 mpItemList
.push_back( pItem
);
924 if ( ImplIsItemUpdate() )
927 CallEventListeners( VCLEVENT_STATUSBAR_ITEMADDED
, reinterpret_cast<void*>(nItemId
) );
930 void StatusBar::RemoveItem( sal_uInt16 nItemId
)
932 sal_uInt16 nPos
= GetItemPos( nItemId
);
933 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
935 delete mpItemList
[ nPos
];
936 mpItemList
.erase( mpItemList
.begin() + nPos
);
939 if ( ImplIsItemUpdate() )
942 CallEventListeners( VCLEVENT_STATUSBAR_ITEMREMOVED
, reinterpret_cast<void*>(nItemId
) );
946 void StatusBar::ShowItem( sal_uInt16 nItemId
)
948 sal_uInt16 nPos
= GetItemPos( nItemId
);
950 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
952 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
953 if ( !pItem
->mbVisible
)
955 pItem
->mbVisible
= true;
958 if ( ImplIsItemUpdate() )
961 CallEventListeners( VCLEVENT_STATUSBAR_SHOWITEM
, reinterpret_cast<void*>(nItemId
) );
966 void StatusBar::HideItem( sal_uInt16 nItemId
)
968 sal_uInt16 nPos
= GetItemPos( nItemId
);
970 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
972 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
973 if ( pItem
->mbVisible
)
975 pItem
->mbVisible
= false;
978 if ( ImplIsItemUpdate() )
981 CallEventListeners( VCLEVENT_STATUSBAR_HIDEITEM
, reinterpret_cast<void*>(nItemId
) );
986 bool StatusBar::IsItemVisible( sal_uInt16 nItemId
) const
988 sal_uInt16 nPos
= GetItemPos( nItemId
);
990 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
991 return mpItemList
[ nPos
]->mbVisible
;
996 void StatusBar::Clear()
999 for (ImplStatusItem
* i
: mpItemList
) {
1005 if ( ImplIsItemUpdate() )
1008 CallEventListeners( VCLEVENT_STATUSBAR_ALLITEMSREMOVED
);
1011 sal_uInt16
StatusBar::GetItemCount() const
1013 return (sal_uInt16
)mpItemList
.size();
1016 sal_uInt16
StatusBar::GetItemId( sal_uInt16 nPos
) const
1018 if ( nPos
< mpItemList
.size() )
1019 return mpItemList
[ nPos
]->mnId
;
1023 sal_uInt16
StatusBar::GetItemPos( sal_uInt16 nItemId
) const
1025 for ( size_t i
= 0, n
= mpItemList
.size(); i
< n
; ++i
) {
1026 if ( mpItemList
[ i
]->mnId
== nItemId
) {
1027 return sal_uInt16( i
);
1031 return STATUSBAR_ITEM_NOTFOUND
;
1034 sal_uInt16
StatusBar::GetItemId( const Point
& rPos
) const
1036 if ( AreItemsVisible() && !mbFormat
)
1038 sal_uInt16 nItemCount
= GetItemCount();
1040 for ( nPos
= 0; nPos
< nItemCount
; nPos
++ )
1043 Rectangle aRect
= ImplGetItemRectPos( nPos
);
1044 if ( aRect
.IsInside( rPos
) )
1045 return mpItemList
[ nPos
]->mnId
;
1052 Rectangle
StatusBar::GetItemRect( sal_uInt16 nItemId
) const
1056 if ( AreItemsVisible() && !mbFormat
)
1058 sal_uInt16 nPos
= GetItemPos( nItemId
);
1059 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1061 // get rectangle and subtract frame
1062 aRect
= ImplGetItemRectPos( nPos
);
1063 long nW
= mpImplData
->mnItemBorderWidth
+1;
1064 aRect
.Top() += nW
-1;
1065 aRect
.Bottom() -= nW
-1;
1067 aRect
.Right() -= nW
;
1075 Point
StatusBar::GetItemTextPos( sal_uInt16 nItemId
) const
1079 sal_uInt16 nPos
= GetItemPos( nItemId
);
1080 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1083 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1084 Rectangle aRect
= ImplGetItemRectPos( nPos
);
1085 long nW
= mpImplData
->mnItemBorderWidth
+ 1;
1086 Rectangle
aTextRect( aRect
.Left()+nW
, aRect
.Top()+nW
,
1087 aRect
.Right()-nW
, aRect
.Bottom()-nW
);
1088 Point aPos
= ImplGetItemTextPos( aTextRect
.GetSize(),
1089 Size( GetTextWidth( pItem
->maText
), GetTextHeight() ),
1091 if ( !mbInUserDraw
)
1093 aPos
.X() += aTextRect
.Left();
1094 aPos
.Y() += aTextRect
.Top();
1103 sal_uLong
StatusBar::GetItemWidth( sal_uInt16 nItemId
) const
1105 sal_uInt16 nPos
= GetItemPos( nItemId
);
1107 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1108 return mpItemList
[ nPos
]->mnWidth
;
1113 StatusBarItemBits
StatusBar::GetItemBits( sal_uInt16 nItemId
) const
1115 sal_uInt16 nPos
= GetItemPos( nItemId
);
1117 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1118 return mpItemList
[ nPos
]->mnBits
;
1120 return StatusBarItemBits::NONE
;
1123 long StatusBar::GetItemOffset( sal_uInt16 nItemId
) const
1125 sal_uInt16 nPos
= GetItemPos( nItemId
);
1127 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1128 return mpItemList
[ nPos
]->mnOffset
;
1133 void StatusBar::SetItemText( sal_uInt16 nItemId
, const OUString
& rText
)
1135 sal_uInt16 nPos
= GetItemPos( nItemId
);
1137 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1139 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1141 if ( pItem
->maText
!= rText
)
1143 pItem
->maText
= rText
;
1145 // adjust item width - see also DataChanged()
1146 long nFudge
= GetTextHeight()/4;
1147 long nWidth
= GetTextWidth( pItem
->maText
) + nFudge
;
1148 if( (nWidth
> pItem
->mnWidth
+ STATUSBAR_OFFSET
) ||
1149 ((nWidth
< pItem
->mnWidth
) && (mnDX
- STATUSBAR_OFFSET
) < mnItemsWidth
))
1151 pItem
->mnWidth
= nWidth
+ STATUSBAR_OFFSET
;
1156 // re-draw item if StatusBar is visible and UpdateMode active
1157 if ( pItem
->mbVisible
&& !mbFormat
&& ImplIsItemUpdate() )
1159 Rectangle aRect
= ImplGetItemRectPos(nPos
);
1167 const OUString
& StatusBar::GetItemText( sal_uInt16 nItemId
) const
1169 sal_uInt16 nPos
= GetItemPos( nItemId
);
1171 assert( nPos
!= STATUSBAR_ITEM_NOTFOUND
);
1173 return mpItemList
[ nPos
]->maText
;
1176 void StatusBar::SetItemCommand( sal_uInt16 nItemId
, const OUString
& rCommand
)
1178 sal_uInt16 nPos
= GetItemPos( nItemId
);
1180 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1182 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1184 if ( pItem
->maCommand
!= rCommand
)
1185 pItem
->maCommand
= rCommand
;
1189 const OUString
StatusBar::GetItemCommand( sal_uInt16 nItemId
)
1191 sal_uInt16 nPos
= GetItemPos( nItemId
);
1193 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1194 return mpItemList
[ nPos
]->maCommand
;
1199 void StatusBar::SetItemData( sal_uInt16 nItemId
, void* pNewData
)
1201 sal_uInt16 nPos
= GetItemPos( nItemId
);
1203 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1205 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1206 pItem
->mpUserData
= pNewData
;
1208 // call Draw-Item if it's a User-Item
1209 if ( (pItem
->mnBits
& StatusBarItemBits::UserDraw
) && pItem
->mbVisible
&&
1210 !mbFormat
&& ImplIsItemUpdate() )
1212 Rectangle aRect
= ImplGetItemRectPos(nPos
);
1213 Invalidate(aRect
, InvalidateFlags::NoErase
);
1219 void* StatusBar::GetItemData( sal_uInt16 nItemId
) const
1221 sal_uInt16 nPos
= GetItemPos( nItemId
);
1223 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1224 return mpItemList
[ nPos
]->mpUserData
;
1229 void StatusBar::RedrawItem(sal_uInt16 nItemId
)
1234 sal_uInt16 nPos
= GetItemPos(nItemId
);
1235 if ( nPos
== STATUSBAR_ITEM_NOTFOUND
)
1238 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1239 if (pItem
&& (pItem
->mnBits
& StatusBarItemBits::UserDraw
) &&
1240 pItem
->mbVisible
&& ImplIsItemUpdate())
1242 Rectangle aRect
= ImplGetItemRectPos(nPos
);
1248 void StatusBar::SetHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1250 sal_uInt16 nPos
= GetItemPos( nItemId
);
1252 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1253 mpItemList
[ nPos
]->maHelpText
= rText
;
1256 const OUString
& StatusBar::GetHelpText( sal_uInt16 nItemId
) const
1258 sal_uInt16 nPos
= GetItemPos( nItemId
);
1260 assert ( nPos
!= STATUSBAR_ITEM_NOTFOUND
);
1262 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1263 if ( pItem
->maHelpText
.isEmpty() && ( !pItem
->maHelpId
.isEmpty() || !pItem
->maCommand
.isEmpty() ))
1265 Help
* pHelp
= Application::GetHelp();
1268 if ( !pItem
->maCommand
.isEmpty() )
1269 pItem
->maHelpText
= pHelp
->GetHelpText( pItem
->maCommand
, this );
1270 if ( pItem
->maHelpText
.isEmpty() && !pItem
->maHelpId
.isEmpty() )
1271 pItem
->maHelpText
= pHelp
->GetHelpText( OStringToOUString( pItem
->maHelpId
, RTL_TEXTENCODING_UTF8
), this );
1275 return pItem
->maHelpText
;
1278 void StatusBar::SetQuickHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1280 sal_uInt16 nPos
= GetItemPos( nItemId
);
1282 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1283 mpItemList
[ nPos
]->maQuickHelpText
= rText
;
1286 const OUString
& StatusBar::GetQuickHelpText( sal_uInt16 nItemId
) const
1288 sal_uInt16 nPos
= GetItemPos( nItemId
);
1290 assert ( nPos
!= STATUSBAR_ITEM_NOTFOUND
);
1292 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1293 return pItem
->maQuickHelpText
;
1296 void StatusBar::SetHelpId( sal_uInt16 nItemId
, const OString
& rHelpId
)
1298 sal_uInt16 nPos
= GetItemPos( nItemId
);
1300 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1301 mpItemList
[ nPos
]->maHelpId
= rHelpId
;
1304 OString
StatusBar::GetHelpId( sal_uInt16 nItemId
) const
1306 sal_uInt16 nPos
= GetItemPos( nItemId
);
1309 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1311 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1312 if ( !pItem
->maHelpId
.isEmpty() )
1313 aRet
= pItem
->maHelpId
;
1315 aRet
= OUStringToOString( pItem
->maCommand
, RTL_TEXTENCODING_UTF8
);
1321 void StatusBar::StartProgressMode( const OUString
& rText
)
1323 SAL_WARN_IF( mbProgressMode
, "vcl", "StatusBar::StartProgressMode(): progress mode is active" );
1325 mbProgressMode
= true;
1330 ImplCalcProgressRect();
1332 // trigger Paint, which draws text and frame
1333 if ( IsReallyVisible() )
1340 void StatusBar::SetProgressValue( sal_uInt16 nNewPercent
)
1342 SAL_WARN_IF( !mbProgressMode
, "vcl", "StatusBar::SetProgressValue(): no progress mode" );
1343 SAL_WARN_IF( nNewPercent
> 100, "vcl", "StatusBar::SetProgressValue(): nPercent > 100" );
1346 && IsReallyVisible()
1347 && (!mnPercent
|| (mnPercent
!= nNewPercent
)) )
1349 bool bNeedErase
= ImplGetSVData()->maNWFData
.mbProgressNeedsErase
;
1350 Invalidate(maPrgsFrameRect
, bNeedErase
? InvalidateFlags::NONE
: InvalidateFlags::NoErase
);
1353 mnPercent
= nNewPercent
;
1356 void StatusBar::EndProgressMode()
1358 SAL_WARN_IF( !mbProgressMode
, "vcl", "StatusBar::EndProgressMode(): no progress mode" );
1360 mbProgressMode
= false;
1363 if ( IsReallyVisible() )
1370 void StatusBar::SetText(const OUString
& rText
)
1372 if ((!mbVisibleItems
|| (GetStyle() & WB_RIGHT
)) && !mbProgressMode
&& IsReallyVisible() && IsUpdateMode())
1377 Window::SetText(rText
);
1382 Window::SetText(rText
);
1386 else if (mbProgressMode
)
1389 if (IsReallyVisible())
1397 Window::SetText(rText
);
1401 Size
StatusBar::CalcWindowSizePixel() const
1404 size_t nCount
= mpItemList
.size();
1406 long nCalcWidth
= (STATUSBAR_OFFSET_X
*2);
1409 while ( i
< nCount
)
1411 ImplStatusItem
* pItem
= mpItemList
[ i
];
1412 nCalcWidth
+= pItem
->mnWidth
+ nOffset
;
1413 nOffset
= pItem
->mnOffset
;
1417 long nMinHeight
= GetTextHeight();
1418 const long nBarTextOffset
= STATUSBAR_OFFSET_TEXTY
*2;
1419 long nProgressHeight
= nMinHeight
+ nBarTextOffset
;
1421 if( IsNativeControlSupported( ControlType::Progress
, ControlPart::Entire
) )
1423 ImplControlValue aValue
;
1424 Rectangle
aControlRegion( (const Point
&)Point(), Size( nCalcWidth
, nMinHeight
) );
1425 Rectangle aNativeControlRegion
, aNativeContentRegion
;
1426 if( GetNativeControlRegion( ControlType::Progress
, ControlPart::Entire
,
1427 aControlRegion
, ControlState::ENABLED
, aValue
, OUString(),
1428 aNativeControlRegion
, aNativeContentRegion
) )
1430 nProgressHeight
= aNativeControlRegion
.GetHeight();
1434 if( mpImplData
->mbDrawItemFrames
&&
1435 IsNativeControlSupported( ControlType::Frame
, ControlPart::Border
) )
1437 ImplControlValue
aControlValue( static_cast<long>(DrawFrameFlags::NoDraw
) );
1438 Rectangle aBound
, aContent
;
1439 Rectangle
aNatRgn( Point( 0, 0 ), Size( 150, 50 ) );
1440 if( GetNativeControlRegion(ControlType::Frame
, ControlPart::Border
,
1441 aNatRgn
, ControlState::NONE
, aControlValue
, OUString(), aBound
, aContent
) )
1443 mpImplData
->mnItemBorderWidth
=
1444 ( aBound
.GetHeight() - aContent
.GetHeight() ) / 2;
1448 nCalcHeight
= nMinHeight
+nBarTextOffset
+ 2*mpImplData
->mnItemBorderWidth
;
1449 if( nCalcHeight
< nProgressHeight
+2 )
1450 nCalcHeight
= nProgressHeight
+2;
1452 return Size( nCalcWidth
, nCalcHeight
);
1455 void StatusBar::SetAccessibleName( sal_uInt16 nItemId
, const OUString
& rName
)
1457 sal_uInt16 nPos
= GetItemPos( nItemId
);
1459 if ( nPos
!= STATUSBAR_ITEM_NOTFOUND
)
1461 ImplStatusItem
* pItem
= mpItemList
[ nPos
];
1463 if ( pItem
->maAccessibleName
!= rName
)
1465 pItem
->maAccessibleName
= rName
;
1466 CallEventListeners( VCLEVENT_STATUSBAR_NAMECHANGED
, reinterpret_cast<void*>(pItem
->mnId
) );
1471 const OUString
& StatusBar::GetAccessibleName( sal_uInt16 nItemId
) const
1473 sal_uInt16 nPos
= GetItemPos( nItemId
);
1475 assert ( nPos
!= STATUSBAR_ITEM_NOTFOUND
);
1477 return mpItemList
[ nPos
]->maAccessibleName
;
1480 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */