1 #include "widget/wbattery.h"
2 
3 #include <QStyleOption>
4 #include <QStylePainter>
5 
6 #include "moc_wbattery.cpp"
7 #include "util/battery/battery.h"
8 #include "util/math.h"
9 
WBattery(QWidget * parent)10 WBattery::WBattery(QWidget* parent)
11         : WWidget(parent),
12           m_pBattery(Battery::getBattery(this)) {
13     setVisible(false);
14     if (m_pBattery) {
15         connect(m_pBattery.data(),
16                 &Battery::stateChanged,
17                 this,
18                 &WBattery::slotStateChanged);
19     }
20 }
21 
setup(const QDomNode & node,const SkinContext & context)22 void WBattery::setup(const QDomNode& node, const SkinContext& context) {
23     QDomElement backPath = context.selectElement(node, "BackPath");
24     if (!backPath.isNull()) {
25         setPixmap(&m_pPixmapBack,
26                   context.getPixmapSource(backPath),
27                   context.selectScaleMode(backPath, Paintable::TILE),
28                   context.getScaleFactor());
29     }
30 
31     QDomElement chargedPath = context.selectElement(node, "PixmapCharged");
32     if (!chargedPath.isNull()) {
33         setPixmap(&m_pPixmapCharged,
34                   context.getPixmapSource(chargedPath),
35                   context.selectScaleMode(chargedPath, Paintable::TILE),
36                   context.getScaleFactor());
37     }
38 
39     int numberStates = context.selectInt(node, "NumberStates");
40     if (numberStates < 0) {
41         numberStates = 0;
42     }
43 
44     m_chargingPixmaps.resize(numberStates);
45     m_dischargingPixmaps.resize(numberStates);
46 
47     QDomElement pixmapsCharging = context.selectElement(node, "PixmapsCharging");
48     if (!pixmapsCharging.isNull()) {
49         // TODO(XXX) inline SVG support via context.getPixmapSource.
50         QString chargingPath = context.nodeToString(pixmapsCharging);
51         Paintable::DrawMode mode = context.selectScaleMode(pixmapsCharging,
52                                                            Paintable::TILE);
53         for (int i = 0; i < m_chargingPixmaps.size(); ++i) {
54             PixmapSource source = context.getPixmapSource(chargingPath.arg(i));
55             setPixmap(&m_chargingPixmaps[i], source, mode, context.getScaleFactor());
56         }
57     }
58 
59     QDomElement pixmapsDischarging = context.selectElement(node, "PixmapsDischarging");
60     if (!pixmapsDischarging.isNull()) {
61         // TODO(XXX) inline SVG support via context.getPixmapSource.
62         QString dischargingPath = context.nodeToString(pixmapsDischarging);
63         Paintable::DrawMode mode = context.selectScaleMode(pixmapsDischarging,
64                                                            Paintable::TILE);
65         for (int i = 0; i < m_dischargingPixmaps.size(); ++i) {
66             PixmapSource source = context.getPixmapSource(dischargingPath.arg(i));
67             setPixmap(&m_dischargingPixmaps[i], source, mode, context.getScaleFactor());
68         }
69     }
70 
71     if (m_pBattery) {
72         m_pBattery->update();
73     }
74 }
75 
formatMinutes(int minutes)76 QString formatMinutes(int minutes) {
77     if (minutes < 60) {
78         return QObject::tr("%1 minutes").arg(minutes);
79     }
80     return QObject::tr("%1:%2").arg(minutes/60)
81             .arg(minutes%60, 2, 10, QChar('0'));
82 }
83 
pixmapIndexFromPercentage(double dPercentage,int numPixmaps)84 int pixmapIndexFromPercentage(double dPercentage, int numPixmaps) {
85     // See WDisplay::getActivePixmapIndex for more info on this.
86     int result = static_cast<int>(dPercentage / 100.0 * numPixmaps);
87     result = math_min(numPixmaps - 1, math_max(0, result));
88     return result;
89 }
90 
formatTooltip(double dPercentage)91 QString WBattery::formatTooltip(double dPercentage) {
92     return QString::number(dPercentage, 'f', 0) + QStringLiteral("%");
93 }
94 
slotStateChanged()95 void WBattery::slotStateChanged() {
96     int minutesLeft = m_pBattery ? m_pBattery->getMinutesLeft() : 0;
97     Battery::ChargingState chargingState = m_pBattery ?
98             m_pBattery->getChargingState() : Battery::UNKNOWN;
99     double dPercentage = m_pBattery ? m_pBattery->getPercentage() : 0;
100 
101     if (chargingState != Battery::UNKNOWN) {
102         setBaseTooltip(formatTooltip(dPercentage));
103     }
104 
105     m_pCurrentPixmap.clear();
106     switch (chargingState) {
107         case Battery::CHARGING:
108             if (!m_chargingPixmaps.isEmpty()) {
109                 m_pCurrentPixmap = m_chargingPixmaps[
110                     pixmapIndexFromPercentage(dPercentage,
111                                               m_chargingPixmaps.size())];
112             }
113             if (minutesLeft != Battery::TIME_UNKNOWN) {
114                 appendBaseTooltip("\n" + tr("Time until charged: %1")
115                                .arg(formatMinutes(minutesLeft)));
116             }
117             break;
118         case Battery::DISCHARGING:
119             if (!m_dischargingPixmaps.isEmpty()) {
120                 m_pCurrentPixmap = m_dischargingPixmaps[
121                     pixmapIndexFromPercentage(dPercentage,
122                                               m_dischargingPixmaps.size())];
123             }
124             if (minutesLeft != Battery::TIME_UNKNOWN) {
125                 appendBaseTooltip("\n" + tr("Time left: %1")
126                                .arg(formatMinutes(minutesLeft)));
127             }
128             break;
129         case Battery::CHARGED:
130             m_pCurrentPixmap = m_pPixmapCharged;
131             appendBaseTooltip("\n" + tr("Battery fully charged."));
132             break;
133         default:
134             break;
135     }
136     setVisible(chargingState != Battery::UNKNOWN);
137 
138     // call parent's update() to show changes, this should call
139     // QWidget::update()
140     WWidget::update();
141 }
142 
setPixmap(PaintablePointer * ppPixmap,const PixmapSource & source,Paintable::DrawMode mode,double scaleFactor)143 void WBattery::setPixmap(PaintablePointer* ppPixmap, const PixmapSource& source,
144                          Paintable::DrawMode mode, double scaleFactor) {
145     PaintablePointer pPixmap = WPixmapStore::getPaintable(source, mode, scaleFactor);
146     if (pPixmap.isNull() || pPixmap->isNull()) {
147         qDebug() << this << "Error loading pixmap:" << source.getPath();
148     } else {
149         *ppPixmap = pPixmap;
150         if (mode == Paintable::FIXED) {
151             setFixedSize(pPixmap->size());
152         }
153     }
154 }
155 
paintEvent(QPaintEvent *)156 void WBattery::paintEvent(QPaintEvent* /*unused*/) {
157     QStyleOption option;
158     option.initFrom(this);
159     QStylePainter p(this);
160     p.drawPrimitive(QStyle::PE_Widget, option);
161 
162     if (m_pPixmapBack) {
163         m_pPixmapBack->draw(rect(), &p);
164     }
165 
166     if (m_pCurrentPixmap) {
167         m_pCurrentPixmap->draw(rect(), &p);
168     }
169 }
170