Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
.
[graphlib.git] / DrawingWindow.cpp
1 #include "DrawingWindow.h"
2 #include <QBasicTimer>
3 #include <QColor>
4 #include <QImage>
5 #include <QMutex>
6 #include <QPaintEvent>
7 #include <QPainter>
8 #include <QRect>
9 #include <QThread>
10 #include <QTimerEvent>
11
12 class DrawingThread: public QThread {
13 public:
14     DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f);
15     void start_once(Priority priority = InheritPriority);
16
17 protected:
18     void run();
19
20 private:
21     DrawingWindow &drawingWindow;
22     DrawingWindow::ThreadFunction threadFunction;
23     bool started_once;
24
25     friend class DrawingWindow;
26     friend class DrawingWindowPrivate;
27 };
28
29 class DrawingWindowPrivate {
30 public:
31     static const int paintInterval = 33;
32
33     DrawingWindow * const q;
34
35     QBasicTimer timer;
36     QMutex mutex;
37
38     QImage *image;
39     QPainter *painter;
40
41     QColor fgColor;
42     QColor bgColor;
43
44     bool dirtyFlag;
45     QRect dirtyRect;
46
47     DrawingThread *thread;
48
49     DrawingWindowPrivate(DrawingWindow *w,
50                          DrawingWindow::ThreadFunction f);
51     ~DrawingWindowPrivate();
52
53     void initialize();
54
55     void lock();
56     void unlock();
57
58     void setDirtyRect();
59     void setDirtyRect(int x, int y);
60     void setDirtyRect(int x1, int y1, int x2, int y2);
61     void setDirtyRect(const QRect &rect);
62
63 };
64
65 //--- DrawingWindow ----------------------------------------------------
66
67 DrawingWindow::DrawingWindow(ThreadFunction f, int w, int h)
68     : QWidget()
69     , width(w)
70     , height(h)
71     , d(new DrawingWindowPrivate(this, f))
72 {
73     d->initialize();
74 }
75
76 DrawingWindow::DrawingWindow(QWidget *parent,
77                              ThreadFunction f, int w, int h)
78     : QWidget(parent)
79     , width(w)
80     , height(h)
81     , d(new DrawingWindowPrivate(this, f))
82 {
83     d->initialize();
84 }
85
86 DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags,
87                              ThreadFunction f, int w, int h)
88     : QWidget(parent, flags)
89     , width(w)
90     , height(h)
91     , d(new DrawingWindowPrivate(this, f))
92 {
93     d->initialize();
94 }
95
96 DrawingWindow::~DrawingWindow()
97 {
98     delete d;
99 }
100
101 void DrawingWindow::setColor(float red, float green, float blue)
102 {
103     d->fgColor.setRgbF(red, green, blue);
104     QPen pen(d->painter->pen());
105     pen.setColor(d->fgColor);
106     d->painter->setPen(pen);
107 }
108
109 void DrawingWindow::setBgColor(float red, float green, float blue)
110 {
111     d->bgColor.setRgbF(red, green, blue);
112 }
113
114 void DrawingWindow::clearGraph()
115 {
116     d->lock();
117     d->painter->fillRect(d->image->rect(), d->bgColor);    
118     d->setDirtyRect();
119     d->unlock();
120 }
121
122 void DrawingWindow::drawPoint(int x, int y)
123 {
124     d->lock();
125     d->painter->drawPoint(x, y);
126     d->setDirtyRect(x, y);
127     d->unlock();
128 }
129
130 void DrawingWindow::drawLine(int x1, int y1, int x2, int y2)
131 {
132     d->lock();
133     d->painter->drawLine(x1, y1, x2, y2);
134     d->setDirtyRect(x1, y1, x2, y2);
135     d->unlock();
136 }
137
138 void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
139 {
140     QRect r;
141     r.setCoords(x1, y1, x2, y2);
142     r = r.normalized();
143     d->lock();
144     d->painter->drawRect(r);
145     r.adjust(0, 0, 1, 1);
146     d->setDirtyRect(r);
147     d->unlock();
148 }
149
150 void DrawingWindow::sleep(unsigned long secs)
151 {
152     DrawingThread::sleep(secs);
153 }
154
155 void DrawingWindow::msleep(unsigned long msecs)
156 {
157     DrawingThread::msleep(msecs);
158 }
159
160 void DrawingWindow::usleep(unsigned long usecs)
161 {
162     DrawingThread::usleep(usecs);
163 }
164
165 void DrawingWindow::closeEvent(QCloseEvent *ev)
166 {
167     d->timer.stop();
168     d->thread->terminate();
169     QWidget::closeEvent(ev);
170     d->thread->wait();
171 }
172
173 void DrawingWindow::paintEvent(QPaintEvent *ev)
174 {
175     QPainter widgetPainter(this);
176     QRect rect = ev->rect();
177     d->mutex.lock();
178     QImage imageCopy(*d->image);
179     d->mutex.unlock();
180     widgetPainter.drawImage(rect, imageCopy, rect);
181 }
182
183 void DrawingWindow::showEvent(QShowEvent *ev)
184 {
185     d->timer.start(d->paintInterval, this);
186     d->thread->start_once(QThread::IdlePriority);
187     QWidget::showEvent(ev);
188 }
189
190 void DrawingWindow::timerEvent(QTimerEvent *ev)
191 {
192     if (ev->timerId() == d->timer.timerId()) {
193         d->mutex.lock();
194         if (d->dirtyFlag) {
195             update(d->dirtyRect);
196             d->dirtyFlag = false;
197         }
198         d->mutex.unlock();
199         d->timer.start(d->paintInterval, this);
200     } else {
201         QWidget::timerEvent(ev);
202     }
203 }
204
205 //--- DrawingWindowPrivate ---------------------------------------------
206
207 DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
208                                            DrawingWindow::ThreadFunction f)
209     : q(w)
210     , image(new QImage(q->width, q->height, QImage::Format_RGB32))
211     , painter(new QPainter(image))
212     , thread(new DrawingThread(*q, f))
213 {
214 }
215
216 void DrawingWindowPrivate::initialize()
217 {
218     q->setFocusPolicy(Qt::StrongFocus);
219     q->setFixedSize(image->size());
220     q->setAttribute(Qt::WA_OpaquePaintEvent);
221     q->setFocus();
222
223     q->setColor(0.0, 0.0, 0.0);
224     q->setBgColor(1.0, 1.0, 1.0);
225     q->clearGraph();
226
227     dirtyFlag = false;
228 }
229
230 DrawingWindowPrivate::~DrawingWindowPrivate()
231 {
232     delete thread;
233     delete painter;
234     delete image;
235 }
236
237 inline
238 void DrawingWindowPrivate::lock()
239 {
240     thread->setTerminationEnabled(false);
241     mutex.lock();
242 }
243
244 inline
245 void DrawingWindowPrivate::unlock()
246 {
247     mutex.unlock();
248     thread->setTerminationEnabled(true);
249 }
250
251 inline
252 void DrawingWindowPrivate::setDirtyRect()
253 {
254     dirtyFlag = true;
255     dirtyRect = image->rect();
256 }
257
258 inline
259 void DrawingWindowPrivate::setDirtyRect(int x, int y)
260 {
261     setDirtyRect(QRect(x, y, 1, 1));
262 }
263
264 inline
265 void DrawingWindowPrivate::setDirtyRect(int x1, int y1, int x2, int y2)
266 {
267     QRect r;
268     r.setCoords(x1, y1, x2, y2);
269     setDirtyRect(r.normalized());
270 }
271
272 void DrawingWindowPrivate::setDirtyRect(const QRect &rect)
273 {
274     if (dirtyFlag) {
275         dirtyRect |= rect;
276     } else {
277         dirtyFlag = true;
278         dirtyRect = rect;
279     }
280 }
281
282 //--- DrawingThread ----------------------------------------------------
283
284 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
285     : drawingWindow(w)
286     , threadFunction(f)
287     , started_once(false)
288 {
289 }
290
291 void DrawingThread::start_once(Priority priority)
292 {
293     if (!started_once) {
294         started_once = true;
295         start(priority);
296     }
297 }
298
299 void DrawingThread::run()
300 {
301     threadFunction(drawingWindow);
302 }