X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/graphlib.git/blobdiff_plain/b90387c5d43606283eaf046eace46c9e4c4e7666..4bdee7c3e2155dde84c2c22035754a96bc6b2515:/DrawingWindow.cpp diff --git a/DrawingWindow.cpp b/DrawingWindow.cpp index 64508ff..02df2eb 100644 --- a/DrawingWindow.cpp +++ b/DrawingWindow.cpp @@ -1,15 +1,8 @@ #include "DrawingWindow.h" #include -#include -#include -#include -#include #include -#include -#include #include #include -#include class DrawingThread: public QThread { public: @@ -25,47 +18,6 @@ private: bool started_once; friend class DrawingWindow; - friend class DrawingWindowPrivate; -}; - -class DrawingWindowPrivate { -public: - static const int paintInterval = 33; - - DrawingWindow * const q; - - QBasicTimer timer; - QMutex imageMutex; - QMutex paintMutex; - QWaitCondition paintCondition; - bool painted; - int lockCount; - - QImage *image; - QPainter *painter; - - QColor fgColor; - QColor bgColor; - - bool dirtyFlag; - QRect dirtyRect; - - DrawingThread *thread; - - DrawingWindowPrivate(DrawingWindow *w, - DrawingWindow::ThreadFunction f); - ~DrawingWindowPrivate(); - - void initialize(); - - void safeLock(QMutex &mutex); - void safeUnlock(QMutex &mutex); - - void dirty(); - void dirty(int x, int y); - void dirty(int x1, int y1, int x2, int y2); - void dirty(const QRect &rect); - }; //--- DrawingWindow ---------------------------------------------------- @@ -74,9 +26,8 @@ DrawingWindow::DrawingWindow(ThreadFunction f, int w, int h) : QWidget() , width(w) , height(h) - , d(new DrawingWindowPrivate(this, f)) { - d->initialize(); + initialize(f); } DrawingWindow::DrawingWindow(QWidget *parent, @@ -84,9 +35,8 @@ DrawingWindow::DrawingWindow(QWidget *parent, : QWidget(parent) , width(w) , height(h) - , d(new DrawingWindowPrivate(this, f)) { - d->initialize(); + initialize(f); } DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags, @@ -94,73 +44,172 @@ DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags, : QWidget(parent, flags) , width(w) , height(h) - , d(new DrawingWindowPrivate(this, f)) { - d->initialize(); + initialize(f); } DrawingWindow::~DrawingWindow() { - delete d; + delete thread; + delete painter; + delete image; +} + +void DrawingWindow::setColor(unsigned int color) +{ + setColor(QColor::fromRgb(color)); +} + +void DrawingWindow::setColor(const char *name) +{ + setColor(QColor(name)); } void DrawingWindow::setColor(float red, float green, float blue) { - d->fgColor.setRgbF(red, green, blue); - QPen pen(d->painter->pen()); - pen.setColor(d->fgColor); - d->painter->setPen(pen); + setColor(QColor::fromRgbF(red, green, blue)); +} + +void DrawingWindow::setBgColor(unsigned int color) +{ + setBgColor(QColor::fromRgb(color)); +} + +void DrawingWindow::setBgColor(const char *name) +{ + setBgColor(QColor(name)); } void DrawingWindow::setBgColor(float red, float green, float blue) { - d->bgColor.setRgbF(red, green, blue); + setBgColor(QColor::fromRgbF(red, green, blue)); } void DrawingWindow::clearGraph() { - d->safeLock(d->imageMutex); - d->painter->fillRect(d->image->rect(), d->bgColor); - d->dirty(); - d->safeUnlock(d->imageMutex); + safeLock(imageMutex); + painter->fillRect(image->rect(), getBgColor()); + dirty(); + safeUnlock(imageMutex); } void DrawingWindow::drawPoint(int x, int y) { - d->safeLock(d->imageMutex); - d->painter->drawPoint(x, y); - d->dirty(x, y); - d->safeUnlock(d->imageMutex); + safeLock(imageMutex); + painter->drawPoint(x, y); + dirty(x, y); + safeUnlock(imageMutex); } void DrawingWindow::drawLine(int x1, int y1, int x2, int y2) { - d->safeLock(d->imageMutex); - d->painter->drawLine(x1, y1, x2, y2); - d->dirty(x1, y1, x2, y2); - d->safeUnlock(d->imageMutex); + safeLock(imageMutex); + painter->drawLine(x1, y1, x2, y2); + dirty(x1, y1, x2, y2); + safeUnlock(imageMutex); } void DrawingWindow::drawRect(int x1, int y1, int x2, int y2) { QRect r; - r.setCoords(x1, y1, x2, y2); + r.setCoords(x1, y1, x2 - 1, y2 - 1); r = r.normalized(); - d->safeLock(d->imageMutex); - d->painter->drawRect(r); + safeLock(imageMutex); + painter->drawRect(r); r.adjust(0, 0, 1, 1); - d->dirty(r); - d->safeUnlock(d->imageMutex); + dirty(r); + safeUnlock(imageMutex); +} + +void DrawingWindow::fillRect(int x1, int y1, int x2, int y2) +{ + painter->setBrush(getColor()); + drawRect(x1, y1, x2, y2); + painter->setBrush(Qt::NoBrush); +} + +void DrawingWindow::drawCircle(int x, int y, int r) +{ + QRect rect; + rect.setCoords(x - r, y - r, x + r - 1, y + r - 1); + safeLock(imageMutex); + painter->drawEllipse(rect); + rect.adjust(0, 0, 1, 1); + dirty(rect); + safeUnlock(imageMutex); +} + +void DrawingWindow::fillCircle(int x, int y, int r) +{ + painter->setBrush(getColor()); + drawCircle(x, y, r); + painter->setBrush(Qt::NoBrush); +} + +void DrawingWindow::drawText(int x, int y, const char *text, int flags) +{ + QRect r(image->rect()); + switch (flags & Qt::AlignHorizontal_Mask) { + case Qt::AlignRight: + r.setRight(x); + break; + case Qt::AlignHCenter: + if (x < width / 2) + r.setLeft(2 * x - width + 1); + else + r.setRight(2 * x); + break; + default: + r.setLeft(x); + } + switch (flags & Qt::AlignVertical_Mask) { + case Qt::AlignBottom: + r.setBottom(y); + break; + case Qt::AlignVCenter: + if (y < height / 2) + r.setTop(2 * y - height + 1); + else + r.setBottom(2 * y); + break; + default: + r.setTop(y); + } + safeLock(imageMutex); + painter->drawText(r, flags, text, &r); + dirty(r); + safeUnlock(imageMutex); +} + +void DrawingWindow::drawTextBg(int x, int y, const char *text, int flags) +{ + painter->setBackgroundMode(Qt::OpaqueMode); + drawText(x, y, text, flags); + painter->setBackgroundMode(Qt::TransparentMode); +} + +unsigned int DrawingWindow::getPointColor(int x, int y) +{ + return image->pixel(x, y); } bool DrawingWindow::sync(unsigned long time) { - bool ret; - d->safeLock(d->paintMutex); - QApplication::postEvent(this, new QEvent(QEvent::User)); - ret = d->paintCondition.wait(&d->paintMutex, time); - d->safeUnlock(d->paintMutex); - return ret; + bool synced; + safeLock(syncMutex); + if (terminateThread) { + synced = false; + } else { + qApp->postEvent(this, new QEvent(QEvent::User)); + synced = syncCondition.wait(&syncMutex, time); + } + safeUnlock(syncMutex); + return synced; +} + +void DrawingWindow::closeGraph() +{ + qApp->postEvent(this, new QEvent(QEvent::Type(QEvent::User + 1))); } void DrawingWindow::sleep(unsigned long secs) @@ -180,26 +229,43 @@ void DrawingWindow::usleep(unsigned long usecs) void DrawingWindow::closeEvent(QCloseEvent *ev) { - d->timer.stop(); - d->thread->terminate(); - d->paintCondition.wakeAll(); + timer.stop(); + thread->terminate(); + syncMutex.lock(); + terminateThread = true; // this flag is needed for the case + // where the following wakeAll() call + // occurs between the + // setTerminationEnable(false) and the + // mutex lock in safeLock() called + // from sync() + syncCondition.wakeAll(); + syncMutex.unlock(); QWidget::closeEvent(ev); - d->thread->wait(); -} - -void DrawingWindow::customEvent(QEvent *) -{ - d->paintMutex.lock(); - d->imageMutex.lock(); - if (d->dirtyFlag) { - QRect r = d->dirtyRect; - d->dirtyFlag = false; - d->imageMutex.unlock(); - repaint(r); - } else - d->imageMutex.unlock(); - d->paintCondition.wakeAll(); - d->paintMutex.unlock(); + thread->wait(); +} + +void DrawingWindow::customEvent(QEvent *ev) +{ + switch ((int )ev->type()) { + case QEvent::User: + mayUpdate(); + qApp->sendPostedEvents(this, QEvent::UpdateLater); + qApp->sendPostedEvents(this, QEvent::UpdateRequest); + qApp->sendPostedEvents(this, QEvent::Paint); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents | + QEventLoop::ExcludeSocketNotifiers | + QEventLoop::DeferredDeletion | + QEventLoop::X11ExcludeTimers); + qApp->flush(); + qApp->syncX(); + syncMutex.lock(); + syncCondition.wakeAll(); + syncMutex.unlock(); + break; + case QEvent::User + 1: + close(); + break; + } } void DrawingWindow::keyPressEvent(QKeyEvent *ev) @@ -220,70 +286,80 @@ void DrawingWindow::keyPressEvent(QKeyEvent *ev) void DrawingWindow::paintEvent(QPaintEvent *ev) { QPainter widgetPainter(this); - d->imageMutex.lock(); - QImage imageCopy(*d->image); - d->imageMutex.unlock(); + imageMutex.lock(); + QImage imageCopy(*image); + imageMutex.unlock(); QRect rect = ev->rect(); widgetPainter.drawImage(rect, imageCopy, rect); } void DrawingWindow::showEvent(QShowEvent *ev) { - d->timer.start(d->paintInterval, this); - d->thread->start_once(QThread::IdlePriority); + timer.start(paintInterval, this); + thread->start_once(QThread::IdlePriority); QWidget::showEvent(ev); } void DrawingWindow::timerEvent(QTimerEvent *ev) { - if (ev->timerId() == d->timer.timerId()) { - d->imageMutex.lock(); - if (d->dirtyFlag) { - update(d->dirtyRect); - d->dirtyFlag = false; - } - d->imageMutex.unlock(); - d->timer.start(d->paintInterval, this); + if (ev->timerId() == timer.timerId()) { + mayUpdate(); + timer.start(paintInterval, this); } else { QWidget::timerEvent(ev); } } -//--- DrawingWindowPrivate --------------------------------------------- +//--- DrawingWindow (private methods) ---------------------------------- -DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w, - DrawingWindow::ThreadFunction f) - : q(w) - , lockCount(0) - , image(new QImage(q->width, q->height, QImage::Format_RGB32)) - , painter(new QPainter(image)) - , thread(new DrawingThread(*q, f)) +void DrawingWindow::initialize(DrawingWindow::ThreadFunction f) { + terminateThread = false; + lockCount = 0; + image = new QImage(width, height, QImage::Format_RGB32); + painter = new QPainter(image); + thread = new DrawingThread(*this, f); + + setFocusPolicy(Qt::StrongFocus); + setFixedSize(image->size()); + setAttribute(Qt::WA_OpaquePaintEvent); + setFocus(); + + setColor("black"); + setBgColor("white"); + clearGraph(); + + dirtyFlag = false; } -void DrawingWindowPrivate::initialize() +inline +void DrawingWindow::setColor(const QColor& color) { - q->setFocusPolicy(Qt::StrongFocus); - q->setFixedSize(image->size()); - q->setAttribute(Qt::WA_OpaquePaintEvent); - q->setFocus(); + QPen pen(painter->pen()); + pen.setColor(color); + painter->setPen(pen); +} - q->setColor(0.0, 0.0, 0.0); // black - q->setBgColor(1.0, 1.0, 1.0); // white - q->clearGraph(); +inline +void DrawingWindow::setBgColor(const QColor& color) +{ + painter->setBackground(color); +} - dirtyFlag = false; +inline +QColor DrawingWindow::getColor() +{ + return painter->pen().color(); } -DrawingWindowPrivate::~DrawingWindowPrivate() +inline +QColor DrawingWindow::getBgColor() { - delete thread; - delete painter; - delete image; + return painter->background().color(); } inline -void DrawingWindowPrivate::safeLock(QMutex &mutex) +void DrawingWindow::safeLock(QMutex &mutex) { if (lockCount++ == 0) thread->setTerminationEnabled(false); @@ -291,7 +367,7 @@ void DrawingWindowPrivate::safeLock(QMutex &mutex) } inline -void DrawingWindowPrivate::safeUnlock(QMutex &mutex) +void DrawingWindow::safeUnlock(QMutex &mutex) { mutex.unlock(); if (--lockCount == 0) @@ -299,27 +375,27 @@ void DrawingWindowPrivate::safeUnlock(QMutex &mutex) } inline -void DrawingWindowPrivate::dirty() +void DrawingWindow::dirty() { dirtyFlag = true; dirtyRect = image->rect(); } inline -void DrawingWindowPrivate::dirty(int x, int y) +void DrawingWindow::dirty(int x, int y) { dirty(QRect(x, y, 1, 1)); } inline -void DrawingWindowPrivate::dirty(int x1, int y1, int x2, int y2) +void DrawingWindow::dirty(int x1, int y1, int x2, int y2) { QRect r; r.setCoords(x1, y1, x2, y2); dirty(r.normalized()); } -void DrawingWindowPrivate::dirty(const QRect &rect) +void DrawingWindow::dirty(const QRect &rect) { if (dirtyFlag) { dirtyRect |= rect; @@ -329,6 +405,17 @@ void DrawingWindowPrivate::dirty(const QRect &rect) } } +void DrawingWindow::mayUpdate() +{ + imageMutex.lock(); + bool dirty = dirtyFlag; + QRect rect = dirtyRect; + dirtyFlag = false; + imageMutex.unlock(); + if (dirty) + update(rect); +} + //--- DrawingThread ---------------------------------------------------- DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)