DoodlePage.cpp 5.66 KB
#include "DoodlePch.h"

namespace JusDoodle {

DoodlePage::DoodlePage(int pageId, QWidget *parent)
    : QWidget(parent)
    , _pageId(pageId)
    , _color(Qt::transparent)
    , _width(0.0)
    , _erase(false)
    , _background(NULL)
    , _lines()
    , _track(NULL)
    , _clear(false)
    , _redraw(true)
    , drawFlag(false)
{
}

DoodlePage::~DoodlePage()
{
    delete _background;
    delete _track;
}

void DoodlePage::setBackground(const QString &imagePath)
{
    QImage *newImage = new QImage(imagePath);
    if (newImage->isNull())
    {
        DOODLE_LOG_ERROR("load <%s>.", imagePath.toUtf8().data());
        delete newImage;
        return;
    }

    delete _background;
    _background = newImage;

    _redraw = true;
    update();
}

void DoodlePage::setColor(const QColor &color)
{
    _color = color;
}

void DoodlePage::setWidth(double width)
{
    _width = width;
}

void DoodlePage::setMode(bool erase)
{
    _erase = erase;
}

void DoodlePage::draw(const QPoint &from, const QPoint &to, const QColor &color, 
          double width)
{

}

void DoodlePage::draw(const Path &path, const QColor &color, double width)
{
    _lines.push_back(Line(color, width, false, path));
    update();
}

void DoodlePage::erase(const QPoint &from, const QPoint &to, double width)
{

}

void DoodlePage::erase(const Path &path, double width)
{
    _lines.push_back(Line(Qt::transparent, width, true, path));
    update();
}

void DoodlePage::clear()
{
    _clear = true;
    update();
}

void DoodlePage::onColorChanged(const QColor &color)
{
    setColor(color);
}

void DoodlePage::setDrawFlag(bool flag)
{
    drawFlag = flag;
}

void DoodlePage::onWidthChanged(double width)
{
    setWidth(width);
}

void DoodlePage::onModeChanged(bool erase)
{
    setMode(erase);
}

void DoodlePage::resizeEvent(QResizeEvent *event)
{
    _redraw = true;
    update();
}

void DoodlePage::moveEvent(QMoveEvent *event)
{
    _redraw = true;
    update();
}

void DoodlePage::showEvent(QShowEvent *event)
{
    _redraw = true;
    update();
}

void DoodlePage::paintEvent(QPaintEvent *event)
{
    QPainter painter;

    painter.begin(this);

    painter.setRenderHint(QPainter::Antialiasing);

    // clean content
    if (_clear || _redraw)
    {
        painter.setCompositionMode(QPainter::CompositionMode_Clear);
        painter.setPen(Qt::NoPen);
        painter.setBrush(Qt::white);
        painter.drawRect(rect());
    }

    if (_clear)
    {
        // delete history
        _clear = false;
        _lines.clear();
    }
    else
    {
        // paint lines
        paintLines(&painter);
    }

    // draw background image
    paintBackground(&painter);
}

void DoodlePage::mousePressEvent(QMouseEvent *event)
{
    trackStart(event->pos());
}

void DoodlePage::mouseMoveEvent(QMouseEvent *event)
{
    trackPoint(event->pos());
}

void DoodlePage::mouseReleaseEvent(QMouseEvent *event)
{
    trackStop(event->pos());
}

void DoodlePage::paintBackground(QPainter *painter)
{
    painter->setCompositionMode(QPainter::CompositionMode_DestinationOver);
    painter->setPen(Qt::NoPen);

    if (!_background)
        painter->setBrush(Qt::lightGray);
    else
        painter->setBrush(_background->scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
    painter->drawRect(rect());
}

void DoodlePage::paintLines(QPainter *painter)
{
    // paint history
    std::list<Line>::iterator it;
    for (it = _lines.begin(); it != _lines.end(); it++)
    {
        paintLine(painter, *it);
    }

    // paint current
    if (_track)
    {
        paintLine(painter, *_track);
    }
}

void DoodlePage::paintLine(QPainter *painter, const Line &line)
{
    Path::const_iterator it = line._path.begin();
    if (it == line._path.end()) return;

    // format path
    QPainterPath path;
    QPointF toPoint, controlPoint, nextControlPoint;
    it->toQPointF(size(), controlPoint);
    path.moveTo(controlPoint);
    for (it++ ; it != line._path.end(); it++)
    {
        it->toQPointF(size(), nextControlPoint);
        toPoint.setX((nextControlPoint.x() + controlPoint.x()) / 2);
        toPoint.setY((nextControlPoint.y() + controlPoint.y()) / 2);
        path.quadTo(controlPoint, toPoint);
        controlPoint = nextControlPoint;
    }

    qreal width = line._width * size().rwidth();

    QPen pen;
    if (line._erase)
    {
        pen = QPen(Qt::transparent, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
        painter->setCompositionMode(QPainter::CompositionMode_SourceOut);
    }
    else
    {
        pen = QPen(line._color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
        painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
    }

    painter->strokePath(path, pen);
}

void DoodlePage::trackStart(const QPointF &point)
{
    if(!drawFlag)
        return;

    if (_erase)
        _track = new Line(_color, WIDTH_ERASE, _erase, size(), true);
    else
        _track = new Line(_color, _width, _erase, size(), true);

    _track->addPoint(point);
}

void DoodlePage::trackPoint(const QPointF &point)
{
    if (!_track) return;

    QRectF rect(rect());
    if (!rect.contains(point.x(), point.y()))
    {
        trackStop(QPointF());
    }
    else
    {
        _track->addPoint(point);
        update();
    }
}

void DoodlePage::trackStop(const QPointF &point)
{
    if (!_track) return;

    if (!point.isNull())
        _track->addPoint(point);

    if (_track->_path.size() > 2)
    {
        if (_track->_erase)
        {
            emit notifyErasePath(_pageId, _track->_path, _track->_width);
        }
        else
        {
            emit notifyDrawPath(_pageId, _track->_path, _track->_color, _track->_width);
        }

        _lines.push_back(*_track);
    }

    delete _track;
    _track = NULL;
    update();
}

}