#include "DrawingWindow.h"
#include <QApplication>
-#include <QBasicTimer>
-#include <QColor>
-#include <QImage>
-#include <QMutex>
#include <QPaintEvent>
#include <QPainter>
-#include <QRect>
#include <QThread>
#include <QTimerEvent>
-#include <QWaitCondition>
class DrawingThread: public QThread {
public:
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 syncMutex;
- QWaitCondition syncCondition;
- bool terminateThread;
- 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);
-
- void update();
};
//--- DrawingWindow ----------------------------------------------------
: QWidget()
, width(w)
, height(h)
- , d(new DrawingWindowPrivate(this, f))
{
- d->initialize();
+ initialize(f);
}
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,
: 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(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);
+ fgColor.setRgbF(red, green, blue);
+ applyColor();
+}
+
+void DrawingWindow::setColor(const char *name)
+{
+ fgColor.setNamedColor(name);
+ applyColor();
}
void DrawingWindow::setBgColor(float red, float green, float blue)
{
- d->bgColor.setRgbF(red, green, blue);
+ bgColor.setRgbF(red, green, blue);
+}
+
+void DrawingWindow::setBgColor(const char *name)
+{
+ bgColor.setNamedColor(name);
}
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(), bgColor);
+ 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(fgColor);
+ 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(fgColor);
+ drawCircle(x, y, r);
+ painter->setBrush(Qt::NoBrush);
+}
+
+void DrawingWindow::drawText(int x, int y, const char *text)
+{
+ QRect r(image->rect());
+ r.moveTo(x, y);
+ safeLock(imageMutex);
+ painter->drawText(r, 0, text, &r);
+ dirty(r);
+ safeUnlock(imageMutex);
}
bool DrawingWindow::sync(unsigned long time)
{
bool synced;
- d->safeLock(d->syncMutex);
- if (d->terminateThread) {
+ safeLock(syncMutex);
+ if (terminateThread) {
synced = false;
} else {
qApp->postEvent(this, new QEvent(QEvent::User));
- synced = d->syncCondition.wait(&d->syncMutex, time);
+ synced = syncCondition.wait(&syncMutex, time);
}
- d->safeUnlock(d->syncMutex);
+ 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::closeEvent(QCloseEvent *ev)
{
- d->timer.stop();
- d->thread->terminate();
- d->syncMutex.lock();
- d->terminateThread = true; // this flag is needed for the case
+ 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()
- d->syncCondition.wakeAll();
- d->syncMutex.unlock();
+ syncCondition.wakeAll();
+ syncMutex.unlock();
QWidget::closeEvent(ev);
- d->thread->wait();
-}
-
-void DrawingWindow::customEvent(QEvent *)
-{
- d->update();
- 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();
- d->syncMutex.lock();
- d->syncCondition.wakeAll();
- d->syncMutex.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)
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->update();
- 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)
- , terminateThread(false)
- , 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);
-void DrawingWindowPrivate::initialize()
-{
- q->setFocusPolicy(Qt::StrongFocus);
- q->setFixedSize(image->size());
- q->setAttribute(Qt::WA_OpaquePaintEvent);
- q->setFocus();
+ setFocusPolicy(Qt::StrongFocus);
+ setFixedSize(image->size());
+ setAttribute(Qt::WA_OpaquePaintEvent);
+ setFocus();
- q->setColor(0.0, 0.0, 0.0); // black
- q->setBgColor(1.0, 1.0, 1.0); // white
- q->clearGraph();
+ setColor("black");
+ setBgColor("white");
+ clearGraph();
dirtyFlag = false;
}
-DrawingWindowPrivate::~DrawingWindowPrivate()
+inline
+void DrawingWindow::applyColor()
{
- delete thread;
- delete painter;
- delete image;
+ QPen pen(painter->pen());
+ pen.setColor(fgColor);
+ painter->setPen(pen);
}
inline
-void DrawingWindowPrivate::safeLock(QMutex &mutex)
+void DrawingWindow::safeLock(QMutex &mutex)
{
if (lockCount++ == 0)
thread->setTerminationEnabled(false);
}
inline
-void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
+void DrawingWindow::safeUnlock(QMutex &mutex)
{
mutex.unlock();
if (--lockCount == 0)
}
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;
}
}
-void DrawingWindowPrivate::update()
+void DrawingWindow::mayUpdate()
{
imageMutex.lock();
bool dirty = dirtyFlag;
dirtyFlag = false;
imageMutex.unlock();
if (dirty)
- q->update(rect);
+ update(rect);
}
//--- DrawingThread ----------------------------------------------------