#ifndef DOODLEPAGE_H #define DOODLEPAGE_H #include #include #include #include #include #include #include namespace JusDoodle { // Doodle Point // X, Y is in logical coordinate system, value from -1.0 to +1.0; // Origin point is the midpoint of page. class Point { public: Point(double x, double y, int intvalMs = 0) : _x(x) , _y(y) , _intvalMs(intvalMs) { } // Construct from physical coordinates Point(const QSize &size, const QPoint &point, int intvalMs = 0) { _x = (point.x() * 2.0 - size.width()) / size.width(); _y = (point.y() * 2.0 - size.height()) / size.height(); _intvalMs = intvalMs; } // Construct from physical coordinates Point(const QSize &size, const QPointF &point, int intvalMs = 0) { _x = (point.x() * 2.0 - size.width()) / size.width(); _y = (point.y() * 2.0 - size.height()) / size.height(); _intvalMs = intvalMs; } // Convert to physical coordinates void toQPoint(const QSize &size, QPoint &point) const { point.setX(floor((_x * size.width() + size.width()) / 2)); point.setY(floor((_y * size.height() + size.height()) / 2)); } // Convert to physical coordinates void toQPointF(const QSize &size, QPointF &point) const { point.setX((_x * size.width() + size.width()) / 2); point.setY((_y * size.height() + size.height()) / 2); } public: double _x; double _y; int _intvalMs; }; // Path // List of points; typedef std::list Path; // Line // A line contains path, color, width // Width is ratio of line width and page width. class Line { public: Line(const QColor &color, double width, bool erase, const QSize &size, bool mine) : _path() , _color(color) , _width(width) , _erase(erase) , _size(size) , _lastTs() , _mine(mine) { } Line(const QColor &color, double width, bool erase, const Path &path) : _path(path) , _color(color) , _width(width) , _erase(erase) , _size(QSize()) , _lastTs(QTime()) , _mine(false) { } void addPoint(const QPoint &point) { QTime nowTs = QTime::currentTime(); if (_lastTs.isNull()) _path.push_back(Point(_size, point)); else _path.push_back(Point(_size, point, _lastTs.msecsTo(nowTs))); _lastTs = nowTs; } void addPoint(const QPointF &point) { QTime nowTs = QTime::currentTime(); if (_lastTs.isNull()) _path.push_back(Point(_size, point)); else _path.push_back(Point(_size, point, _lastTs.msecsTo(nowTs))); _lastTs = nowTs; } public: Path _path; QColor _color; double _width; bool _erase; QSize _size; QTime _lastTs; bool _mine; }; class DoodlePage : public QWidget { Q_OBJECT public: explicit DoodlePage(int pageId, QWidget *parent = 0); ~DoodlePage(); // Set background image. void setBackground(const QString &imagePath); // Set next drawing line color. void setColor(const QColor &color); // Set next drawing line width. void setWidth(double width); // Set next action mode. void setMode(bool erase); // Draw a line. void draw(const QPoint &from, const QPoint &to, const QColor &color, double width); // Draw a path. void draw(const Path &path, const QColor &color, double width); // Erase a line. void erase(const QPoint &from, const QPoint &to, double width); // Erase a path. void erase(const Path &path, double width); // Clear the page. void clear(); public Q_SLOTS: // Process of color changed. void onColorChanged(const QColor &color); // Process of width changed. void onWidthChanged(double width); // Process of mode changed. void onModeChanged(bool erase); void setDrawFlag(bool flag); Q_SIGNALS: // Emit after draw a line. void notifyDrawPath(int pageId, const Path &path, const QColor &color, double width); // Emit after erase a line. void notifyErasePath(int pageId, const Path &path, double width); protected: // Override resize event. Redraw the content. void resizeEvent(QResizeEvent *event); // Override move event. Redraw the content. void moveEvent(QMoveEvent *event); // Override show event. Redraw the content. void showEvent(QShowEvent *event); // Paint the content. void paintEvent(QPaintEvent *event); // Override move down event. Start track. void mousePressEvent(QMouseEvent *event); // Override move move event. Track points. void mouseMoveEvent(QMouseEvent *event); // Override move up event. Stop track. void mouseReleaseEvent(QMouseEvent *event); private: // Paint the background image. void paintBackground(QPainter *painter); // Paint lines. void paintLines(QPainter *painter); // Paint one line. void paintLine(QPainter *painter, const Line &line); // Start track void trackStart(const QPointF &point); // Record point void trackPoint(const QPointF &point); // Stop track void trackStop(const QPointF &point); private: int _pageId; QColor _color; double _width; bool _erase; QImage *_background; std::list _lines; Line *_track; bool _clear; bool _redraw; bool drawFlag; }; } #endif // DOODLEPAGE_H