├── .gitignore ├── README.md ├── hello-remarkable.pro ├── main.cpp ├── main.qml ├── qml.qrc ├── tabletcanvas.cpp ├── tabletcanvas.h ├── tabletwindow.cpp └── tabletwindow.h /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hello-remarkable 2 | 3 | A simple hello-world application for the reMarkable based on the Qt Tablet example. 4 | 5 | See http://dragly.org/2017/12/01/developing-for-the-remarkable for more information. 6 | -------------------------------------------------------------------------------- /hello-remarkable.pro: -------------------------------------------------------------------------------- 1 | QT += quick 2 | CONFIG += c++11 3 | 4 | # The following define makes your compiler emit warnings if you use 5 | # any feature of Qt which as been marked deprecated (the exact warnings 6 | # depend on your compiler). Please consult the documentation of the 7 | # deprecated API in order to know how to port your code away from it. 8 | DEFINES += QT_DEPRECATED_WARNINGS 9 | 10 | # You can also make your code fail to compile if you use deprecated APIs. 11 | # In order to do so, uncomment the following line. 12 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 13 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 14 | 15 | SOURCES += main.cpp \ 16 | tabletwindow.cpp \ 17 | tabletcanvas.cpp 18 | 19 | RESOURCES += qml.qrc 20 | 21 | message($$QMAKESPEC) 22 | linux-oe-g++ { 23 | message("Is arm") 24 | LIBS += -lqsgepaper 25 | } 26 | 27 | # Additional import path used to resolve QML modules in Qt Creator's code model 28 | QML_IMPORT_PATH = 29 | 30 | # Additional import path used to resolve QML modules just for Qt Quick Designer 31 | QML_DESIGNER_IMPORT_PATH = 32 | 33 | # Default rules for deployment. 34 | qnx: target.path = /tmp/$${TARGET}/bin 35 | else: unix:!android: target.path = /opt/$${TARGET}/bin 36 | !isEmpty(target.path): INSTALLS += target 37 | 38 | HEADERS += \ 39 | tabletwindow.h \ 40 | tabletcanvas.h 41 | 42 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "tabletwindow.h" 6 | 7 | #include 8 | #ifdef __arm__ 9 | Q_IMPORT_PLUGIN(QsgEpaperPlugin) 10 | #endif 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | qmlRegisterType("Test", 1, 0, "TabletWindow"); 15 | qmlRegisterType("Test", 1, 0, "TabletCanvas"); 16 | 17 | #ifdef __arm__ 18 | qputenv("QMLSCENE_DEVICE", "epaper"); 19 | qputenv("QT_QPA_PLATFORM", "epaper:enable_fonts"); 20 | qputenv("QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS", "rotate=180"); 21 | qputenv("QT_QPA_GENERIC_PLUGINS", "evdevtablet"); 22 | #endif 23 | 24 | QGuiApplication app(argc, argv); 25 | 26 | QQmlApplicationEngine engine; 27 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 28 | if (engine.rootObjects().isEmpty()) 29 | return -1; 30 | 31 | return app.exec(); 32 | } 33 | -------------------------------------------------------------------------------- /main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | import QtQuick.Window 2.2 3 | 4 | import Test 1.0 5 | 6 | TabletWindow { 7 | id: root 8 | visible: true 9 | title: qsTr("Hello World") 10 | 11 | width: 1404 12 | height: 1872 13 | 14 | canvas: tabletCanvas 15 | 16 | Rectangle { 17 | anchors.fill: parent 18 | color: "white" 19 | } 20 | 21 | TabletCanvas { 22 | id: tabletCanvas 23 | anchors.fill: parent 24 | } 25 | 26 | Text { 27 | anchors.centerIn: parent 28 | text: "Hello, World!" 29 | } 30 | 31 | Grid { 32 | id: grid 33 | anchors.fill: parent 34 | } 35 | 36 | Text { 37 | anchors { 38 | left: parent.left 39 | top: parent.top 40 | margins: 32 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | main.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /tabletcanvas.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | #include "tabletcanvas.h" 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | //! [0] 50 | TabletCanvas::TabletCanvas(QQuickItem *parent) 51 | : QQuickItem (parent) 52 | , m_alphaChannelValuator(TangentialPressureValuator) 53 | , m_colorSaturationValuator(NoValuator) 54 | , m_lineWidthValuator(PressureValuator) 55 | , m_color(Qt::red) 56 | , m_brush(m_color) 57 | , m_pen(m_brush, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) 58 | , m_deviceDown(false) 59 | { 60 | initPixmap(); 61 | 62 | m_canvasWidth = 1404 / m_columns; 63 | m_canvasHeight = 1872 / m_rows; 64 | for (int i = 0; i < m_rows; i++) { 65 | m_paintedCanvasMap.append(QVector()); 66 | for (int j = 0; j < m_columns; j++) { 67 | qreal x = j * m_canvasWidth; 68 | qreal y = i * m_canvasHeight; 69 | PaintedCanvas *canvas = new PaintedCanvas(QRectF(x, y, m_canvasWidth, m_canvasHeight), &m_pixmap, this); 70 | m_paintedCanvases.append(canvas); 71 | m_paintedCanvasMap[i].append(canvas); 72 | } 73 | } 74 | } 75 | 76 | void TabletCanvas::initPixmap() 77 | { 78 | QPixmap newPixmap = QPixmap(1404, 1872); 79 | newPixmap.fill(Qt::white); 80 | QPainter painter(&newPixmap); 81 | if (!m_pixmap.isNull()) 82 | painter.drawPixmap(0, 0, m_pixmap); 83 | painter.end(); 84 | m_pixmap = newPixmap; 85 | } 86 | //! [0] 87 | 88 | //! [3] 89 | void TabletCanvas::tabletEvent(QTabletEvent *event) 90 | { 91 | switch (event->type()) { 92 | case QEvent::TabletPress: 93 | if (!m_deviceDown) { 94 | m_deviceDown = true; 95 | lastPoint.pos = event->posF(); 96 | lastPoint.rotation = event->rotation(); 97 | } 98 | break; 99 | case QEvent::TabletMove: 100 | if (event->device() == QTabletEvent::RotationStylus) 101 | updateCursor(event); 102 | if (m_deviceDown) { 103 | updateBrush(event); 104 | QPainter painter(&m_pixmap); 105 | paintPixmap(painter, event); 106 | lastPoint.pos = event->posF(); 107 | lastPoint.rotation = event->rotation(); 108 | } 109 | break; 110 | case QEvent::TabletRelease: 111 | if (m_deviceDown && event->buttons() == Qt::NoButton) 112 | m_deviceDown = false; 113 | break; 114 | default: 115 | break; 116 | } 117 | int i = event->posF().y() / m_canvasHeight; 118 | int j = event->posF().x() / m_canvasWidth; 119 | 120 | if (m_paintedCanvasMap.size() < 1) { 121 | qWarning() << "Error: no canvases in map" << event->posF(); 122 | return; 123 | } 124 | if (i >= m_paintedCanvasMap.size()) { 125 | qWarning() << "Error: event outside all canvases" << event->posF(); 126 | return; 127 | } 128 | if (j >= m_paintedCanvasMap[i].size()) { 129 | qWarning() << "Error: event outside all canvases" << event->posF(); 130 | return; 131 | } 132 | 133 | PaintedCanvas *canvas = m_paintedCanvasMap[i][j]; 134 | canvas->update(); 135 | } 136 | 137 | void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event) 138 | { 139 | // painter.setRenderHint(QPainter::Antialiasing); 140 | 141 | switch (event->device()) { 142 | //! [6] 143 | case QTabletEvent::Airbrush: 144 | { 145 | painter.setPen(Qt::NoPen); 146 | QRadialGradient grad(lastPoint.pos, m_pen.widthF() * 10.0); 147 | QColor color = m_brush.color(); 148 | color.setAlphaF(color.alphaF() * 0.25); 149 | grad.setColorAt(0, m_brush.color()); 150 | grad.setColorAt(0.5, Qt::transparent); 151 | painter.setBrush(grad); 152 | qreal radius = grad.radius(); 153 | painter.drawEllipse(event->posF(), radius, radius); 154 | } 155 | break; 156 | case QTabletEvent::RotationStylus: 157 | { 158 | m_brush.setStyle(Qt::SolidPattern); 159 | painter.setPen(Qt::NoPen); 160 | painter.setBrush(m_brush); 161 | QPolygonF poly; 162 | qreal halfWidth = m_pen.widthF(); 163 | QPointF brushAdjust(qSin(qDegreesToRadians(lastPoint.rotation)) * halfWidth, 164 | qCos(qDegreesToRadians(lastPoint.rotation)) * halfWidth); 165 | poly << lastPoint.pos + brushAdjust; 166 | poly << lastPoint.pos - brushAdjust; 167 | brushAdjust = QPointF(qSin(qDegreesToRadians(event->rotation())) * halfWidth, 168 | qCos(qDegreesToRadians(event->rotation())) * halfWidth); 169 | poly << event->posF() - brushAdjust; 170 | poly << event->posF() + brushAdjust; 171 | painter.drawConvexPolygon(poly); 172 | } 173 | break; 174 | default: 175 | { 176 | const QString error(tr("Unknown tablet device - treating as stylus")); 177 | } 178 | // FALL-THROUGH 179 | case QTabletEvent::Stylus: 180 | painter.setPen(m_pen); 181 | painter.drawLine(lastPoint.pos, event->posF()); 182 | break; 183 | } 184 | } 185 | //! [5] 186 | 187 | //! [7] 188 | void TabletCanvas::updateBrush(const QTabletEvent *event) 189 | { 190 | int hue, saturation, value, alpha; 191 | m_color.getHsv(&hue, &saturation, &value, &alpha); 192 | 193 | int vValue = int(((event->yTilt() + 60.0) / 120.0) * 255); 194 | int hValue = int(((event->xTilt() + 60.0) / 120.0) * 255); 195 | //! [7] //! [8] 196 | 197 | switch (m_alphaChannelValuator) { 198 | case PressureValuator: 199 | m_color.setAlphaF(event->pressure()); 200 | break; 201 | case TangentialPressureValuator: 202 | if (event->device() == QTabletEvent::Airbrush) 203 | m_color.setAlphaF(qMax(0.01, (event->tangentialPressure() + 1.0) / 2.0)); 204 | else 205 | m_color.setAlpha(255); 206 | break; 207 | case TiltValuator: 208 | m_color.setAlpha(maximum(abs(vValue - 127), abs(hValue - 127))); 209 | break; 210 | default: 211 | m_color.setAlpha(255); 212 | } 213 | 214 | //! [8] //! [9] 215 | switch (m_colorSaturationValuator) { 216 | case VTiltValuator: 217 | m_color.setHsv(hue, vValue, value, alpha); 218 | break; 219 | case HTiltValuator: 220 | m_color.setHsv(hue, hValue, value, alpha); 221 | break; 222 | case PressureValuator: 223 | m_color.setHsv(hue, int(event->pressure() * 255.0), value, alpha); 224 | break; 225 | default: 226 | ; 227 | } 228 | 229 | //! [9] //! [10] 230 | switch (m_lineWidthValuator) { 231 | case PressureValuator: 232 | m_pen.setWidthF(event->pressure() * 10 + 1); 233 | break; 234 | case TiltValuator: 235 | m_pen.setWidthF(maximum(abs(vValue - 127), abs(hValue - 127)) / 12); 236 | break; 237 | default: 238 | m_pen.setWidthF(1); 239 | } 240 | 241 | //! [10] //! [11] 242 | if (event->pointerType() == QTabletEvent::Eraser) { 243 | m_brush.setColor(Qt::white); 244 | m_pen.setColor(Qt::white); 245 | m_pen.setWidthF(event->pressure() * 10 + 1); 246 | } else { 247 | m_brush.setColor(m_color); 248 | m_pen.setColor(m_color); 249 | } 250 | } 251 | //! [11] 252 | 253 | //! [12] 254 | void TabletCanvas::updateCursor(const QTabletEvent *event) 255 | { 256 | QCursor cursor; 257 | if (event->type() != QEvent::TabletLeaveProximity) { 258 | if (event->pointerType() == QTabletEvent::Eraser) { 259 | cursor = QCursor(QPixmap(":/images/cursor-eraser.png"), 3, 28); 260 | } else { 261 | switch (event->device()) { 262 | case QTabletEvent::Stylus: 263 | cursor = QCursor(QPixmap(":/images/cursor-pencil.png"), 0, 0); 264 | break; 265 | case QTabletEvent::Airbrush: 266 | cursor = QCursor(QPixmap(":/images/cursor-airbrush.png"), 3, 4); 267 | break; 268 | case QTabletEvent::RotationStylus: { 269 | QImage origImg(QLatin1String(":/images/cursor-felt-marker.png")); 270 | QImage img(32, 32, QImage::Format_ARGB32); 271 | QColor solid = m_color; 272 | solid.setAlpha(255); 273 | img.fill(solid); 274 | QPainter painter(&img); 275 | QTransform transform = painter.transform(); 276 | transform.translate(16, 16); 277 | transform.rotate(-event->rotation()); 278 | painter.setTransform(transform); 279 | painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 280 | painter.drawImage(-24, -24, origImg); 281 | painter.setCompositionMode(QPainter::CompositionMode_HardLight); 282 | painter.drawImage(-24, -24, origImg); 283 | painter.end(); 284 | cursor = QCursor(QPixmap::fromImage(img), 16, 16); 285 | } break; 286 | default: 287 | break; 288 | } 289 | } 290 | } 291 | setCursor(cursor); 292 | } 293 | 294 | PaintedCanvas::PaintedCanvas(QRectF rect, QPixmap *pixmap, QQuickItem *parent) 295 | : QQuickPaintedItem(parent) 296 | , m_pixmap(pixmap) 297 | { 298 | setFillColor(Qt::white); 299 | setX(rect.x()); 300 | setY(rect.y()); 301 | setWidth(rect.width()); 302 | setHeight(rect.height()); 303 | } 304 | 305 | void PaintedCanvas::paint(QPainter *painter) 306 | { 307 | painter->drawPixmap(boundingRect(), *m_pixmap, QRect(x(), y(), width(), height())); 308 | } 309 | -------------------------------------------------------------------------------- /tabletcanvas.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | #ifndef TABLETCANVAS_H 42 | #define TABLETCANVAS_H 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | QT_BEGIN_NAMESPACE 55 | class QPaintEvent; 56 | class QString; 57 | QT_END_NAMESPACE 58 | 59 | class PaintedCanvas : public QQuickPaintedItem 60 | { 61 | Q_OBJECT 62 | 63 | public: 64 | PaintedCanvas(QRectF rect, QPixmap *pixmap, QQuickItem *parent = nullptr); 65 | virtual void paint(QPainter *painter) override; 66 | bool dirty = false; 67 | 68 | private: 69 | QPixmap *m_pixmap; 70 | }; 71 | 72 | //! [0] 73 | class TabletCanvas : public QQuickItem 74 | { 75 | Q_OBJECT 76 | 77 | public: 78 | enum Valuator { PressureValuator, TangentialPressureValuator, 79 | TiltValuator, VTiltValuator, HTiltValuator, NoValuator }; 80 | Q_ENUM(Valuator) 81 | 82 | TabletCanvas(QQuickItem *parent = nullptr); 83 | 84 | void setAlphaChannelValuator(Valuator type) 85 | { m_alphaChannelValuator = type; } 86 | void setColorSaturationValuator(Valuator type) 87 | { m_colorSaturationValuator = type; } 88 | void setLineWidthType(Valuator type) 89 | { m_lineWidthValuator = type; } 90 | void setColor(const QColor &c) 91 | { if (c.isValid()) m_color = c; } 92 | QColor color() const 93 | { return m_color; } 94 | void setTabletDevice(QTabletEvent *event) 95 | { updateCursor(event); } 96 | int maximum(int a, int b) 97 | { return a > b ? a : b; } 98 | void tabletEvent(QTabletEvent *event); 99 | 100 | private: 101 | void initPixmap(); 102 | void paintPixmap(QPainter &painter, QTabletEvent *event); 103 | Qt::BrushStyle brushPattern(qreal value); 104 | void updateBrush(const QTabletEvent *event); 105 | void updateCursor(const QTabletEvent *event); 106 | 107 | Valuator m_alphaChannelValuator; 108 | Valuator m_colorSaturationValuator; 109 | Valuator m_lineWidthValuator; 110 | QColor m_color; 111 | QPixmap m_pixmap; 112 | QBrush m_brush; 113 | QPen m_pen; 114 | bool m_deviceDown; 115 | QRect m_latestRect; 116 | QVector> m_paintedCanvasMap; 117 | QVector m_paintedCanvases; 118 | 119 | int m_rows = 8; 120 | int m_columns = 6; 121 | 122 | qreal m_canvasWidth = 0.0; 123 | qreal m_canvasHeight = 0.0; 124 | 125 | struct Point { 126 | QPointF pos; 127 | qreal rotation; 128 | } lastPoint; 129 | }; 130 | //! [0] 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /tabletwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "tabletwindow.h" 2 | #include "tabletcanvas.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | TabletWindow::TabletWindow(QWindow *parent) : QQuickWindow(parent) 9 | { 10 | } 11 | 12 | QPointF rotate(QPointF other, qreal width, qreal height) 13 | { 14 | return QPointF(other.y() / height * width, (1.0 - other.x() / width) * height); 15 | } 16 | 17 | 18 | void TabletWindow::tabletEvent(QTabletEvent *event) 19 | { 20 | // qDebug() << event; 21 | 22 | QPointF rotated = rotate(event->posF(), width(), height()); 23 | QPointF rotatedGlobal(rotate(event->globalPosF(), width(), height())); 24 | penEvent(rotated, event->pressure()); 25 | 26 | if (m_canvas) { 27 | QPointF offset = rotated - m_canvas->position(); 28 | QTabletEvent *fakeEvent = new QTabletEvent(event->type(), offset, rotatedGlobal, event->device(), event->pointerType(), event->pressure(), event->xTilt(), event->yTilt(), event->tangentialPressure(), event->rotation(), event->z(), event->modifiers(), event->uniqueId()); 29 | m_canvas->tabletEvent(fakeEvent); 30 | } 31 | } 32 | 33 | TabletCanvas *TabletWindow::canvas() const 34 | { 35 | return m_canvas; 36 | } 37 | 38 | void TabletWindow::setCanvas(TabletCanvas *canvas) 39 | { 40 | if (m_canvas == canvas) 41 | return; 42 | 43 | m_canvas = canvas; 44 | emit canvasChanged(m_canvas); 45 | } 46 | -------------------------------------------------------------------------------- /tabletwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef TABLETWINDOW_H 2 | #define TABLETWINDOW_H 3 | 4 | #include 5 | #include "tabletcanvas.h" 6 | 7 | class TabletWindow : public QQuickWindow 8 | { 9 | Q_OBJECT 10 | Q_PROPERTY(TabletCanvas* canvas READ canvas WRITE setCanvas NOTIFY canvasChanged) 11 | 12 | public: 13 | explicit TabletWindow(QWindow *parent = nullptr); 14 | 15 | QQmlListProperty canvases(); 16 | TabletCanvas* canvas() const; 17 | 18 | public slots: 19 | void setCanvas(TabletCanvas* canvas); 20 | 21 | signals: 22 | void penEvent(QPointF position, qreal pressure); 23 | void canvasChanged(TabletCanvas* canvas); 24 | 25 | protected: 26 | virtual void tabletEvent(QTabletEvent *) override; 27 | 28 | // QWindow interface 29 | protected: 30 | TabletCanvas* m_canvas = nullptr; 31 | }; 32 | 33 | #endif // TABLETWINDOW_H 34 | --------------------------------------------------------------------------------