/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <comphelper/string.hxx>
#include <sal/log.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/time.hxx>
#include <vcl/window.hxx>
#include <vcl/event.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/help.hxx>
#include <vcl/settings.hxx>
#include <helpwin.hxx>
#include <salframe.hxx>
#include <svdata.hxx>
#define HELPWINSTYLE_QUICK 0
#define HELPWINSTYLE_BALLOON 1
#define HELPTEXTMARGIN_QUICK 3
#define HELPTEXTMARGIN_BALLOON 6
#define HELPTEXTMAXLEN 150
Help::Help()
{
}
Help::~Help()
{
}
bool Help::Start( const OUString&, const vcl::Window* )
{
return false;
}
bool Help::Start(const OUString&, weld::Widget*)
{
return false;
}
void Help::SearchKeyword( const OUString& )
{
}
OUString Help::GetHelpText( const OUString& )
{
return OUString();
}
void Help::EnableContextHelp()
{
ImplGetSVHelpData().mbContextHelp = true;
}
void Help::DisableContextHelp()
{
ImplGetSVHelpData().mbContextHelp = false;
}
void Help::EnableExtHelp()
{
ImplGetSVHelpData().mbExtHelp = true;
}
void Help::DisableExtHelp()
{
ImplGetSVHelpData().mbExtHelp = false;
}
bool Help::IsExtHelpEnabled()
{
return ImplGetSVHelpData().mbExtHelp;
}
bool Help::StartExtHelp()
{
ImplSVData* pSVData = ImplGetSVData();
ImplSVHelpData& aHelpData = ImplGetSVHelpData();
if ( aHelpData.mbExtHelp && !aHelpData.mbExtHelpMode )
{
aHelpData.mbExtHelpMode = true;
aHelpData.mbOldBalloonMode = aHelpData.mbBalloonHelp;
aHelpData.mbBalloonHelp = true;
if (pSVData->maFrameData.mpAppWin)
pSVData->maFrameData.mpAppWin->ImplGenerateMouseMove();
return true;
}
return false;
}
bool Help::EndExtHelp()
{
ImplSVData* pSVData = ImplGetSVData();
ImplSVHelpData& aHelpData = ImplGetSVHelpData();
if ( aHelpData.mbExtHelp && aHelpData.mbExtHelpMode )
{
aHelpData.mbExtHelpMode = false;
aHelpData.mbBalloonHelp = aHelpData.mbOldBalloonMode;
if (pSVData->maFrameData.mpAppWin)
pSVData->maFrameData.mpAppWin->ImplGenerateMouseMove();
return true;
}
return false;
}
void Help::EnableBalloonHelp()
{
ImplGetSVHelpData().mbBalloonHelp = true;
}
void Help::DisableBalloonHelp()
{
ImplGetSVHelpData().mbBalloonHelp = false;
}
bool Help::IsBalloonHelpEnabled()
{
return ImplGetSVHelpData().mbBalloonHelp;
}
void Help::ShowBalloon( vcl::Window* pParent,
const Point& rScreenPos, const tools::Rectangle& rRect,
const OUString& rHelpText )
{
ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, QuickHelpFlags::NONE,
rHelpText, rScreenPos, rRect );
}
void Help::EnableQuickHelp()
{
ImplGetSVHelpData().mbQuickHelp = true;
}
void Help::DisableQuickHelp()
{
ImplGetSVHelpData().mbQuickHelp = false;
}
bool Help::IsQuickHelpEnabled()
{
return ImplGetSVHelpData().mbQuickHelp;
}
void Help::ShowQuickHelp( vcl::Window* pParent,
const tools::Rectangle& rScreenRect,
const OUString& rHelpText,
QuickHelpFlags nStyle )
{
sal_uInt16 nHelpWinStyle = ( nStyle & QuickHelpFlags::TipStyleBalloon ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK;
Point aScreenPos = nStyle & QuickHelpFlags::NoAutoPos
? Point()
: pParent->OutputToScreenPixel(pParent->GetPointerPosPixel());
ImplShowHelpWindow( pParent, nHelpWinStyle, nStyle,
rHelpText, aScreenPos, rScreenRect );
}
void Help::HideBalloonAndQuickHelp()
{
HelpTextWindow const * pHelpWin = ImplGetSVHelpData().mpHelpWin;
bool const bIsVisible = ( pHelpWin != nullptr ) && pHelpWin->IsVisible();
ImplDestroyHelpWindow( bIsVisible );
}
void* Help::ShowPopover(vcl::Window* pParent, const tools::Rectangle& rScreenRect,
const OUString& rText, QuickHelpFlags nStyle)
{
void* nId = pParent->ImplGetFrame()->ShowPopover(rText, pParent, rScreenRect, nStyle);
if (nId)
{
//popovers are handled natively, return early
return nId;
}
sal_uInt16 nHelpWinStyle = ( nStyle & QuickHelpFlags::TipStyleBalloon ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK;
VclPtrInstance<HelpTextWindow> pHelpWin( pParent, rText, nHelpWinStyle, nStyle );
nId = pHelpWin.get();
UpdatePopover(nId, pParent, rScreenRect, rText);
pHelpWin->ShowHelp(true);
return nId;
}
void Help::UpdatePopover(void* nId, vcl::Window* pParent, const tools::Rectangle& rScreenRect,
const OUString& rText)
{
if (pParent->ImplGetFrame()->UpdatePopover(nId, rText, pParent, rScreenRect))
{
//popovers are handled natively, return early
return;
}
HelpTextWindow* pHelpWin = static_cast< HelpTextWindow* >( nId );
ENSURE_OR_RETURN_VOID( pHelpWin != nullptr, "Help::UpdatePopover: invalid ID!" );
Size aSz = pHelpWin->CalcOutSize();
pHelpWin->SetOutputSizePixel( aSz );
ImplSetHelpWindowPos( pHelpWin, pHelpWin->GetWinStyle(), pHelpWin->GetStyle(),
pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), rScreenRect );
pHelpWin->SetHelpText( rText );
pHelpWin->Invalidate();
}
void Help::HidePopover(vcl::Window const * pParent, void* nId)
{
if (pParent->ImplGetFrame()->HidePopover(nId))
{
//popovers are handled natively, return early
return;
}
VclPtr<HelpTextWindow> pHelpWin = static_cast<HelpTextWindow*>(nId);
vcl::Window* pFrameWindow = pHelpWin->ImplGetFrameWindow();
pHelpWin->Hide();
// trigger update, so that a Paint is instantly triggered since we do not save the background
pFrameWindow->ImplUpdateAll();
pHelpWin.disposeAndClear();
ImplGetSVHelpData().mnLastHelpHideTime = tools::Time::GetSystemTicks();
}
HelpTextWindow::HelpTextWindow( vcl::Window* pParent, const OUString& rText, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle ) :
FloatingWindow( pParent, WB_SYSTEMWINDOW|WB_TOOLTIPWIN ), // #105827# if we change the parent, mirroring will not work correctly when positioning this window
maHelpText( rText ),
maShowTimer( "vcl::HelpTextWindow maShowTimer" ),
maHideTimer( "vcl::HelpTextWindow maHideTimer" )
{
SetType( WindowType::HELPTEXTWINDOW );
ImplSetMouseTransparent( true );
mnHelpWinStyle = nHelpWinStyle;
mnStyle = nStyle;
if( mnStyle & QuickHelpFlags::BiDiRtl )
{
vcl::text::ComplexTextLayoutFlags nLayoutMode = GetOutDev()->GetLayoutMode();
nLayoutMode |= vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
GetOutDev()->SetLayoutMode( nLayoutMode );
}
SetHelpText( rText );
Window::SetHelpText( rText );
if ( ImplGetSVHelpData().mbSetKeyboardHelp )
ImplGetSVHelpData().mbKeyboardHelp = true;
maShowTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) );
const HelpSettings& rHelpSettings = pParent->GetSettings().GetHelpSettings();
maHideTimer.SetTimeout( rHelpSettings.GetTipTimeout() );
maHideTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) );
}
void HelpTextWindow::ApplySettings(vcl::RenderContext& rRenderContext)
{
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
SetPointFont(rRenderContext, rStyleSettings.GetHelpFont());
rRenderContext.SetTextColor(rStyleSettings.GetHelpTextColor());
rRenderContext.SetTextAlign(ALIGN_TOP);
if (rRenderContext.IsNativeControlSupported(ControlType::Tooltip, ControlPart::Entire))
{
EnableChildTransparentMode();
SetParentClipMode(ParentClipMode::NoClip);
SetPaintTransparent(true);
rRenderContext.SetBackground();
}
else
rRenderContext.SetBackground(Wallpaper(rStyleSettings.GetHelpColor()));
if (rStyleSettings.GetHelpColor().IsDark())
rRenderContext.SetLineColor(COL_WHITE);
else
rRenderContext.SetLineColor(COL_BLACK);
rRenderContext.SetFillColor();
}
HelpTextWindow::~HelpTextWindow()
{
disposeOnce();
}
void HelpTextWindow::dispose()
{
maShowTimer.Stop();
maHideTimer.Stop();
if( this == ImplGetSVHelpData().mpHelpWin )
ImplGetSVHelpData().mpHelpWin = nullptr;
FloatingWindow::dispose();
}
void HelpTextWindow::SetHelpText( const OUString& rHelpText )
{
maHelpText = rHelpText;
ApplySettings(*GetOutDev());
if ( mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0)
{
Size aSize;
aSize.setHeight( GetTextHeight() );
if ( mnStyle & QuickHelpFlags::CtrlText )
aSize.setWidth( GetOutDev()->GetCtrlTextWidth( maHelpText ) );
else
aSize.setWidth( GetTextWidth( maHelpText ) );
maTextRect = tools::Rectangle( Point( HELPTEXTMARGIN_QUICK, HELPTEXTMARGIN_QUICK ), aSize );
}
else // HELPWINSTYLE_BALLOON
{
sal_Int32 nCharsInLine;
if (mnHelpWinStyle == HELPWINSTYLE_QUICK)
nCharsInLine = maHelpText.getLength();
else
nCharsInLine = 35 + ((maHelpText.getLength() / 100) * 5);
// average width to have all windows consistent
OUStringBuffer aBuf(nCharsInLine);
comphelper::string::padToLength(aBuf, nCharsInLine, 'x');
tools::Long nWidth = GetTextWidth( OUString::unacquired(aBuf) );
Size aTmpSize( nWidth, 0x7FFFFFFF );
tools::Rectangle aTry1( Point(), aTmpSize );
DrawTextFlags nDrawFlags = DrawTextFlags::MultiLine | DrawTextFlags::WordBreak |
DrawTextFlags::Left | DrawTextFlags::Top;
if ( mnStyle & QuickHelpFlags::CtrlText )
nDrawFlags |= DrawTextFlags::Mnemonic;
tools::Rectangle aTextRect = GetTextRect( aTry1, maHelpText, nDrawFlags );
// get a better width later...
maTextRect = aTextRect;
// safety distance...
maTextRect.SetPos( Point( HELPTEXTMARGIN_BALLOON, HELPTEXTMARGIN_BALLOON ) );
}
Size aSize( CalcOutSize() );
SetOutputSizePixel( aSize );
if (IsVisible())
PaintImmediately();
}
void HelpTextWindow::ImplShow()
{
VclPtr<HelpTextWindow> xWindow( this );
Show( true, ShowFlags::NoActivate );
if( !xWindow->isDisposed() )
PaintImmediately();
}
void HelpTextWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
{
// paint native background
bool bNativeOK = false;
if (rRenderContext.IsNativeControlSupported(ControlType::Tooltip, ControlPart::Entire))
{
tools::Rectangle aCtrlRegion(Point(0, 0), GetOutputSizePixel());
ImplControlValue aControlValue;
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Tooltip, ControlPart::Entire, aCtrlRegion,
ControlState::NONE, aControlValue, OUString());
}
// paint text
if (mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0)
{
if ( mnStyle & QuickHelpFlags::CtrlText )
rRenderContext.DrawCtrlText(maTextRect.TopLeft(), maHelpText);
else
rRenderContext.DrawText(maTextRect.TopLeft(), maHelpText);
}
else // HELPWINSTYLE_BALLOON
{
DrawTextFlags nDrawFlags = DrawTextFlags::MultiLine|DrawTextFlags::WordBreak|
DrawTextFlags::Left|DrawTextFlags::Top;
if (mnStyle & QuickHelpFlags::CtrlText)
nDrawFlags |= DrawTextFlags::Mnemonic;
rRenderContext.DrawText(maTextRect, maHelpText, nDrawFlags);
}
// border
if (bNativeOK)
return;
Size aSz = GetOutputSizePixel();
rRenderContext.DrawRect(tools::Rectangle(Point(), aSz));
if (mnHelpWinStyle == HELPWINSTYLE_BALLOON)
{
aSz.AdjustWidth( -2 );
aSz.AdjustHeight( -2 );
Color aColor(rRenderContext.GetLineColor());
rRenderContext.SetLineColor(COL_GRAY);
rRenderContext.DrawRect(tools::Rectangle(Point(1, 1), aSz));
rRenderContext.SetLineColor(aColor);
}
}
void HelpTextWindow::ShowHelp(bool bNoDelay)
{
sal_uLong nTimeout = 0;
if (!bNoDelay)
{
// In case of ExtendedHelp display help sooner
if ( ImplGetSVHelpData().mbExtHelpMode )
nTimeout = 15;
else
{
if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
nTimeout = HelpSettings::GetTipDelay();
else
nTimeout = HelpSettings::GetBalloonDelay();
}
}
maShowTimer.SetTimeout( nTimeout );
maShowTimer.Start();
}
IMPL_LINK( HelpTextWindow, TimerHdl, Timer*, pTimer, void)
{
if ( pTimer == &maShowTimer )
{
ResetHideTimer();
ImplShow();
}
else
{
SAL_WARN_IF( pTimer != &maHideTimer, "vcl", "HelpTextWindow::TimerHdl with bad Timer" );
ImplDestroyHelpWindow( true );
}
}
Size HelpTextWindow::CalcOutSize() const
{
Size aSz = maTextRect.GetSize();
aSz.AdjustWidth(2*maTextRect.Left() );
aSz.AdjustHeight(2*maTextRect.Top() );
return aSz;
}
void HelpTextWindow::RequestHelp( const HelpEvent& /*rHEvt*/ )
{
// Just to assure that Window::RequestHelp() is not called by
// ShowQuickHelp/ShowBalloonHelp in the HelpTextWindow.
}
OUString HelpTextWindow::GetText() const
{
return maHelpText;
}
void HelpTextWindow::ResetHideTimer()
{
if (mnHelpWinStyle == HELPWINSTYLE_QUICK)
{
// start auto-hide-timer for non-ShowTip windows
if (this == ImplGetSVHelpData().mpHelpWin)
maHideTimer.Start();
}
}
void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
const OUString& rHelpText,
const Point& rScreenPos, const tools::Rectangle& rHelpArea )
{
if (pParent->ImplGetFrame()->ShowTooltip(rHelpText, rHelpArea))
{
//tooltips are handled natively, return early
return;
}
ImplSVHelpData& aHelpData = ImplGetSVHelpData();
if (rHelpText.isEmpty() && !aHelpData.mbRequestingHelp)
return;
bool bNoDelay = false;
if (VclPtr<HelpTextWindow> pHelpWin = aHelpData.mpHelpWin)
{
SAL_WARN_IF( pHelpWin == pParent, "vcl", "HelpInHelp ?!" );
bool bRemoveHelp = (rHelpText.isEmpty() || (pHelpWin->GetWinStyle() != nHelpWinStyle))
&& aHelpData.mbRequestingHelp;
if (!bRemoveHelp && pHelpWin->GetParent() == pParent)
{
bool const bUpdate = (pHelpWin->GetHelpText() != rHelpText) ||
((pHelpWin->GetHelpArea() != rHelpArea) && aHelpData.mbRequestingHelp);
if (bUpdate)
{
pHelpWin->SetHelpText( rHelpText );
// approach mouse position
ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea );
if( pHelpWin->IsVisible() )
pHelpWin->Invalidate();
}
pHelpWin->ResetHideTimer(); // It is shown anew, so prolongate the hide timeout
return;
}
// remove help window if no HelpText or
// other help mode. but keep it if we are scrolling, ie not requesting help
bool bWasVisible = pHelpWin->IsVisible();
if ( bWasVisible )
bNoDelay = true; // display it quickly if we were already in quick help mode
ImplDestroyHelpWindow( bWasVisible );
}
if (rHelpText.isEmpty())
return;
VclPtr<HelpTextWindow> pHelpWin = VclPtr<HelpTextWindow>::Create( pParent, rHelpText, nHelpWinStyle, nStyle );
aHelpData.mpHelpWin = pHelpWin;
pHelpWin->SetHelpArea( rHelpArea );
// positioning
Size aSz = pHelpWin->CalcOutSize();
pHelpWin->SetOutputSizePixel( aSz );
ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea );
// if not called from Window::RequestHelp, then without delay...
if (!bNoDelay)
{
if ( !aHelpData.mbRequestingHelp )
{
bNoDelay = true;
}
else
{
sal_uInt64 nCurTime = tools::Time::GetSystemTicks();
if ( ( nCurTime - aHelpData.mnLastHelpHideTime ) < o3tl::make_unsigned(HelpSettings::GetTipDelay()) )
bNoDelay = true;
}
}
pHelpWin->ShowHelp(bNoDelay);
}
void ImplDestroyHelpWindow( bool bUpdateHideTime )
{
ImplDestroyHelpWindow(ImplGetSVHelpData(), bUpdateHideTime);
}
void ImplDestroyHelpWindow(ImplSVHelpData& rHelpData, bool bUpdateHideTime)
{
VclPtr<HelpTextWindow> pHelpWin = rHelpData.mpHelpWin;
if( pHelpWin )
{
rHelpData.mpHelpWin = nullptr;
rHelpData.mbKeyboardHelp = false;
pHelpWin->Hide();
pHelpWin.disposeAndClear();
if( bUpdateHideTime )
rHelpData.mnLastHelpHideTime = tools::Time::GetSystemTicks();
}
}
void ImplSetHelpWindowPos( vcl::Window* pHelpWin, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
const Point& rPos, const tools::Rectangle& rHelpArea )
{
AbsoluteScreenPixelPoint aPos;
AbsoluteScreenPixelSize aSz( pHelpWin->GetSizePixel() );
AbsoluteScreenPixelRectangle aScreenRect = pHelpWin->ImplGetFrameWindow()->GetDesktopRectPixel();
vcl::Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
// get mouse screen coords
AbsoluteScreenPixelPoint aMousePos(pWindow->OutputToAbsoluteScreenPixel(pWindow->GetPointerPosPixel()));
if ( nStyle & QuickHelpFlags::NoAutoPos )
{
// convert help area to screen coords
AbsoluteScreenPixelRectangle devHelpArea(
pWindow->OutputToAbsoluteScreenPixel( rHelpArea.TopLeft() ),
pWindow->OutputToAbsoluteScreenPixel( rHelpArea.BottomRight() ) );
// which position of the rectangle?
aPos = devHelpArea.Center();
if ( nStyle & QuickHelpFlags::Left )
aPos.setX( devHelpArea.Left() );
else if ( nStyle & QuickHelpFlags::Right )
aPos.setX( devHelpArea.Right() );
if ( nStyle & QuickHelpFlags::Top )
aPos.setY( devHelpArea.Top() );
else if ( nStyle & QuickHelpFlags::Bottom )
aPos.setY( devHelpArea.Bottom() );
// which direction?
if ( nStyle & QuickHelpFlags::Left )
;
else if ( nStyle & QuickHelpFlags::Right )
aPos.AdjustX( -(aSz.Width()) );
else
aPos.AdjustX( -(aSz.Width()/2) );
if ( nStyle & QuickHelpFlags::Top )
;
else if ( nStyle & QuickHelpFlags::Bottom )
aPos.AdjustY( -(aSz.Height()) );
else
aPos.AdjustY( -(aSz.Height()/2) );
}
else
{
aPos = pWindow->OutputToAbsoluteScreenPixel(rPos);
if ( nHelpWinStyle == HELPWINSTYLE_QUICK )
{
tools::Long nScreenHeight = aScreenRect.GetHeight();
aPos.AdjustX( -4 );
if ( aPos.Y() > aScreenRect.Top()+nScreenHeight-(nScreenHeight/4) )
aPos.AdjustY( -(aSz.Height()+4) );
else
aPos.AdjustY(21 );
}
else
{
// If it's the mouse position, move the window slightly
// so the mouse pointer does not cover it
if ( aPos == aMousePos )
{
aPos.AdjustX(12 );
aPos.AdjustY(16 );
}
}
}
if ( aPos.X() < aScreenRect.Left() )
aPos.setX( aScreenRect.Left() );
else if ( ( aPos.X() + aSz.Width() ) > aScreenRect.Right() )
aPos.setX( aScreenRect.Right() - aSz.Width() );
if ( aPos.Y() < aScreenRect.Top() )
aPos.setY( aScreenRect.Top() );
else if ( ( aPos.Y() + aSz.Height() ) > aScreenRect.Bottom() )
aPos.setY( aScreenRect.Bottom() - aSz.Height() );
if( ! (nStyle & QuickHelpFlags::NoEvadePointer) )
{
/* the remark below should be obsolete by now as the helpwindow should
not be focusable, leaving it as a hint. However it is sensible in most
conditions to evade the mouse pointer so the content window is fully visible.
// the popup must not appear under the mouse
// otherwise it would directly be closed due to a focus change...
*/
AbsoluteScreenPixelRectangle aHelpRect( aPos, aSz );
if( aHelpRect.Contains( aMousePos ) )
{
AbsoluteScreenPixelPoint delta(2,2);
AbsoluteScreenPixelPoint aSize( aSz.Width(), aSz.Height() );
AbsoluteScreenPixelPoint aTest( aMousePos - aSize - delta );
if( aTest.X() > aScreenRect.Left() && aTest.Y() > aScreenRect.Top() )
aPos = aTest;
else
aPos = aMousePos + delta;
}
}
Point aPosOut = pWindow->AbsoluteScreenToOutputPixel( aPos );
pHelpWin->SetPosPixel( aPosOut );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'padToLength' is required to be utilized.
↑ V1053 Calling the 'ApplySettings' virtual function indirectly in the constructor may lead to unexpected result at runtime. Check lines: 'help.cxx:265', 'help.cxx:321', 'helpwin.hxx:50'.
↑ V547 Expression 'pHelpWin != nullptr' is always false.