Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
.
[graphlib.git] / DrawingWindow.cpp
index 5013bc1..02df2eb 100644 (file)
@@ -1,15 +1,8 @@
 #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:
@@ -25,50 +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 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 applyColor();
-
-    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 ----------------------------------------------------
@@ -77,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,
@@ -87,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,
@@ -97,60 +44,69 @@ 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)
+void DrawingWindow::setColor(unsigned int color)
 {
-    d->fgColor.setRgbF(red, green, blue);
-    d->applyColor();
+    setColor(QColor::fromRgb(color));
 }
 
 void DrawingWindow::setColor(const char *name)
 {
-    d->fgColor.setNamedColor(name);
-    d->applyColor();
+    setColor(QColor(name));
 }
 
-void DrawingWindow::setBgColor(float red, float green, float blue)
+void DrawingWindow::setColor(float red, float green, float blue)
+{
+    setColor(QColor::fromRgbF(red, green, blue));
+}
+
+void DrawingWindow::setBgColor(unsigned int color)
 {
-    d->bgColor.setRgbF(red, green, blue);
+    setBgColor(QColor::fromRgb(color));
 }
 
 void DrawingWindow::setBgColor(const char *name)
 {
-    d->bgColor.setNamedColor(name);
+    setBgColor(QColor(name));
+}
+
+void DrawingWindow::setBgColor(float red, float green, float 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)
@@ -158,52 +114,104 @@ void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
     QRect r;
     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)
 {
-    d->painter->setBrush(d->fgColor);
+    painter->setBrush(getColor());
     drawRect(x1, y1, x2, y2);
-    d->painter->setBrush(Qt::NoBrush);
+    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);
-    d->safeLock(d->imageMutex);
-    d->painter->drawEllipse(rect);
+    safeLock(imageMutex);
+    painter->drawEllipse(rect);
     rect.adjust(0, 0, 1, 1);
-    d->dirty(rect);
-    d->safeUnlock(d->imageMutex);
+    dirty(rect);
+    safeUnlock(imageMutex);
 }
 
 void DrawingWindow::fillCircle(int x, int y, int r)
 {
-    d->painter->setBrush(d->fgColor);
+    painter->setBrush(getColor());
     drawCircle(x, y, r);
-    d->painter->setBrush(Qt::NoBrush);
+    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;
-    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);
@@ -221,36 +229,43 @@ void DrawingWindow::usleep(unsigned long usecs)
 
 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)
@@ -271,74 +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->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("black");
-    q->setBgColor("white");
-    q->clearGraph();
+    setColor("black");
+    setBgColor("white");
+    clearGraph();
 
     dirtyFlag = false;
 }
 
-DrawingWindowPrivate::~DrawingWindowPrivate()
+inline
+void DrawingWindow::setColor(const QColor& color)
 {
-    delete thread;
-    delete painter;
-    delete image;
+    QPen pen(painter->pen());
+    pen.setColor(color);
+    painter->setPen(pen);
 }
 
 inline
-void DrawingWindowPrivate::applyColor()
+void DrawingWindow::setBgColor(const QColor& color)
 {
-    QPen pen(painter->pen());
-    pen.setColor(fgColor);
-    painter->setPen(pen);
+    painter->setBackground(color);
+}
+
+inline
+QColor DrawingWindow::getColor()
+{
+    return painter->pen().color();
+}
+
+inline
+QColor DrawingWindow::getBgColor()
+{
+    return painter->background().color();
 }
 
 inline
-void DrawingWindowPrivate::safeLock(QMutex &mutex)
+void DrawingWindow::safeLock(QMutex &mutex)
 {
     if (lockCount++ == 0)
         thread->setTerminationEnabled(false);
@@ -346,7 +367,7 @@ void DrawingWindowPrivate::safeLock(QMutex &mutex)
 }
 
 inline
-void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
+void DrawingWindow::safeUnlock(QMutex &mutex)
 {
     mutex.unlock();
     if (--lockCount == 0)
@@ -354,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;
@@ -384,7 +405,7 @@ void DrawingWindowPrivate::dirty(const QRect &rect)
     }
 }
 
-void DrawingWindowPrivate::update()
+void DrawingWindow::mayUpdate()
 {
     imageMutex.lock();
     bool dirty = dirtyFlag;
@@ -392,7 +413,7 @@ void DrawingWindowPrivate::update()
     dirtyFlag = false;
     imageMutex.unlock();
     if (dirty)
-        q->update(rect);
+        update(rect);
 }
 
 //--- DrawingThread ----------------------------------------------------