diff options
Diffstat (limited to 'liveview')
-rw-r--r-- | liveview/liveview.cpp | 69 | ||||
-rw-r--r-- | liveview/liveview.h | 15 | ||||
-rw-r--r-- | liveview/liveview.pro | 6 | ||||
-rw-r--r-- | liveview/liveviewpaintengine.cpp | 98 | ||||
-rw-r--r-- | liveview/liveviewpaintengine.h | 32 | ||||
-rw-r--r-- | liveview/liveviewplugin.cpp | 1 |
6 files changed, 215 insertions, 6 deletions
diff --git a/liveview/liveview.cpp b/liveview/liveview.cpp index 5e2c5aa..df2b099 100644 --- a/liveview/liveview.cpp +++ b/liveview/liveview.cpp @@ -1,5 +1,6 @@ #include <QtEndian> +#include "liveviewpaintengine.h" #include "liveview.h" using namespace sowatch; @@ -10,28 +11,56 @@ QTM_USE_NAMESPACE LiveView::LiveView(ConfigKey* settings, QObject* parent) : BluetoothWatch(QBluetoothAddress(settings->value("address").toString()), parent), _settings(settings->getSubkey(QString(), this)), + _24hMode(settings->value("24h-mode", false).toBool()), + _screenWidth(0), _screenHeight(0), _sendTimer(new QTimer(this)) { _sendTimer->setInterval(DelayBetweenMessages); connect(_sendTimer, SIGNAL(timeout()), SLOT(handleSendTimerTick())); - _24hMode = settings->value("24h-mode", false).toBool(); _buttons << "Select" << "Up" << "Down" << "Left" << "Right"; } LiveView::~LiveView() { - + if (_paintEngine) { + delete _paintEngine; + } } QPaintEngine* LiveView::paintEngine() const { - return 0; // TODO + if (!_paintEngine) { + _paintEngine = new LiveViewPaintEngine; + } + + return _paintEngine; } int LiveView::metric(PaintDeviceMetric metric) const { - return 0; // TODO + switch (metric) { + case PdmWidth: + return _screenWidth; + case PdmHeight: + return _screenHeight; + case PdmWidthMM: + return 24; + case PdmHeightMM: + return 24; + case PdmNumColors: + return 65536; + case PdmDepth: + return 16; + case PdmDpiX: + case PdmPhysicalDpiX: + return 136; + case PdmDpiY: + case PdmPhysicalDpiY: + return 136; + } + + return -1; } QString LiveView::model() const @@ -106,7 +135,28 @@ void LiveView::displayApplication() void LiveView::vibrate(int msecs) { + // TODO +} +QImage* LiveView::image() +{ + return &_image; +} + +void LiveView::renderImage(int x, int y, const QImage &image) +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + if (image.save(&buffer, "PNG")) { + displayBitmap(x, y, buffer.buffer()); + } else { + qWarning() << "Failed to encode image"; + } +} + +void LiveView::clear() +{ + displayClear(); } void LiveView::setupBluetoothWatch() @@ -359,6 +409,17 @@ void LiveView::handleDateTimeRequest(const Message &msg) void LiveView::handleDisplayProperties(const Message &msg) { + if (msg.data.size() < 2) { + qWarning() << "Invalid DPR response"; + return; + } + + _screenWidth = msg.data[0]; + _screenHeight = msg.data[1]; + + // Recreate the display image + _image = QImage(_screenWidth, _screenHeight, QImage::Format_RGB16); + // For some reason firmware expects us to send this message right // after display properties // Otherwise the watch hangs up the connection diff --git a/liveview/liveview.h b/liveview/liveview.h index e150797..4a2e165 100644 --- a/liveview/liveview.h +++ b/liveview/liveview.h @@ -7,6 +7,8 @@ namespace sowatch { +class LiveViewPaintEngine; + class LiveView : public BluetoothWatch { Q_OBJECT @@ -39,6 +41,13 @@ public: void vibrate(int msecs); + // Only for application mode + QImage* image(); + /** Render a image in a certain position. */ + void renderImage(int x, int y, const QImage& image); + /** Clear the current display to black. */ + void clear(); + protected: static const int DelayBetweenMessages = 5; @@ -134,8 +143,14 @@ private: bool _24hMode : 1; + int _screenWidth; + int _screenHeight; QStringList _buttons; + // Required by QPaintDevice + mutable LiveViewPaintEngine* _paintEngine; + QImage _image; + /** Message outbox queue. */ QQueue<Message> _sendingMsgs; QTimer* _sendTimer; diff --git a/liveview/liveview.pro b/liveview/liveview.pro index 045c0eb..0e6c582 100644 --- a/liveview/liveview.pro +++ b/liveview/liveview.pro @@ -13,10 +13,12 @@ MOBILITY += connectivity systeminfo SOURCES += liveviewplugin.cpp \ liveviewscanner.cpp \ - liveview.cpp + liveview.cpp \ + liveviewpaintengine.cpp HEADERS += liveviewplugin.h \ liveviewscanner.h \ - liveview.h + liveview.h \ + liveviewpaintengine.h res_files.files += res/graphics res/fonts diff --git a/liveview/liveviewpaintengine.cpp b/liveview/liveviewpaintengine.cpp new file mode 100644 index 0000000..1785d62 --- /dev/null +++ b/liveview/liveviewpaintengine.cpp @@ -0,0 +1,98 @@ +#include "liveviewpaintengine.h" + +using namespace sowatch; + +LiveViewPaintEngine::LiveViewPaintEngine() : + WatchPaintEngine() +{ + +} + +bool LiveViewPaintEngine::begin(QPaintDevice *pdev) +{ + _watch = static_cast<LiveView*>(pdev); + + return WatchPaintEngine::begin(_watch->image()); +} + +bool LiveViewPaintEngine::end() +{ + bool ret = WatchPaintEngine::end(); + if (ret) { + QRect rect = _damaged.boundingRect(); + if (!rect.isEmpty()) { + QImage sub_image = _watch->image()->copy(rect); + _watch->renderImage(rect.x(), rect.y(), sub_image); + } + } + return ret; +} + +void LiveViewPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + int i; + for (i = 0; i < rectCount; i++) { + const QRectF& r = rects[i]; + if (_hasBrush && fillsEntireImage(r.toRect()) && _isBrushBlack) { + _watch->clear(); + _damaged = QRegion(); + continue; + } + if (_hasBrush) { + damageRect(r); + } + if (_hasPen) { + damagePenStroke(QLineF(r.left(), r.top(), r.right(), r.top())); + damagePenStroke(QLineF(r.right(), r.top(), r.right(), r.bottom())); + damagePenStroke(QLineF(r.left(), r.bottom(), r.right(), r.bottom())); + damagePenStroke(QLineF(r.left(), r.top(), r.left(), r.bottom())); + } + } + _painter.drawRects(rects, rectCount); +} + +void LiveViewPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + int i; + for (i = 0; i < rectCount; i++) { + const QRect& r = rects[i]; + if (_hasBrush && fillsEntireImage(r) && _isBrushBlack) { + _watch->clear(); + _damaged = QRegion(); + continue; + } + if (_hasBrush) { + damageRect(r); + } + if (_hasPen) { + damagePenStroke(QLine(r.left(), r.top(), r.right(), r.top())); + damagePenStroke(QLine(r.right(), r.top(), r.right(), r.bottom())); + damagePenStroke(QLine(r.left(), r.bottom(), r.right(), r.bottom())); + damagePenStroke(QLine(r.left(), r.top(), r.left(), r.bottom())); + } + } + + _painter.drawRects(rects, rectCount); +} + +void LiveViewPaintEngine::updateState(const QPaintEngineState &state) +{ + WatchPaintEngine::updateState(state); + if (state.state() & QPaintEngine::DirtyBrush) { + QBrush brush = state.brush(); + _isBrushBlack = false; + if (brush.style() == Qt::SolidPattern) { + const QColor color = brush.color(); + if (color == Qt::black) { + _isBrushBlack = true; + } + } + } +} + +bool LiveViewPaintEngine::fillsEntireImage(const QRect& rect) +{ + return rect == _area && + (!_clipEnabled || + (_clipRegion.numRects() == 1 && _clipRegion.rects().at(0) == _area)); +} diff --git a/liveview/liveviewpaintengine.h b/liveview/liveviewpaintengine.h new file mode 100644 index 0000000..f94c133 --- /dev/null +++ b/liveview/liveviewpaintengine.h @@ -0,0 +1,32 @@ +#ifndef LIVEVIEWPAINTENGINE_H +#define LIVEVIEWPAINTENGINE_H + +#include <sowatch.h> +#include "liveview.h" + +namespace sowatch +{ + +class LiveViewPaintEngine : public WatchPaintEngine +{ +public: + LiveViewPaintEngine(); + + bool begin(QPaintDevice *pdev); + bool end(); + + void drawRects(const QRectF *rects, int rectCount); + void drawRects(const QRect *rects, int rectCount); + + void updateState(const QPaintEngineState &state); + +protected: + bool fillsEntireImage(const QRect& rect); + + LiveView* _watch; + bool _isBrushBlack; +}; + +} + +#endif // LIVEVIEWPAINTENGINE_H diff --git a/liveview/liveviewplugin.cpp b/liveview/liveviewplugin.cpp index 0562f06..c7d862e 100644 --- a/liveview/liveviewplugin.cpp +++ b/liveview/liveviewplugin.cpp @@ -9,6 +9,7 @@ QTM_USE_NAMESPACE LiveViewPlugin::LiveViewPlugin() { + } LiveViewPlugin::~LiveViewPlugin() |