KWidgetsAddons

kcapacitybar.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2008 Rafael Fernández López <ereslibre@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kcapacitybar.h"
9#include "kstyleextensions.h"
10
11#include <math.h>
12
13#include <QLinearGradient>
14#include <QPaintEvent>
15#include <QPainter>
16#include <QPainterPath>
17#include <QStyle>
18#include <QStyleOptionProgressBar>
19
20#define ROUND_MARGIN 6
21#define VERTICAL_SPACING 1
22
23static const int LightShade = 100;
24static const int MidShade = 200;
25static const int DarkShade = 300;
26
27class KCapacityBarPrivate
28{
29public:
30 KCapacityBarPrivate(KCapacityBar::DrawTextMode drawTextMode)
31 : drawTextMode(drawTextMode)
32 {
33 }
34
35 QString text;
36 int value = 0;
37 bool fillFullBlocks = true;
38 bool continuous = true;
39 int barHeight = 12;
40 Qt::Alignment horizontalTextAlignment = Qt::AlignCenter;
42
43 KCapacityBar::DrawTextMode drawTextMode;
44};
45
47 : KCapacityBar(DrawTextOutline, parent)
48{
49}
50
52 : QWidget(parent)
53 , d(new KCapacityBarPrivate(drawTextMode))
54{
55 d->ce_capacityBar = KStyleExtensions::customControlElement(QStringLiteral("CE_CapacityBar"), this);
56}
57
58KCapacityBar::~KCapacityBar() = default;
59
61{
62 d->value = value;
63 update();
64}
65
66int KCapacityBar::value() const
67{
68 return d->value;
69}
70
72{
73 bool updateGeom = d->text.isEmpty() || text.isEmpty();
74 d->text = text;
75 if (updateGeom) {
77 }
78
79#ifndef QT_NO_ACCESSIBILITY
81#endif
82
83 update();
84}
85
86QString KCapacityBar::text() const
87{
88 return d->text;
89}
90
91void KCapacityBar::setFillFullBlocks(bool fillFullBlocks)
92{
93 d->fillFullBlocks = fillFullBlocks;
94 update();
95}
96
97bool KCapacityBar::fillFullBlocks() const
98{
99 return d->fillFullBlocks;
100}
101
102void KCapacityBar::setContinuous(bool continuous)
103{
104 d->continuous = continuous;
105 update();
106}
107
108bool KCapacityBar::continuous() const
109{
110 return d->continuous;
111}
112
113void KCapacityBar::setBarHeight(int barHeight)
114{
115 // automatically convert odd values to even. This will make the bar look
116 // better.
117 d->barHeight = (barHeight % 2) ? barHeight + 1 : barHeight;
119}
120
121int KCapacityBar::barHeight() const
122{
123 return d->barHeight;
124}
125
127{
128 Qt::Alignment alignment = horizontalTextAlignment;
129
130 // if the value came with any vertical alignment flag, remove it.
131 alignment &= ~Qt::AlignTop;
132 alignment &= ~Qt::AlignBottom;
133 alignment &= ~Qt::AlignVCenter;
134
135 d->horizontalTextAlignment = alignment;
136 update();
137}
138
139Qt::Alignment KCapacityBar::horizontalTextAlignment() const
140{
141 return d->horizontalTextAlignment;
142}
143
145{
146 d->drawTextMode = mode;
147 update();
148}
149
150KCapacityBar::DrawTextMode KCapacityBar::drawTextMode() const
151{
152 return d->drawTextMode;
153}
154
156{
157 if (d->ce_capacityBar) {
159 opt.initFrom(this);
160 opt.rect = rect;
161 opt.minimum = 0;
162 opt.maximum = 100;
163 opt.progress = d->value;
164 opt.state |= QStyle::State_Horizontal;
165 opt.text = d->text;
166 opt.textAlignment = Qt::AlignCenter;
167 opt.textVisible = !d->text.isEmpty();
168 style()->drawControl(d->ce_capacityBar, &opt, p, this);
169
170 return;
171 }
172
174
175 p->save();
176
177 QRect drawRect(rect);
178
179 if (d->drawTextMode == DrawTextOutline) {
180 drawRect.setHeight(d->barHeight);
181 }
182
183 QPainterPath outline;
184 outline.moveTo(rect.left() + ROUND_MARGIN / 4 + 1, rect.top());
185 outline.lineTo(rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1, rect.top());
186 outline.quadTo(rect.left() + drawRect.width() + ROUND_MARGIN / 2,
187 drawRect.height() / 2 + rect.top(),
188 rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1,
189 drawRect.height() + rect.top());
190 outline.lineTo(rect.left() + ROUND_MARGIN / 4 + 1, drawRect.height() + rect.top());
191 outline.quadTo(-ROUND_MARGIN / 2 + rect.left(), drawRect.height() / 2 + rect.top(), rect.left() + ROUND_MARGIN / 4 + 1, rect.top());
192 const QColor fillColor = palette().window().color().darker(DarkShade);
193 p->fillPath(outline, QColor(fillColor.red(), fillColor.green(), fillColor.blue(), 50));
194
195 QRadialGradient bottomGradient(QPointF(rect.width() / 2, drawRect.bottom() + 1), rect.width() / 2);
196 bottomGradient.setColorAt(0, palette().window().color().darker(LightShade));
197 bottomGradient.setColorAt(1, Qt::transparent);
198 p->fillRect(QRect(rect.left(), drawRect.bottom() + rect.top(), rect.width(), 1), bottomGradient);
199
200 p->translate(rect.left() + 2, rect.top() + 1);
201
202 drawRect.setWidth(drawRect.width() - 4);
203 drawRect.setHeight(drawRect.height() - 2);
204
205 QPainterPath path;
206 path.moveTo(ROUND_MARGIN / 4, 0);
207 path.lineTo(drawRect.width() - ROUND_MARGIN / 4, 0);
208 path.quadTo(drawRect.width() + ROUND_MARGIN / 2, drawRect.height() / 2, drawRect.width() - ROUND_MARGIN / 4, drawRect.height());
209 path.lineTo(ROUND_MARGIN / 4, drawRect.height());
210 path.quadTo(-ROUND_MARGIN / 2, drawRect.height() / 2, ROUND_MARGIN / 4, 0);
211
212 QLinearGradient linearGradient(0, 0, 0, drawRect.height());
213 linearGradient.setColorAt(0.5, palette().window().color().darker(MidShade));
214 linearGradient.setColorAt(1, palette().window().color().darker(LightShade));
215 p->fillPath(path, linearGradient);
216
218 p->setPen(Qt::NoPen);
219
220 if (d->continuous || !d->fillFullBlocks) {
221 int start = (layoutDirection() == Qt::LeftToRight) ? -1 : (drawRect.width() + 2) - (drawRect.width() + 2) * (d->value / 100.0);
222
223 p->setClipRect(QRect(start, 0, (drawRect.width() + 2) * (d->value / 100.0), drawRect.height()), Qt::IntersectClip);
224 }
225
226 int left = (layoutDirection() == Qt::LeftToRight) ? 0 : drawRect.width();
227
228 int right = (layoutDirection() == Qt::LeftToRight) ? drawRect.width() : 0;
229
230 int roundMargin = (layoutDirection() == Qt::LeftToRight) ? ROUND_MARGIN : -ROUND_MARGIN;
231
232 int spacing = 2;
233 int verticalSpacing = VERTICAL_SPACING;
234 int slotWidth = 6;
235 int start = roundMargin / 4;
236
237 QPainterPath internalBar;
238 internalBar.moveTo(left + roundMargin / 4, 0);
239 internalBar.lineTo(right - roundMargin / 4, 0);
240 internalBar.quadTo(right + roundMargin / 2, drawRect.height() / 2, right - roundMargin / 4, drawRect.height());
241 internalBar.lineTo(left + roundMargin / 4, drawRect.height());
242 internalBar.quadTo(left - roundMargin / 2, drawRect.height() / 2, left + roundMargin / 4, 0);
243
244 QLinearGradient fillInternalBar(left, 0, right, 0);
245 fillInternalBar.setColorAt(0, palette().window().color().darker(MidShade));
246 fillInternalBar.setColorAt(0.5, palette().window().color().darker(LightShade));
247 fillInternalBar.setColorAt(1, palette().window().color().darker(MidShade));
248
249 if (d->drawTextMode == KCapacityBar::DrawTextInline) {
250 p->save();
251 p->setOpacity(p->opacity() * 0.7);
252 }
253
254 if (!d->continuous) {
255 int numSlots = (drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) / (slotWidth + spacing);
256 int stopSlot = floor((numSlots + 2) * (d->value / 100.0));
257
258 int plusOffset = d->fillFullBlocks ? ((drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) - (numSlots * (slotWidth + spacing))) / 2.0 : 0;
259
260 if (!d->fillFullBlocks || stopSlot) {
261 QPainterPath firstSlot;
262 firstSlot.moveTo(left + roundMargin / 4, verticalSpacing);
263 firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, verticalSpacing);
264 firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, drawRect.height() - verticalSpacing);
265 firstSlot.lineTo(left + roundMargin / 4, drawRect.height() - verticalSpacing);
266 firstSlot.quadTo(left, drawRect.height() / 2, left + roundMargin / 4, verticalSpacing);
267 p->fillPath(firstSlot, fillInternalBar);
268 start += slotWidth + spacing + plusOffset;
269
270 bool stopped = false;
271 for (int i = 0; i < numSlots + 1; i++) {
272 if (d->fillFullBlocks && (i == (stopSlot + 1))) {
273 stopped = true;
274 break;
275 }
276 p->fillRect(QRect(rect.left() + start, rect.top() + verticalSpacing, slotWidth, drawRect.height() - verticalSpacing * 2), fillInternalBar);
277 start += slotWidth + spacing;
278 }
279
280 if (!d->fillFullBlocks || (!stopped && (stopSlot != (numSlots + 1)) && (stopSlot != numSlots))) {
281 QPainterPath lastSlot;
282 lastSlot.moveTo(start, verticalSpacing);
283 lastSlot.lineTo(start, drawRect.height() - verticalSpacing);
284 lastSlot.lineTo(start + slotWidth + plusOffset, drawRect.height() - verticalSpacing);
285 lastSlot.quadTo(start + roundMargin, drawRect.height() / 2, start + slotWidth + plusOffset, verticalSpacing);
286 lastSlot.lineTo(start, verticalSpacing);
287 p->fillPath(lastSlot, fillInternalBar);
288 }
289 }
290 } else {
291 p->fillPath(internalBar, fillInternalBar);
292 }
293
294 if (d->drawTextMode == KCapacityBar::DrawTextInline) {
295 p->restore();
296 }
297
298 p->save();
299 p->setClipping(false);
300 QRadialGradient topGradient(QPointF(rect.width() / 2, drawRect.top()), rect.width() / 2);
301 const QColor fillTopColor = palette().window().color().darker(LightShade);
302 topGradient.setColorAt(0, QColor(fillTopColor.red(), fillTopColor.green(), fillTopColor.blue(), 127));
303 topGradient.setColorAt(1, Qt::transparent);
304 p->fillRect(QRect(rect.left(), rect.top() + drawRect.top(), rect.width(), 2), topGradient);
305 p->restore();
306
307 p->save();
308 p->setClipRect(QRect(-1, 0, rect.width(), drawRect.height() / 2), Qt::ReplaceClip);
309 QLinearGradient glassGradient(0, -5, 0, drawRect.height());
310 const QColor fillGlassColor = palette().base().color();
311 glassGradient.setColorAt(0, QColor(fillGlassColor.red(), fillGlassColor.green(), fillGlassColor.blue(), 255));
312 glassGradient.setColorAt(1, Qt::transparent);
313 p->fillPath(internalBar, glassGradient);
314 p->restore();
315
316 p->restore();
317
318 if (d->drawTextMode == KCapacityBar::DrawTextInline) {
319 QRect rect(drawRect);
320 rect.setHeight(rect.height() + 4);
321 p->drawText(rect, Qt::AlignCenter, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width() - 2 * ROUND_MARGIN));
322 } else {
323 p->drawText(rect, Qt::AlignBottom | d->horizontalTextAlignment, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width()));
324 }
325}
326
327QSize KCapacityBar::minimumSizeHint() const
328{
329 int width = fontMetrics().boundingRect(d->text).width() + ((d->drawTextMode == KCapacityBar::DrawTextInline) ? ROUND_MARGIN * 2 : 0);
330
331 int height = (d->drawTextMode == KCapacityBar::DrawTextInline) ? qMax(fontMetrics().height(), d->barHeight)
332 : (d->text.isEmpty() ? 0 : fontMetrics().height() + VERTICAL_SPACING * 2) + d->barHeight;
333
334 if (height % 2) {
335 height++;
336 }
337
338 return QSize(width, height);
339}
340
341void KCapacityBar::paintEvent(QPaintEvent *event)
342{
343 QPainter p(this);
344 p.setClipRect(event->rect());
346 p.end();
347}
348
349void KCapacityBar::changeEvent(QEvent *event)
350{
352 if (event->type() == QEvent::StyleChange) {
353 d->ce_capacityBar = KStyleExtensions::customControlElement(QStringLiteral("CE_CapacityBar"), this);
354 }
355}
356
357#include "moc_kcapacitybar.cpp"
This widget shows a bar which is filled to show the level of usage of a certain device.
void setFillFullBlocks(bool fillFullBlocks)
When the capacity bar is non-continuous, sets whether the last block shown should be drawn full or ca...
void drawCapacityBar(QPainter *p, const QRect &rect) const
This method allows you to draw the widget, directly, for example on item delegates.
void setValue(int value)
Capacity bar fill value.
void setContinuous(bool continuous)
Sets whether the fill of the capacity bar should be continuous or in block mode.
void setHorizontalTextAlignment(Qt::Alignment textAlignment)
If the capacity bar is in outline text mode, draw the text with textAlignment alignment.
void setBarHeight(int barHeight)
Sets the height (in pixels) of the bar.
KCapacityBar(QWidget *parent=nullptr)
Constructs a capacity bar with DrawTextOutline as draw text mode.
void setDrawTextMode(DrawTextMode mode)
Set the way text is drawn if any is set.
void setText(const QString &text)
Sets the text for the capacity bar.
@ DrawTextOutline
If any text set, draw it out of the capacity bar.
@ DrawTextInline
If any text set, draw it into the capacity bar.
Q_SCRIPTABLE Q_NOREPLY void start()
QStyle::ControlElement customControlElement(const QString &element, const QWidget *widget)
Resolve a dynamic QStyle::ControlElement for eg.
int blue() const const
QColor darker(int factor) const const
int green() const const
int red() const const
QRect boundingRect(QChar ch) const const
void setColorAt(qreal position, const QColor &color)
void drawText(const QPoint &position, const QString &text)
void fillPath(const QPainterPath &path, const QBrush &brush)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
qreal opacity() const const
void restore()
void save()
void setBrush(Qt::BrushStyle style)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void setClipping(bool enable)
void setOpacity(qreal opacity)
void setPen(Qt::PenStyle style)
void setRenderHints(RenderHints hints, bool on)
void translate(const QPoint &offset)
void lineTo(const QPointF &endPoint)
void moveTo(const QPointF &point)
void quadTo(const QPointF &c, const QPointF &endPoint)
int bottom() const const
int height() const const
void setHeight(int height)
void setWidth(int width)
int top() const const
int width() const const
bool isEmpty() const const
State_Horizontal
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
void initFrom(const QWidget *widget)
typedef Alignment
IntersectClip
transparent
LeftToRight
ElideRight
void setAccessibleName(const QString &name)
virtual void changeEvent(QEvent *event)
QRect contentsRect() const const
virtual bool event(QEvent *event) override
QFontMetrics fontMetrics() const const
QStyle * style() const const
void update()
void updateGeometry()
QWidget * window() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:51 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.