mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 10:52:53 +00:00
405 lines
14 KiB
C++
405 lines
14 KiB
C++
/*
|
|
* Copyright (C) 2007, 2008 Petri Damsten <damu@iki.fi>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Library General Public License as
|
|
* published by the Free Software Foundation; either version 2, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "lcd.h"
|
|
#include <QPainter>
|
|
#include <QDir>
|
|
#include <QGraphicsLinearLayout>
|
|
#include <QtGui/qgraphicssceneevent.h>
|
|
|
|
#include <QtXml/qdom.h>
|
|
#include <QCursor>
|
|
#include <KDebug>
|
|
#include <KDecompressor>
|
|
#include <Plasma/Theme>
|
|
#include <Plasma/Svg>
|
|
|
|
class LCD::Private
|
|
{
|
|
public:
|
|
LCD* l;
|
|
QString content;
|
|
Plasma::Svg svg;
|
|
bool dirty;
|
|
QPixmap img;
|
|
QStringList items;
|
|
QMap<QString, QStringList> groups;
|
|
QHash<QString, QDomText> texts;
|
|
QStringList clickable;
|
|
QDomDocument doc;
|
|
|
|
static const QString A;
|
|
static const QString B;
|
|
static const QString C;
|
|
static const QString D;
|
|
static const QString E;
|
|
static const QString F;
|
|
static const QString G;
|
|
static const QString DP;
|
|
static QMap<QChar, QStringList> sevenSegmentDigits;
|
|
qreal xScale;
|
|
qreal yScale;
|
|
|
|
Private(LCD* lcd) : l(lcd), dirty(false), xScale(1.0), yScale(1.0)
|
|
{
|
|
// http://en.wikipedia.org/wiki/Seven-segment_display_character_representations
|
|
if (sevenSegmentDigits.isEmpty()) {
|
|
sevenSegmentDigits[' '] = QStringList();
|
|
sevenSegmentDigits['-'] = QStringList() << G;
|
|
sevenSegmentDigits['0'] = QStringList() << A << B << C << D << E << F;
|
|
sevenSegmentDigits['1'] = QStringList() << B << C;
|
|
sevenSegmentDigits['2'] = QStringList() << A << B << D << E << G;
|
|
sevenSegmentDigits['3'] = QStringList() << A << B << C << D << G;
|
|
sevenSegmentDigits['4'] = QStringList() << B << C << F << G;
|
|
sevenSegmentDigits['5'] = QStringList() << A << C << D << F << G;
|
|
sevenSegmentDigits['6'] = QStringList() << A << C << D << E << F << G;
|
|
sevenSegmentDigits['7'] = QStringList() << A << B << C;
|
|
sevenSegmentDigits['8'] = QStringList() << A << B << C << D << E << F << G;
|
|
sevenSegmentDigits['9'] = QStringList() << A << B << C << D << F << G;
|
|
sevenSegmentDigits['A'] = QStringList() << A << B << C << E << F << G;
|
|
sevenSegmentDigits['B'] = QStringList() << A << B << C << D << E << F << G;
|
|
sevenSegmentDigits['C'] = QStringList() << A << D << E << F;
|
|
sevenSegmentDigits['D'] = QStringList() << A << B << C << D << E << F;
|
|
sevenSegmentDigits['E'] = QStringList() << A << D << E << F << G;
|
|
sevenSegmentDigits['F'] = QStringList() << A << E << F << G;
|
|
sevenSegmentDigits['G'] = QStringList() << A << C << D << E << F;
|
|
sevenSegmentDigits['H'] = QStringList() << B << C << E << F << G;
|
|
sevenSegmentDigits['I'] = QStringList() << B << C;
|
|
sevenSegmentDigits['J'] = QStringList() << B << C << D << E;
|
|
sevenSegmentDigits['K'] = QStringList() << E << F << G;
|
|
sevenSegmentDigits['L'] = QStringList() << D << E << F;
|
|
sevenSegmentDigits['M'] = QStringList() << A << B << D << F;
|
|
sevenSegmentDigits['N'] = QStringList() << A << B << C << E << F;
|
|
sevenSegmentDigits['O'] = QStringList() << A << B << C << D << E << F;
|
|
sevenSegmentDigits['P'] = QStringList() << A << B << E << F << G;
|
|
sevenSegmentDigits['Q'] = QStringList() << A << B << D << F << G;
|
|
sevenSegmentDigits['R'] = QStringList() << A << E << F;
|
|
sevenSegmentDigits['S'] = QStringList() << A << C << D << F << G;
|
|
sevenSegmentDigits['T'] = QStringList() << A << E << F;
|
|
sevenSegmentDigits['U'] = QStringList() << B << C << D << E << F;
|
|
sevenSegmentDigits['V'] = QStringList() << B << C << D << E << F;
|
|
sevenSegmentDigits['W'] = QStringList() << B << D << F << G;
|
|
sevenSegmentDigits['X'] = QStringList() << B << C << E << F << G;
|
|
sevenSegmentDigits['Y'] = QStringList() << B << C << F << G;
|
|
sevenSegmentDigits['Z'] = QStringList() << A << B << D << E << G;
|
|
sevenSegmentDigits['a'] = QStringList() << A << B << C << D << E << G;
|
|
sevenSegmentDigits['b'] = QStringList() << C << D << E << F << G;
|
|
sevenSegmentDigits['c'] = QStringList() << D << E << G;
|
|
sevenSegmentDigits['d'] = QStringList() << B << C << D << E << G;
|
|
sevenSegmentDigits['e'] = QStringList() << A << B << E << F << G;
|
|
sevenSegmentDigits['f'] = QStringList() << A << E << F << G;
|
|
sevenSegmentDigits['g'] = QStringList() << A << B << C << D << F << G;
|
|
sevenSegmentDigits['h'] = QStringList() << C << E << F << G;
|
|
sevenSegmentDigits['i'] = QStringList() << C;
|
|
sevenSegmentDigits['j'] = QStringList() << C << D;
|
|
sevenSegmentDigits['k'] = QStringList() << A << C << E << F << G;
|
|
sevenSegmentDigits['l'] = QStringList() << E << F;
|
|
sevenSegmentDigits['m'] = QStringList() << A << C << E << G;
|
|
sevenSegmentDigits['n'] = QStringList() << C << E << G;
|
|
sevenSegmentDigits[QChar(0x00F1)] = QStringList() << A << C << E << G; // ñ
|
|
sevenSegmentDigits['o'] = QStringList() << C << D << E << G;
|
|
sevenSegmentDigits['p'] = QStringList() << A << B << E << F << G;
|
|
sevenSegmentDigits['q'] = QStringList() << A << B << C << F << G;
|
|
sevenSegmentDigits['r'] = QStringList() << E << G;
|
|
sevenSegmentDigits['s'] = QStringList() << E << G;
|
|
sevenSegmentDigits['t'] = QStringList() << D << E << F << G;
|
|
sevenSegmentDigits['u'] = QStringList() << C << D << E;
|
|
sevenSegmentDigits['v'] = QStringList() << E << G;
|
|
sevenSegmentDigits['w'] = QStringList() << E << G;
|
|
sevenSegmentDigits['x'] = QStringList() << E << G;
|
|
sevenSegmentDigits['y'] = QStringList() << E << G;
|
|
sevenSegmentDigits['z'] = QStringList() << E << G;
|
|
sevenSegmentDigits[QChar(0x00F6)] = QStringList() << A << C << D << E << G; // ö
|
|
}
|
|
}
|
|
|
|
int digits(const QString& name)
|
|
{
|
|
return groups[name].count();
|
|
}
|
|
|
|
void paint(QPainter* p, const QString& item)
|
|
{
|
|
QRectF r = svg.elementRect(item);
|
|
svg.paint(p, r, item);
|
|
}
|
|
|
|
QRectF scaledRect(const QString& item)
|
|
{
|
|
QRectF r = svg.elementRect(item);
|
|
r.setRect(r.x() * xScale, r.y() * yScale, r.width() * xScale, r.height() * yScale);
|
|
return r;
|
|
}
|
|
|
|
void checkIfDirty()
|
|
{
|
|
if (dirty || (l->size().toSize() != img.size() && l->size().toSize() != QSize(0, 0))) {
|
|
//kDebug() << "Making bitmap" << l->size();
|
|
if (l->size().toSize() != img.size()) {
|
|
img = QPixmap(l->size().toSize());
|
|
}
|
|
img.fill(Qt::transparent);
|
|
|
|
QPainter p(&img);
|
|
|
|
xScale = l->size().width() / svg.size().width();
|
|
yScale = l->size().height() / svg.size().height();
|
|
p.setRenderHint(QPainter::TextAntialiasing, true);
|
|
p.setRenderHint(QPainter::Antialiasing, true);
|
|
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
|
|
|
p.save();
|
|
p.scale(l->size().width() / svg.size().width(),
|
|
l->size().height() / svg.size().height());
|
|
|
|
foreach (const QString& item, items) {
|
|
paint(&p, item);
|
|
}
|
|
p.restore();
|
|
dirty = false;
|
|
}
|
|
}
|
|
|
|
void parseXml()
|
|
{
|
|
KDecompressor kdecompressor;
|
|
if (!kdecompressor.setType(KDecompressor::TypeGZip)
|
|
|| !kdecompressor.process(content.toAscii())) {
|
|
kWarning() << "Could not decompress content" << kdecompressor.errorString();
|
|
return;
|
|
}
|
|
|
|
doc.setContent(kdecompressor.result());
|
|
QList<QDomNodeList> lists;
|
|
int pos;
|
|
lists << doc.elementsByTagName("g");
|
|
lists << doc.elementsByTagName("path");
|
|
lists << doc.elementsByTagName("rect");
|
|
foreach (const QDomNodeList& list, lists) {
|
|
for (int i = 0; i < list.count(); ++i) {
|
|
QDomElement element = list.item(i).toElement();
|
|
QString id = element.attribute("id");
|
|
if ((pos = id.lastIndexOf(':')) > -1) {
|
|
groups[id.left(pos)] << id.mid(pos + 1);
|
|
}
|
|
}
|
|
}
|
|
QDomNodeList list = doc.elementsByTagName("text");
|
|
for (int i = 0; i < list.count(); ++i) {
|
|
QDomElement element = list.item(i).toElement();
|
|
QDomNodeList l = element.elementsByTagName("tspan");
|
|
QDomElement e = l.item(0).toElement();
|
|
for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
|
QDomText t = n.toText();
|
|
if (!t.isNull()) {
|
|
texts[element.attribute("id")] = t;
|
|
}
|
|
}
|
|
}
|
|
|
|
//kDebug() << groups;
|
|
}
|
|
};
|
|
|
|
QMap<QChar, QStringList> LCD::Private::sevenSegmentDigits;
|
|
const QString LCD::Private::A("A");
|
|
const QString LCD::Private::B("B");
|
|
const QString LCD::Private::C("C");
|
|
const QString LCD::Private::D("D");
|
|
const QString LCD::Private::E("E");
|
|
const QString LCD::Private::F("F");
|
|
const QString LCD::Private::G("G");
|
|
const QString LCD::Private::DP("DP");
|
|
|
|
LCD::LCD(QGraphicsItem *parent) :
|
|
QGraphicsWidget(parent),
|
|
d(new Private(this))
|
|
{
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
}
|
|
|
|
LCD::~LCD()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
QString LCD::svg() const
|
|
{
|
|
return d->content;
|
|
}
|
|
|
|
void LCD::setSvg(const QString &svg)
|
|
{
|
|
d->content = Plasma::Theme::defaultTheme()->imagePath(svg);
|
|
d->svg.setImagePath(d->content);
|
|
d->parseXml();
|
|
d->dirty = true;
|
|
update();
|
|
}
|
|
|
|
QStringList LCD::groupItems(const QString &name)
|
|
{
|
|
return d->groups[name];
|
|
}
|
|
|
|
void LCD::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
|
{
|
|
Q_UNUSED(option)
|
|
Q_UNUSED(widget)
|
|
|
|
d->checkIfDirty();
|
|
p->drawPixmap(0, 0, d->img);
|
|
}
|
|
|
|
void LCD::setDigit(const QString &name, QChar digit, bool dot)
|
|
{
|
|
QStringList segments;
|
|
|
|
//kDebug() << name << digit << dot;
|
|
if (d->sevenSegmentDigits.keys().contains(digit)) {
|
|
segments = d->sevenSegmentDigits[digit];
|
|
}
|
|
if (dot) {
|
|
segments << d->DP;
|
|
}
|
|
setGroup(name, segments);
|
|
}
|
|
|
|
void LCD::setNumber(const QString &name, const QString& number)
|
|
{
|
|
int j = 0;
|
|
int digits = d->digits(name);
|
|
bool dot = false;
|
|
|
|
//kDebug() << name << number << digits;
|
|
for (int i = number.length() - 1; i >= 0; --i) {
|
|
if (number[i] == '.') {
|
|
dot = true;
|
|
} else {
|
|
setDigit(name + QString(":%1").arg(j++), number[i], dot);
|
|
dot = false;
|
|
}
|
|
if (j >= digits) {
|
|
break;
|
|
}
|
|
}
|
|
for (int i = j; i < digits; ++i) {
|
|
setDigit(name + QString(":%1").arg(i), ' ', false);
|
|
}
|
|
}
|
|
|
|
void LCD::setGroup(const QString &name, const QStringList& on)
|
|
{
|
|
QStringList all = d->groups[name];
|
|
foreach (const QString& item, all) {
|
|
if (on.contains(item)) {
|
|
setItemOn(name + ':' + item);
|
|
} else {
|
|
setItemOff(name + ':' + item);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LCD::clear()
|
|
{
|
|
d->items.clear();
|
|
}
|
|
|
|
void LCD::setItemOn(const QString &name)
|
|
{
|
|
if (!d->items.contains(name)) {
|
|
//kDebug() << "++++++++++" << name;
|
|
d->items << name;
|
|
d->dirty = true;
|
|
update();
|
|
}
|
|
}
|
|
|
|
void LCD::setItemOff(const QString &name)
|
|
{
|
|
if (d->items.contains(name)) {
|
|
//kDebug() << "----------" << name;
|
|
d->items.removeAll(name);
|
|
d->dirty = true;
|
|
update();
|
|
}
|
|
}
|
|
|
|
void LCD::setLabel(const QString &name, const QString &text)
|
|
{
|
|
if (d->texts[name].data() != text) {
|
|
d->texts[name].setData(text);
|
|
}
|
|
}
|
|
|
|
QString LCD::label(const QString &name) const
|
|
{
|
|
return d->texts[name].data();
|
|
}
|
|
|
|
QPixmap LCD::toPixmap()
|
|
{
|
|
d->checkIfDirty();
|
|
return d->img;
|
|
}
|
|
|
|
void LCD::setItemClickable(const QString &name, bool clickable)
|
|
{
|
|
d->clickable.removeAll(name);
|
|
if (clickable) {
|
|
setAcceptHoverEvents(true);
|
|
d->clickable << name;
|
|
}
|
|
}
|
|
|
|
void LCD::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
|
|
{
|
|
foreach (const QString& name, d->clickable) {
|
|
if (d->scaledRect(name).contains(event->pos())) {
|
|
setCursor(QCursor(Qt::PointingHandCursor));
|
|
return;
|
|
}
|
|
}
|
|
unsetCursor();
|
|
}
|
|
|
|
void LCD::mousePressEvent(QGraphicsSceneMouseEvent* event)
|
|
{
|
|
foreach (const QString& name, d->clickable) {
|
|
if (d->scaledRect(name).contains(event->pos())) {
|
|
emit clicked(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
QSizeF LCD::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
|
|
{
|
|
QSizeF s = QGraphicsWidget::sizeHint(which, constraint);
|
|
d->checkIfDirty();
|
|
if (which == Qt::PreferredSize) {
|
|
s = d->svg.size();
|
|
} else if (which == Qt::MinimumSize) {
|
|
s = d->svg.size() / 2;
|
|
} else {
|
|
s = QGraphicsWidget::sizeHint(which, constraint);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
#include "moc_lcd.cpp"
|