+//! Dessine un triangle.
+/*!
+ * Dessine un triangle défini par les coordonnées de ses sommets:
+ * (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de dessin
+ * courante.
+ *
+ * \param x1, y1 coordonnées du premier sommet du triangle
+ * \param x2, y2 coordonnées du deuxième sommet du triangle
+ * \param x3, y3 coordonnées du troisième sommet du triangle
+ *
+ * \see fillTriangle, setColor
+ */
+void DrawingWindow::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
+{
+ QPolygon poly(3);
+ poly.putPoints(0, 3, x1, y1, x2, y2, x3, y3);
+ safeLock(imageMutex);
+ painter->drawConvexPolygon(poly);
+ dirty(poly.boundingRect());
+ safeUnlock(imageMutex);
+}
+
+//! Dessine un triangle plein.
+/*!
+ * Dessine un triangle plein défini par les coordonnées de ses
+ * sommets: (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de
+ * dessin courante.
+ *
+ * \param x1, y1 coordonnées du premier sommet du triangle
+ * \param x2, y2 coordonnées du deuxième sommet du triangle
+ * \param x3, y3 coordonnées du troisième sommet du triangle
+ *
+ * \see drawTriangle, setColor
+ */
+void DrawingWindow::fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
+{
+ painter->setBrush(getColor());
+ drawTriangle(x1, y1, x2, y2, x3, y3);
+ painter->setBrush(Qt::NoBrush);
+}
+
+//! Écrit du texte.
+/*!
+ * Écrit le texte text, aux coordonnées (x, y) et avec les paramètres
+ * d'alignement flags. Le texte est écrit avec la couleur de dessin
+ * courante. Les flags sont une combinaison (ou binaire) de
+ * Qt::AlignLeft, Qt::AligneRight, Qt::AlignHCenter, Qt::AlignTop,
+ * Qt::AlignBottom, Qt::AlignVCenter, Qt::AlignCenter. Par défaut, le
+ * texte est aligné en haut à gauche.
+ *
+ * \param x, y coordonnées du texte
+ * \param text texte à écrire
+ * \param flags paramètres d'alignement
+ *
+ * \see drawText(int, int, const std::string &, int)
+ * \see drawTextBg, setColor
+ * \see QPainter::drawText
+ */
+void DrawingWindow::drawText(int x, int y, const char *text, int flags)
+{
+ safeLock(syncMutex);
+ if (!terminateThread) {
+ qApp->postEvent(this, new DrawTextEvent(x, y, text, flags));
+ syncCondition.wait(&syncMutex);
+ }
+ safeUnlock(syncMutex);
+}
+
+//! Écrit du texte.
+/*!
+ * \see drawText(int, int, const char *, int)
+ */
+void DrawingWindow::drawText(int x, int y, const std::string &text, int flags)
+{
+ drawText(x, y, text.c_str(), flags);
+}
+
+//! Écrit du texte sur fond coloré.
+/*!
+ * Écrit du texte comme drawText, mais l'arrière-plan est coloré avec
+ * la couleur de fond courante.
+ *
+ * \param x, y coordonnées du texte
+ * \param text texte à écrire
+ * \param flags paramètres d'alignement
+ *
+ * \see drawTextBg(int, int, const std::string &, int)
+ * \see drawText, setColor, setColorBg
+ */
+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);
+}
+
+//! Écrit du texte sur fond coloré.
+/*!
+ * \see drawTextBg(int, int, const char *, int)
+ */
+void DrawingWindow::drawTextBg(int x, int y, const std::string &text, int flags)
+{
+ drawTextBg(x, y, text.c_str(), flags);
+}
+
+//! Retourne la couleur d'un pixel.
+/*!
+ * Retourne la couleur du pixel de coordonnées (x, y). La valeur
+ * retournée peut servir de paramètres à setColor(unsigned int) ou
+ * setBgColor(unsigned int).
+ *
+ * \param x, y coordonnées du pixel
+ * \return couleur du pixel
+ *
+ * \see setColor(unsigned int), setBgColor(unsigned int)
+ */
+unsigned int DrawingWindow::getPointColor(int x, int y) const
+{
+ return image->pixel(x, y);
+}
+
+//! Attend l'appui sur un des boutons de la souris.
+/*!
+ * Attend l'appui sur un des boutons de la souris. Retourne le bouton
+ * qui a été pressé et les coordonnées du pointeur de souris à ce
+ * moment-là.
+ *
+ * \param x, y coordonnées du pointeur de souris
+ * \param button numéro du bouton qui a été pressé
+ * (1: gauche, 2: droit, 3: milieu, 0 sinon)
+ * \param time durée maximale de l'attente
+ * \return true si un bouton a été pressé
+ *
+ * \bug expérimental
+ */
+bool DrawingWindow::waitMousePress(int &x, int &y, int &button,
+ unsigned long time)
+{
+ bool pressed;
+ safeLock(inputMutex);
+ if (terminateThread) {
+ pressed = false;
+ } else {
+ pressed = inputCondition.wait(&inputMutex, time) && !terminateThread;
+ if (pressed) {
+ x = mousePos.x();
+ y = mousePos.y();
+ if (mouseButton & Qt::LeftButton)
+ button = 1;
+ else if (mouseButton & Qt::RightButton)
+ button = 2;
+ else if (mouseButton & Qt::MidButton)
+ button = 3;
+ else
+ button = 0;
+ }
+ }
+ safeUnlock(inputMutex);
+ return pressed;
+}
+
+//! Synchronise le contenu de la fenêtre.
+/*!
+ * Pour des raisons d'efficacités, le résultat des fonctions de dessin
+ * n'est pas affiché immédiatement. L'appel à sync permet de
+ * synchroniser le contenu de la fenêtre. Autrement dit, cela bloque
+ * l'exécution du programme jusqu'à ce que le contenu de la fenêtre
+ * soit à jour.
+ *
+ * \param time durée maximale de l'attente
+ * \return true si la fenêtre a pu être synchronisée
+ */
+bool DrawingWindow::sync(unsigned long time)
+{
+ bool synced;
+ safeLock(syncMutex);
+ if (terminateThread) {
+ synced = false;
+ } else {
+ qApp->postEvent(this, new SyncRequestEvent());
+ synced = syncCondition.wait(&syncMutex, time);
+ }
+ safeUnlock(syncMutex);
+ return synced;
+}
+
+//! Ferme la fenêtre graphique.
+void DrawingWindow::closeGraph()
+{
+ qApp->postEvent(this, new CloseRequestEvent());
+}
+
+//! Suspend l'exécution pendant un certain temps.
+/*!
+ * \param secs temps d'attente en seconde
+ */
+void DrawingWindow::sleep(unsigned long secs)
+{
+ DrawingThread::sleep(secs);
+}
+
+//! Suspend l'exécution pendant un certain temps.
+/*!
+ * \param msecs temps d'attente en millisecondes
+ */
+void DrawingWindow::msleep(unsigned long msecs)
+{
+ DrawingThread::msleep(msecs);
+}
+
+//! Suspend l'exécution pendant un certain temps.
+/*!
+ * \param usecs temps d'attente en microsecondes
+ */
+void DrawingWindow::usleep(unsigned long usecs)
+{
+ DrawingThread::usleep(usecs);
+}
+
+//--- DrawingWindow (protected methods) --------------------------------
+//! \cond show_protected
+
+/*!
+ * \see QWidget
+ */
+void DrawingWindow::closeEvent(QCloseEvent *ev)
+{
+ timer.stop();
+ thread->exit();
+ syncMutex.lock();
+ inputMutex.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();
+ inputCondition.wakeAll();
+ inputMutex.unlock();
+ syncMutex.unlock();
+ QWidget::closeEvent(ev);
+ if (!thread->wait(250)) {
+ thread->terminate();
+ thread->wait();
+ }
+}
+
+/*!
+ * \see QWidget
+ */
+void DrawingWindow::customEvent(QEvent *ev)
+{
+ switch ((int )ev->type()) {
+ case SyncRequest:
+ realSync();
+ break;
+ case CloseRequest:
+ close();
+ break;
+ case DrawTextRequest:
+ DrawTextEvent *tev = dynamic_cast<DrawTextEvent *>(ev);
+ realDrawText(tev->x, tev->y, tev->text, tev->flags);
+ break;
+ }
+}
+
+/*!
+ * \see QWidget
+ *
+ * \bug expérimental
+ */
+void DrawingWindow::mousePressEvent(QMouseEvent *ev)
+{
+ inputMutex.lock();
+ mousePos = ev->pos();
+ mouseButton = ev->button();
+ ev->accept();
+ inputCondition.wakeAll();
+ inputMutex.unlock();
+}
+
+/*!
+ * \see QWidget
+ */
+void DrawingWindow::keyPressEvent(QKeyEvent *ev)
+{
+ if (ev->key() == Qt::Key_Escape) {
+ ev->accept();
+ close();
+ }
+}
+
+/*!
+ * \see QWidget
+ */