X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/graphlib.git/blobdiff_plain/abb9adcc79ad7c8bff8741c19df15e6fad1603c6..5cb6b0c2a5bd8569ba18bb274924b2e05598e851:/DrawingWindow.cpp diff --git a/DrawingWindow.cpp b/DrawingWindow.cpp index 9a8d501..02df2eb 100644 --- a/DrawingWindow.cpp +++ b/DrawingWindow.cpp @@ -1,171 +1,401 @@ #include "DrawingWindow.h" +#include #include #include #include -class DrawingWindow::DrawingThread: public QThread { +class DrawingThread: public QThread { public: - DrawingThread(DrawingWindow &w, ThreadFunction f) - : drawingWindow(w) - , threadFunction(f) - { - } + DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f); + void start_once(Priority priority = InheritPriority); - void run() - { - exit(threadFunction(drawingWindow)); - } +protected: + void run(); private: DrawingWindow &drawingWindow; - ThreadFunction threadFunction; + DrawingWindow::ThreadFunction threadFunction; + bool started_once; + friend class DrawingWindow; }; -DrawingWindow::DrawingWindow(ThreadFunction fun, int width, int height) +//--- DrawingWindow ---------------------------------------------------- + +DrawingWindow::DrawingWindow(ThreadFunction f, int w, int h) : QWidget() + , width(w) + , height(h) { - initialize(fun, width, height); + initialize(f); } DrawingWindow::DrawingWindow(QWidget *parent, - ThreadFunction fun, int width, int height) + ThreadFunction f, int w, int h) : QWidget(parent) + , width(w) + , height(h) { - initialize(fun, width, height); + initialize(f); } DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags, - ThreadFunction fun, int width, int height) + ThreadFunction f, int w, int h) : QWidget(parent, flags) + , width(w) + , height(h) { - initialize(fun, width, height); + initialize(f); } -void DrawingWindow::initialize(ThreadFunction fun, int width, int height) +DrawingWindow::~DrawingWindow() { - image = new QImage(width, height, QImage::Format_RGB32); - image->fill(QColor(Qt::white).rgb()); - - painter = new QPainter(image); + delete thread; + delete painter; + delete image; +} -#ifdef USE_PIXMAP_CACHE - pixmap = new QPixmap(image->size()); - QPainter pixmapPainter(pixmap); - pixmapPainter.drawImage(0, 0, *image); -#endif +void DrawingWindow::setColor(unsigned int color) +{ + setColor(QColor::fromRgb(color)); +} - dirtyFlag = false; +void DrawingWindow::setColor(const char *name) +{ + setColor(QColor(name)); +} - setFocusPolicy(Qt::StrongFocus); - setFixedSize(image->size()); - setAttribute(Qt::WA_OpaquePaintEvent); - setFocus(); - timer.start(paintInterval, this); +void DrawingWindow::setColor(float red, float green, float blue) +{ + setColor(QColor::fromRgbF(red, green, blue)); +} - thread = new DrawingThread(*this, fun); - thread_started = false; +void DrawingWindow::setBgColor(unsigned int color) +{ + setBgColor(QColor::fromRgb(color)); } -DrawingWindow::~DrawingWindow() +void DrawingWindow::setBgColor(const char *name) { - delete thread; -#ifdef USE_PIXMAP_CACHE - delete pixmap; -#endif - delete painter; - delete image; + setBgColor(QColor(name)); } -void DrawingWindow::setColor(const QColor &color) +void DrawingWindow::setBgColor(float red, float green, float blue) { - QPen pen(painter->pen()); - pen.setColor(color); - painter->setPen(pen); + setBgColor(QColor::fromRgbF(red, green, blue)); } -void DrawingWindow::setColor(float red, float green, float blue) +void DrawingWindow::clearGraph() { - QColor color; - color.setRgbF(red, green, blue); - this->setColor(color); + safeLock(imageMutex); + painter->fillRect(image->rect(), getBgColor()); + dirty(); + safeUnlock(imageMutex); } void DrawingWindow::drawPoint(int x, int y) { - lock(); + safeLock(imageMutex); painter->drawPoint(x, y); - setDirtyRect(x, y); - unlock(); + dirty(x, y); + safeUnlock(imageMutex); } void DrawingWindow::drawLine(int x1, int y1, int x2, int y2) { - lock(); + safeLock(imageMutex); painter->drawLine(x1, y1, x2, y2); - setDirtyRect(x1, y1, x2, y2); - unlock(); + 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 - 1, y2 - 1); + r = r.normalized(); + safeLock(imageMutex); + painter->drawRect(r); + r.adjust(0, 0, 1, 1); + 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 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) +{ + DrawingThread::sleep(secs); +} + +void DrawingWindow::msleep(unsigned long msecs) +{ + DrawingThread::msleep(msecs); +} + +void DrawingWindow::usleep(unsigned long usecs) +{ + DrawingThread::usleep(usecs); +} + +void DrawingWindow::closeEvent(QCloseEvent *ev) +{ + 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); + 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) +{ + bool accept = true; + switch (ev->key()) { + case Qt::Key_Escape: + close(); + break; + default: + accept = false; + break; + } + if (accept) + ev->accept(); } void DrawingWindow::paintEvent(QPaintEvent *ev) { QPainter widgetPainter(this); + imageMutex.lock(); + QImage imageCopy(*image); + imageMutex.unlock(); QRect rect = ev->rect(); -#ifdef USE_PIXMAP_CACHE - widgetPainter.drawPixmap(rect, *pixmap, rect); -#else - lock(); - widgetPainter.drawImage(rect, *image, rect); - unlock(); -#endif + widgetPainter.drawImage(rect, imageCopy, rect); } void DrawingWindow::showEvent(QShowEvent *ev) { - if (!thread_started) { - thread->start(); - thread_started = true; - } + timer.start(paintInterval, this); + thread->start_once(QThread::IdlePriority); QWidget::showEvent(ev); } void DrawingWindow::timerEvent(QTimerEvent *ev) { if (ev->timerId() == timer.timerId()) { - lock(); - if (dirtyFlag) { -#ifdef USE_PIXMAP_CACHE - QPainter pixmapPainter(pixmap); - pixmapPainter.drawImage(dirtyRect, *image, dirtyRect); -#endif - dirtyFlag = false; - update(dirtyRect); - timer.start(paintInterval, this); - } - unlock(); + mayUpdate(); + timer.start(paintInterval, this); } else { QWidget::timerEvent(ev); } } -void DrawingWindow::setDirtyRect() +//--- DrawingWindow (private methods) ---------------------------------- + +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; +} + +inline +void DrawingWindow::setColor(const QColor& color) +{ + QPen pen(painter->pen()); + pen.setColor(color); + painter->setPen(pen); +} + +inline +void DrawingWindow::setBgColor(const QColor& color) +{ + painter->setBackground(color); +} + +inline +QColor DrawingWindow::getColor() +{ + return painter->pen().color(); +} + +inline +QColor DrawingWindow::getBgColor() +{ + return painter->background().color(); +} + +inline +void DrawingWindow::safeLock(QMutex &mutex) +{ + if (lockCount++ == 0) + thread->setTerminationEnabled(false); + mutex.lock(); +} + +inline +void DrawingWindow::safeUnlock(QMutex &mutex) +{ + mutex.unlock(); + if (--lockCount == 0) + thread->setTerminationEnabled(true); +} + +inline +void DrawingWindow::dirty() { - setDirtyRect(QRect(0, 0, width(), height())); + dirtyFlag = true; + dirtyRect = image->rect(); } -void DrawingWindow::setDirtyRect(int x, int y) +inline +void DrawingWindow::dirty(int x, int y) { - setDirtyRect(QRect(x, y, 1, 1)); + dirty(QRect(x, y, 1, 1)); } -void DrawingWindow::setDirtyRect(int x1, int y1, int x2, int y2) +inline +void DrawingWindow::dirty(int x1, int y1, int x2, int y2) { QRect r; r.setCoords(x1, y1, x2, y2); - setDirtyRect(r.normalized()); + dirty(r.normalized()); } -void DrawingWindow::setDirtyRect(const QRect &rect) +void DrawingWindow::dirty(const QRect &rect) { if (dirtyFlag) { dirtyRect |= rect; @@ -174,3 +404,36 @@ void DrawingWindow::setDirtyRect(const QRect &rect) dirtyRect = 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) + : drawingWindow(w) + , threadFunction(f) + , started_once(false) +{ +} + +void DrawingThread::start_once(Priority priority) +{ + if (!started_once) { + started_once = true; + start(priority); + } +} + +void DrawingThread::run() +{ + threadFunction(drawingWindow); +}