summaryrefslogtreecommitdiff
path: root/liveview
diff options
context:
space:
mode:
Diffstat (limited to 'liveview')
-rw-r--r--liveview/liveview.cpp69
-rw-r--r--liveview/liveview.h15
-rw-r--r--liveview/liveview.pro6
-rw-r--r--liveview/liveviewpaintengine.cpp98
-rw-r--r--liveview/liveviewpaintengine.h32
-rw-r--r--liveview/liveviewplugin.cpp1
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()