tdf#157518: vcl: Introduce vcl control LevelBar
Introduces LevelBar that shares implementation with Progress(Bar). LevelBar is to be as a level indicator, e.g. password strength level. Currently with native backends for gtk and Windows. Currently, except on gtk - the colors of the bar at different levels are hardcoded and not dependent on any kind of themeing. On Windows it follows the styling of progress bar of type "Meter" according to the uxguide: https://learn.microsoft.com/en-us/windows/win32/uxguide/progress-bars#meters Change-Id: Id772cda23615e9582463bf589e4674fd4588c864 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157826 Tested-by: Jenkins Reviewed-by: Sarper Akdemir <sarper.akdemir.extern@allotropia.de>
This commit is contained in:
@@ -92,6 +92,7 @@ enum class ControlType {
|
||||
// application but not for the splash
|
||||
// screen (used in desktop/)
|
||||
IntroProgress = 132,
|
||||
LevelBar = 133,
|
||||
// tool tips
|
||||
Tooltip = 140,
|
||||
// to draw the implemented theme
|
||||
|
||||
@@ -36,7 +36,7 @@ struct ImplStatusItem;
|
||||
void DrawProgress(vcl::Window* pWindow, vcl::RenderContext& rRenderContext, const Point& rPos,
|
||||
tools::Long nOffset, tools::Long nPrgsWidth, tools::Long nPrgsHeight,
|
||||
sal_uInt16 nPercent1, sal_uInt16 nPercent2, sal_uInt16 nPercentCount,
|
||||
const tools::Rectangle& rFramePosSize);
|
||||
const tools::Rectangle& rFramePosSize, ControlType eControlType);
|
||||
|
||||
|
||||
enum class StatusBarItemBits {
|
||||
|
||||
@@ -52,6 +52,13 @@
|
||||
|
||||
class UNLESS_MERGELIBS(VCL_DLLPUBLIC) ProgressBar final : public vcl::Window
|
||||
{
|
||||
public:
|
||||
enum class BarStyle
|
||||
{
|
||||
Progress,
|
||||
Level,
|
||||
};
|
||||
|
||||
private:
|
||||
Point maPos;
|
||||
tools::Long mnPrgsWidth;
|
||||
@@ -59,6 +66,7 @@ private:
|
||||
sal_uInt16 mnPercent;
|
||||
sal_uInt16 mnPercentCount;
|
||||
bool mbCalcNew;
|
||||
BarStyle meBarStyle;
|
||||
|
||||
using Window::ImplInit;
|
||||
SAL_DLLPRIVATE void ImplInit();
|
||||
@@ -66,7 +74,7 @@ private:
|
||||
SAL_DLLPRIVATE void ImplDrawProgress(vcl::RenderContext& rRenderContext, sal_uInt16 nNewPerc);
|
||||
|
||||
public:
|
||||
ProgressBar( vcl::Window* pParent, WinBits nWinBits );
|
||||
ProgressBar( vcl::Window* pParent, WinBits nWinBits, BarStyle eBarStyle );
|
||||
|
||||
virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
|
||||
virtual void Resize() override;
|
||||
|
||||
@@ -1714,6 +1714,14 @@ public:
|
||||
virtual void set_text(const OUString& rText) = 0;
|
||||
};
|
||||
|
||||
class VCL_DLLPUBLIC LevelBar : virtual public Widget
|
||||
{
|
||||
public:
|
||||
/// Sets LevelBar fill percentage.
|
||||
/// @param fPercentage bar's fill percentage, [0.0, 100.0]
|
||||
virtual void set_percentage(double fPercentage) = 0;
|
||||
};
|
||||
|
||||
class VCL_DLLPUBLIC Entry : virtual public Widget
|
||||
{
|
||||
private:
|
||||
@@ -2622,6 +2630,7 @@ public:
|
||||
virtual std::unique_ptr<Entry> weld_entry(const OUString& id) = 0;
|
||||
virtual std::unique_ptr<Scale> weld_scale(const OUString& id) = 0;
|
||||
virtual std::unique_ptr<ProgressBar> weld_progress_bar(const OUString& id) = 0;
|
||||
virtual std::unique_ptr<LevelBar> weld_level_bar(const OUString& id) = 0;
|
||||
virtual std::unique_ptr<Spinner> weld_spinner(const OUString& id) = 0;
|
||||
virtual std::unique_ptr<Image> weld_image(const OUString& id) = 0;
|
||||
virtual std::unique_ptr<Calendar> weld_calendar(const OUString& id) = 0;
|
||||
|
||||
@@ -1781,7 +1781,7 @@ vcl::Window* VCLXToolkit::ImplCreateWindow( rtl::Reference<VCLXWindow>* ppNewCom
|
||||
}
|
||||
else if (aServiceName == "progressbar")
|
||||
{
|
||||
pNewWindow = VclPtr<ProgressBar>::Create( pParent, nWinBits );
|
||||
pNewWindow = VclPtr<ProgressBar>::Create( pParent, nWinBits, ProgressBar::BarStyle::Progress );
|
||||
*ppNewComp = new VCLXProgressBar;
|
||||
}
|
||||
else if (aServiceName == "filecontrol")
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
case ControlType::Radiobutton:
|
||||
case ControlType::ListNode:
|
||||
case ControlType::Slider:
|
||||
case ControlType::LevelBar:
|
||||
case ControlType::Progress:
|
||||
// FIXME: these guys have complex state hidden in ImplControlValue
|
||||
// structs which affects rendering, needs to be a and needs to be
|
||||
|
||||
@@ -91,6 +91,8 @@ public:
|
||||
|
||||
virtual std::unique_ptr<weld::ProgressBar> weld_progress_bar(const OUString& id) override;
|
||||
|
||||
virtual std::unique_ptr<weld::LevelBar> weld_level_bar(const OUString& id) override;
|
||||
|
||||
virtual std::unique_ptr<weld::Spinner> weld_spinner(const OUString& id) override;
|
||||
|
||||
virtual std::unique_ptr<weld::Image> weld_image(const OUString& id) override;
|
||||
|
||||
@@ -3302,6 +3302,24 @@ public:
|
||||
|
||||
virtual void set_text(const OUString& rText) override { m_xProgressBar->SetText(rText); }
|
||||
};
|
||||
|
||||
class SalInstanceLevelBar : public SalInstanceWidget, public virtual weld::LevelBar
|
||||
{
|
||||
private:
|
||||
VclPtr<::ProgressBar> m_xLevelBar;
|
||||
|
||||
public:
|
||||
SalInstanceLevelBar(::ProgressBar* pLevelBar, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
|
||||
: SalInstanceWidget(pLevelBar, pBuilder, bTakeOwnership)
|
||||
, m_xLevelBar(pLevelBar)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void set_percentage(double fPercentage) override
|
||||
{
|
||||
m_xLevelBar->SetValue(static_cast<sal_uInt16>(fPercentage));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(SalInstanceCalendar, SelectHdl, ::Calendar*, void)
|
||||
@@ -7212,6 +7230,12 @@ std::unique_ptr<weld::ProgressBar> SalInstanceBuilder::weld_progress_bar(const O
|
||||
return pProgress ? std::make_unique<SalInstanceProgressBar>(pProgress, this, false) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<weld::LevelBar> SalInstanceBuilder::weld_level_bar(const OUString& id)
|
||||
{
|
||||
::ProgressBar* pLevel = m_xBuilder->get<::ProgressBar>(id);
|
||||
return pLevel ? std::make_unique<SalInstanceLevelBar>(pLevel, this, false) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<weld::Spinner> SalInstanceBuilder::weld_spinner(const OUString& id)
|
||||
{
|
||||
Throbber* pThrobber = m_xBuilder->get<Throbber>(id);
|
||||
|
||||
@@ -39,12 +39,15 @@ void ProgressBar::ImplInit()
|
||||
ImplInitSettings( true, true, true );
|
||||
}
|
||||
|
||||
static WinBits clearProgressBarBorder( vcl::Window const * pParent, WinBits nOrgStyle )
|
||||
static WinBits clearProgressBarBorder( vcl::Window const * pParent, WinBits nOrgStyle, ProgressBar::BarStyle eBarStyle )
|
||||
{
|
||||
WinBits nOutStyle = nOrgStyle;
|
||||
if( pParent && (nOrgStyle & WB_BORDER) != 0 )
|
||||
{
|
||||
if( pParent->IsNativeControlSupported( ControlType::Progress, ControlPart::Entire ) )
|
||||
if (pParent->IsNativeControlSupported(eBarStyle == ProgressBar::BarStyle::Progress
|
||||
? ControlType::Progress
|
||||
: ControlType::LevelBar,
|
||||
ControlPart::Entire))
|
||||
nOutStyle &= WB_BORDER;
|
||||
}
|
||||
return nOutStyle;
|
||||
@@ -52,11 +55,12 @@ static WinBits clearProgressBarBorder( vcl::Window const * pParent, WinBits nOrg
|
||||
|
||||
Size ProgressBar::GetOptimalSize() const
|
||||
{
|
||||
return Size(150, 20);
|
||||
return meBarStyle == BarStyle::Progress ? Size(150, 20) : Size(150,10);
|
||||
}
|
||||
|
||||
ProgressBar::ProgressBar( vcl::Window* pParent, WinBits nWinStyle ) :
|
||||
Window( pParent, clearProgressBarBorder( pParent, nWinStyle ) )
|
||||
ProgressBar::ProgressBar( vcl::Window* pParent, WinBits nWinStyle, BarStyle eBarStyle ) :
|
||||
Window( pParent, clearProgressBarBorder( pParent, nWinStyle, eBarStyle ) ),
|
||||
meBarStyle(eBarStyle)
|
||||
{
|
||||
SetOutputSizePixel( GetOptimalSize() );
|
||||
ImplInit();
|
||||
@@ -74,8 +78,10 @@ void ProgressBar::ImplInitSettings( bool bFont,
|
||||
|
||||
if ( bBackground )
|
||||
{
|
||||
if( !IsControlBackground() &&
|
||||
IsNativeControlSupported( ControlType::Progress, ControlPart::Entire ) )
|
||||
if (!IsControlBackground()
|
||||
&& IsNativeControlSupported(meBarStyle == BarStyle::Progress ? ControlType::Progress
|
||||
: ControlType::LevelBar,
|
||||
ControlPart::Entire))
|
||||
{
|
||||
if( GetStyle() & WB_BORDER )
|
||||
SetBorderStyle( WindowBorderStyle::REMOVEBORDER );
|
||||
@@ -144,9 +150,10 @@ void ProgressBar::ImplDrawProgress(vcl::RenderContext& rRenderContext, sal_uInt1
|
||||
maPos.setX( (aSize.Width() - nMaxWidth) / 2 );
|
||||
}
|
||||
|
||||
::DrawProgress(this, rRenderContext, maPos, PROGRESSBAR_OFFSET, mnPrgsWidth, mnPrgsHeight,
|
||||
/*nPercent1=*/0, nNewPerc * 100, mnPercentCount,
|
||||
tools::Rectangle(Point(), GetSizePixel()));
|
||||
::DrawProgress(
|
||||
this, rRenderContext, maPos, PROGRESSBAR_OFFSET, mnPrgsWidth, mnPrgsHeight,
|
||||
/*nPercent1=*/0, nNewPerc * 100, mnPercentCount, tools::Rectangle(Point(), GetSizePixel()),
|
||||
meBarStyle == BarStyle::Progress ? ControlType::Progress : ControlType::LevelBar);
|
||||
}
|
||||
|
||||
void ProgressBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
|
||||
|
||||
@@ -188,6 +188,7 @@ bool FileDefinitionWidgetDraw::isNativeControlSupported(ControlType eType, Contr
|
||||
case ControlType::MenuPopup:
|
||||
return true;
|
||||
case ControlType::Progress:
|
||||
case ControlType::LevelBar:
|
||||
return true;
|
||||
case ControlType::IntroProgress:
|
||||
return false;
|
||||
@@ -750,6 +751,7 @@ bool FileDefinitionWidgetDraw::drawNativeControl(ControlType eType, ControlPart
|
||||
}
|
||||
break;
|
||||
case ControlType::Progress:
|
||||
case ControlType::LevelBar:
|
||||
{
|
||||
bOK = resolveDefinition(eType, ePart, eState, rValue, nX, nY, nWidth, nHeight);
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
|
||||
{ "slider", ControlType::Slider },
|
||||
{ "fixedline", ControlType::Fixedline },
|
||||
{ "progress", ControlType::Progress },
|
||||
{ "levelbar", ControlType::LevelBar },
|
||||
{ "tabitem", ControlType::TabItem },
|
||||
{ "tabheader", ControlType::TabHeader },
|
||||
{ "tabpane", ControlType::TabPane },
|
||||
|
||||
@@ -2025,7 +2025,13 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OUString
|
||||
{
|
||||
extractAdjustmentToMap(id, rMap, m_pParserState->m_aScrollAdjustmentMaps);
|
||||
bVertical = extractOrientation(rMap);
|
||||
xWindow = VclPtr<ProgressBar>::Create(pParent, bVertical ? WB_VERT : WB_HORZ);
|
||||
xWindow = VclPtr<ProgressBar>::Create(pParent, bVertical ? WB_VERT : WB_HORZ, ProgressBar::BarStyle::Progress);
|
||||
}
|
||||
else if (name == "GtkLevelBar")
|
||||
{
|
||||
extractAdjustmentToMap(id, rMap, m_pParserState->m_aScrollAdjustmentMaps);
|
||||
bVertical = extractOrientation(rMap);
|
||||
xWindow = VclPtr<ProgressBar>::Create(pParent, bVertical ? WB_VERT : WB_HORZ, ProgressBar::BarStyle::Level);
|
||||
}
|
||||
else if (name == "GtkScrolledWindow")
|
||||
{
|
||||
|
||||
@@ -474,9 +474,9 @@ void StatusBar::ImplDrawItem(vcl::RenderContext& rRenderContext, bool bOffScreen
|
||||
void DrawProgress(vcl::Window* pWindow, vcl::RenderContext& rRenderContext, const Point& rPos,
|
||||
tools::Long nOffset, tools::Long nPrgsWidth, tools::Long nPrgsHeight,
|
||||
sal_uInt16 nPercent1, sal_uInt16 nPercent2, sal_uInt16 nPercentCount,
|
||||
const tools::Rectangle& rFramePosSize)
|
||||
const tools::Rectangle& rFramePosSize, ControlType eControlType)
|
||||
{
|
||||
if (rRenderContext.IsNativeControlSupported(ControlType::Progress, ControlPart::Entire))
|
||||
if (rRenderContext.IsNativeControlSupported(eControlType, ControlPart::Entire))
|
||||
{
|
||||
bool bNeedErase = ImplGetSVData()->maNWFData.mbProgressNeedsErase;
|
||||
|
||||
@@ -514,7 +514,7 @@ void DrawProgress(vcl::Window* pWindow, vcl::RenderContext& rRenderContext, cons
|
||||
rRenderContext.IntersectClipRegion(rFramePosSize);
|
||||
}
|
||||
|
||||
bool bNativeOK = rRenderContext.DrawNativeControl(ControlType::Progress, ControlPart::Entire, aControlRegion,
|
||||
bool bNativeOK = rRenderContext.DrawNativeControl(eControlType, ControlPart::Entire, aControlRegion,
|
||||
ControlState::ENABLED, aValue, OUString());
|
||||
if (bNeedErase)
|
||||
rRenderContext.Pop();
|
||||
@@ -522,6 +522,18 @@ void DrawProgress(vcl::Window* pWindow, vcl::RenderContext& rRenderContext, cons
|
||||
return;
|
||||
}
|
||||
|
||||
if (eControlType == ControlType::LevelBar)
|
||||
{
|
||||
if (nPercent2 < 2500)
|
||||
rRenderContext.SetFillColor({ 0xFF0000 });
|
||||
else if (nPercent2 < 5000)
|
||||
rRenderContext.SetFillColor({ 0xFFFF00 });
|
||||
else if (nPercent2 < 7500)
|
||||
rRenderContext.SetFillColor({ 0x0000FF });
|
||||
else
|
||||
rRenderContext.SetFillColor({ 0x00FF00 });
|
||||
}
|
||||
|
||||
// precompute values
|
||||
sal_uInt16 nPerc1 = nPercent1 / nPercentCount;
|
||||
sal_uInt16 nPerc2 = nPercent2 / nPercentCount;
|
||||
@@ -570,7 +582,7 @@ void DrawProgress(vcl::Window* pWindow, vcl::RenderContext& rRenderContext, cons
|
||||
while (nPerc1 < nPerc2);
|
||||
|
||||
// if greater than 100%, set rectangle to blink
|
||||
if (nPercent2 > 10000)
|
||||
if (nPercent2 > 10000 && eControlType == ControlType::Progress)
|
||||
{
|
||||
// define on/off status
|
||||
if (((nPercent2 / nPercentCount) & 0x01) == (nPercentCount & 0x01))
|
||||
@@ -603,7 +615,7 @@ void StatusBar::ImplDrawProgress(vcl::RenderContext& rRenderContext, sal_uInt16
|
||||
nPrgsHeight = maPrgsFrameRect.GetHeight();
|
||||
}
|
||||
DrawProgress(this, rRenderContext, aPos, mnPrgsSize / 2, mnPrgsSize, nPrgsHeight,
|
||||
0, nPercent2 * 100, mnPercentCount, maPrgsFrameRect);
|
||||
0, nPercent2 * 100, mnPercentCount, maPrgsFrameRect, ControlType::Progress);
|
||||
}
|
||||
|
||||
void StatusBar::ImplCalcProgressRect()
|
||||
|
||||
@@ -12843,6 +12843,25 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class GtkInstanceLevelBar : public GtkInstanceWidget, public virtual weld::LevelBar
|
||||
{
|
||||
private:
|
||||
GtkLevelBar* m_pLevelBar;
|
||||
|
||||
public:
|
||||
GtkInstanceLevelBar(GtkLevelBar* pLevelBar, GtkInstanceBuilder* pBuilder,
|
||||
bool bTakeOwnership)
|
||||
: GtkInstanceWidget(GTK_WIDGET(pLevelBar), pBuilder, bTakeOwnership)
|
||||
, m_pLevelBar(pLevelBar)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void set_percentage(double fPercentage) override
|
||||
{
|
||||
gtk_level_bar_set_value(m_pLevelBar, fPercentage / 100.0);
|
||||
}
|
||||
};
|
||||
|
||||
class GtkInstanceSpinner : public GtkInstanceWidget, public virtual weld::Spinner
|
||||
{
|
||||
private:
|
||||
@@ -24341,6 +24360,16 @@ public:
|
||||
return std::make_unique<GtkInstanceProgressBar>(pProgressBar, this, false);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<weld::LevelBar> weld_level_bar(const OUString& id) override
|
||||
{
|
||||
GtkLevelBar* pLevelBar = GTK_LEVEL_BAR(gtk_builder_get_object(
|
||||
m_pBuilder, OUStringToOString(id, RTL_TEXTENCODING_UTF8).getStr()));
|
||||
if (!pLevelBar)
|
||||
return nullptr;
|
||||
auto_add_parentless_widgets_to_container(GTK_WIDGET(pLevelBar));
|
||||
return std::make_unique<GtkInstanceLevelBar>(pLevelBar, this, false);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<weld::Spinner> weld_spinner(const OUString &id) override
|
||||
{
|
||||
GtkSpinner* pSpinner = GTK_SPINNER(gtk_builder_get_object(m_pBuilder, OUStringToOString(id, RTL_TEXTENCODING_UTF8).getStr()));
|
||||
|
||||
@@ -190,6 +190,7 @@ bool WinSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nP
|
||||
}
|
||||
break;
|
||||
case ControlType::Progress:
|
||||
case ControlType::LevelBar:
|
||||
if( nPart == ControlPart::Entire )
|
||||
hTheme = getThemeHandle(mhWnd, L"Progress", mWinSalGraphicsImplBase);
|
||||
break;
|
||||
@@ -1003,12 +1004,19 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
|
||||
}
|
||||
}
|
||||
|
||||
if( nType == ControlType::Progress )
|
||||
if( nType == ControlType::Progress || nType == ControlType::LevelBar )
|
||||
{
|
||||
if( nPart != ControlPart::Entire )
|
||||
return false;
|
||||
|
||||
if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) )
|
||||
int nPartIdBackground = PP_BAR;
|
||||
if( nType == ControlType::LevelBar )
|
||||
{
|
||||
nPartIdBackground = PP_TRANSPARENTBAR;
|
||||
iState = PBBS_PARTIAL;
|
||||
}
|
||||
|
||||
if( ! ImplDrawTheme( hTheme, hDC, nPartIdBackground, iState, rc, aCaption) )
|
||||
return false;
|
||||
RECT aProgressRect = rc;
|
||||
if( GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
|
||||
@@ -1022,6 +1030,26 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
|
||||
else
|
||||
aProgressRect.right = aProgressRect.left + nProgressWidth;
|
||||
|
||||
if (nType == ControlType::LevelBar)
|
||||
{
|
||||
const auto nPercentage
|
||||
= aValue.getNumericVal() * 100 / std::max(LONG{ 1 }, (rc.right - rc.left));
|
||||
|
||||
COLORREF aBrushColor{};
|
||||
if (nPercentage < 25)
|
||||
aBrushColor = RGB(255, 0, 0);
|
||||
else if (nPercentage < 50)
|
||||
aBrushColor = RGB(255, 255, 0);
|
||||
else if (nPercentage < 75)
|
||||
aBrushColor = RGB(0, 0, 255);
|
||||
else
|
||||
aBrushColor = RGB(0, 255, 0);
|
||||
|
||||
ScopedHBRUSH hBrush(CreateSolidBrush(aBrushColor));
|
||||
FillRect(hDC, &aProgressRect, hBrush.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
|
||||
}
|
||||
|
||||
@@ -1272,6 +1300,7 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
|
||||
}
|
||||
break;
|
||||
case ControlType::Progress:
|
||||
case ControlType::LevelBar:
|
||||
if( nPart == ControlPart::Entire )
|
||||
hTheme = getThemeHandle(mhWnd, L"Progress", mWinSalGraphicsImplBase);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user