2 * Copyright (c) 2007-2013, Arnaud Giersch <arnaud.giersch@univ-fcomte.fr>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 * products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "DrawingWindow.h"
31 #include <QApplication>
32 #include <QPaintEvent>
34 #include <QTimerEvent>
36 /*! \class DrawingWindow
37 * \brief Fenêtre de dessin.
39 * \author Arnaud Giersch <arnaud.giersch@univ-fcomte.fr>
42 * Cette classe décrit un widget Qt permettant d'écrire des
43 * applications graphiques simples. Pour cela, il faut définir une
44 * fonction de dessin. Cette fonction ne retourne rien et prend comme
45 * unique paramètre une référence vers un objet de class
48 * La fonction devra ensuite être passée en paramètre pour les
49 * constructeurs de la classe, ainsi que les dimension requises pour
50 * la fenêtre graphique. Le programme est ensuite compilé comme
51 * n'importe quel programme Qt.
53 * Concrètement, la fonction sera exécutée dans un nouveau thread,
54 * tandis que le thread principal s'occupera de la gestion des
55 * évènements et du rendu dans la fenêtre.
57 * <b>NB.</b> Pour toutes les méthodes de dessin, le coin en haut à gauche
58 * de la fenêtre a les coordonnées (0, 0). Le coin en bas à droite de
59 * la fenêtre a les coordonnées (largeur - 1, hauteur - 1), si la
60 * fenêtre est de dimension largeur × hauteur.
62 * Un appui sur la touche <Esc> provoque la fermeture de la fenêtre.
63 * Comme pour la plupart des applications, il est également possible
64 * de fermer la fenêtre via le gestionnaire de fenêtres.
66 * Il est possible, dans une application, d'ouvrir plusieurs fenêtres,
67 * avec des fonctions de dessin éventuellement différentes.
68 * L'application se terminera normalement lorsque la dernière fenêtre
72 /*! \example hello.cpp
74 * Voir le code source à la fin de la page. Pour compiler et exécuter
75 * ce programme, il faut :
77 * <b>1. Créer le fichier \c hello.pro</b>
79 * Pour simplifier, ce fichier contient la liste des fichiers sources
80 * composant le programme.
84 * <b>2. Créer le fichier \c Makefile avec la commande :</b>
86 * \verbatim qmake-qt4 hello.pro \endverbatim
87 * ou tout simplement :
88 * \verbatim qmake-qt4 \endverbatim
90 * <b>3. Compiler le programme avec la commande :</b>
92 * \verbatim make hello \endverbatim
93 * ou tout simplement :
94 * \verbatim make \endverbatim
96 * <b>4. Exécuter le programme avec la commande :</b>
98 * \verbatim ./hello \endverbatim
100 * <b>Code source de l'exemple</b>
103 /*! \example exemple.cpp
105 * Un exemple un peu plus sophistiqué.
108 //! Classe de thread.
109 class DrawingThread: public QThread {
111 DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f);
112 void start_once(Priority priority = InheritPriority);
118 DrawingWindow &drawingWindow;
119 DrawingWindow::ThreadFunction threadFunction;
122 friend class DrawingWindow;
126 SyncRequest = QEvent::User, //!< Demande de synchronisation.
127 CloseRequest, //!< Demande de fermeture de la fenêtre.
128 DrawTextRequest, //!< Demande d'écriture de texte.
131 //! Demande de synchronisation.
132 class SyncRequestEvent: public QEvent {
134 SyncRequestEvent(): QEvent(static_cast<QEvent::Type>(SyncRequest))
138 //! Demande de fermeture de fenêtre.
139 class CloseRequestEvent: public QEvent {
141 CloseRequestEvent(): QEvent(static_cast<QEvent::Type>(CloseRequest))
145 //! Demande de tracé de texte.
146 class DrawTextEvent: public QEvent {
152 DrawTextEvent(int x_, int y_, const char *text_, int flags_)
153 : QEvent(static_cast<QEvent::Type>(DrawTextRequest))
154 , x(x_), y(y_), text(text_), flags(flags_)
158 //--- DrawingWindow ----------------------------------------------------
160 /*! \file DrawingWindow.h
161 * \brief Classe DrawingWindow.
164 /*! \typedef DrawingWindow::ThreadFunction
165 * \brief Type de la fonction de dessin, passée en paramètre de construction.
167 /*! \var DrawingWindow::DEFAULT_WIDTH
168 * \brief Largeur par défaut de la fenêtre.
170 /*! \var DrawingWindow::DEFAULT_HEIGHT
171 * \brief Hauteur par défaut de la fenêtre.
173 /*! \var DrawingWindow::width
174 * \brief Largeur de la fenêtre.
176 /*! \var DrawingWindow::height
177 * \brief Hauteur de la fenêtre.
179 /*! \var DrawingWindow::paintInterval
180 * \brief Intervalle de temps entre deux rendus (ms).
185 * Construit une nouvelle fenêtre de dessin avec les dimensions
186 * passées en paramètres. La fonction fun sera exécutée dans un
189 * \param fun fonction de dessin
190 * \param width_ largeur de la fenêtre
191 * \param height_ hauteur de la fenêtre
195 DrawingWindow::DrawingWindow(ThreadFunction fun, int width_, int height_)
205 * Construit un nouveau widget de dessin avec les dimensions passées
206 * en paramètres. La fonction fun sera exécutée dans un nouveau
209 * \param parent widget parent
210 * \param fun fonction de dessin
211 * \param width_ largeur de la fenêtre
212 * \param height_ hauteur de la fenêtre
216 DrawingWindow::DrawingWindow(QWidget *parent,
217 ThreadFunction fun, int width_, int height_)
227 * Construit un nouveau widget de dessin avec les dimensions passées
228 * en paramètres. La fonction fun sera exécutée dans un nouveau
231 * \param parent widget parent
232 * \param flags flags passés au constructeur de QWidget
233 * \param fun fonction de dessin
234 * \param width_ largeur de la fenêtre
235 * \param height_ hauteur de la fenêtre
239 DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags,
240 ThreadFunction fun, int width_, int height_)
241 : QWidget(parent, flags)
249 DrawingWindow::~DrawingWindow()
256 //! Change la couleur de dessin.
258 * La couleur est un entier, tel que retourné par getPointColor.
259 * Normalement de la forme #00RRGGBB.
261 * \param color couleur
263 * \see setColor(const char *), setColor(float, float, float),
264 * setBgColor(unsigned int),
267 void DrawingWindow::setColor(unsigned int color)
269 setColor(QColor::fromRgb(color));
272 //! Change la couleur de dessin.
274 * Le nom de couleur est de la forme "black", "white", "red", "blue", ...
276 * \param name nom de couleur
278 * \see setColor(unsigned int), setColor(float, float, float),
279 * setBgColor(const char *)
280 * \see http://www.w3.org/TR/SVG/types.html#ColorKeywords
282 void DrawingWindow::setColor(const char *name)
284 setColor(QColor(name));
287 //! Change la couleur de dessin.
289 * Les composantes de rouge, vert et bleu de la couleur doivent être
290 * compris entre 0 et 1. Si le trois composantes sont à 0, on obtient
291 * du noir; si les trois composantes sont à 1, on obtient du blanc.
293 * \param red composante de rouge
294 * \param green composante de vert
295 * \param blue composante de bleu
297 * \see setColor(unsigned int), setColor(const char *),
298 * setBgColor(float, float, float)
300 void DrawingWindow::setColor(float red, float green, float blue)
302 setColor(QColor::fromRgbF(red, green, blue));
305 //! Change la couleur de fond.
307 * \param color couleur
309 * \see setBgColor(const char *), setBgColor(float, float, float),
310 * setColor(unsigned int),
314 void DrawingWindow::setBgColor(unsigned int color)
316 setBgColor(QColor::fromRgb(color));
319 //! Change la couleur de fond.
321 * \param name nom de couleur
323 * \see setBgColor(unsigned int), setBgColor(float, float, float),
324 * setColor(const char *),
326 * \see http://www.w3.org/TR/SVG/types.html#ColorKeywords
328 void DrawingWindow::setBgColor(const char *name)
330 setBgColor(QColor(name));
333 //! Change la couleur de fond.
335 * \param red composante de rouge
336 * \param green composante de vert
337 * \param blue composante de bleu
339 * \see setBgColor(unsigned int), setBgColor(const char *),
340 * setColor(float, float, float),
343 void DrawingWindow::setBgColor(float red, float green, float blue)
345 setBgColor(QColor::fromRgbF(red, green, blue));
348 //! Change l'épaisseur du pinceau
350 * Le pinceau à une épaisseur de 1 par défaut.
352 * \param width épaisseur du pinceau
354 void DrawingWindow::setPenWidth(int width)
356 QPen pen(painter->pen());
358 painter->setPen(pen);
361 //! Retourne la fonte courante utilisée pour dessiner du texte.
363 * \see QFont, setFont
365 const QFont &DrawingWindow::getFont() const
367 return painter->font();
370 //! Applique une nouvelle font pour dessiner du texte.
372 * \see QFont, getFont
374 void DrawingWindow::setFont(const QFont &font)
376 painter->setFont(font);
379 //! Active ou non l'antialiasing.
381 * Permet de lisser le dessin.
382 * Fonctionnalité désactivée par défaut.
384 * \param state état de l'antialiasing
388 void DrawingWindow::setAntialiasing(bool state)
390 painter->setRenderHint(QPainter::Antialiasing, state);
393 //! Efface la fenêtre.
395 * La fenêtre est effacée avec la couleur de fond courante.
399 void DrawingWindow::clearGraph()
401 safeLock(imageMutex);
402 painter->fillRect(image->rect(), getBgColor());
404 safeUnlock(imageMutex);
407 //! Dessine un point.
409 * Dessine un point (pixel) aux coordonnées (x, y), avec la couleur de
412 * \param x, y coordonnées du point
416 void DrawingWindow::drawPoint(int x, int y)
418 safeLock(imageMutex);
419 painter->drawPoint(x, y);
421 safeUnlock(imageMutex);
424 //! Dessine un segment.
426 * Dessine un segement de droite entre les coordonnées (x1, y1) et
427 * (x2, y2), avec la couleur de dessin courante.
429 * \param x1, y1 coordonnées d'une extrémité du segment
430 * \param x2, y2 coordonnées de l'autre extrémité du segment
434 void DrawingWindow::drawLine(int x1, int y1, int x2, int y2)
436 if (x1 == x2 && y1 == y2) {
439 safeLock(imageMutex);
440 painter->drawLine(x1, y1, x2, y2);
441 dirty(x1, y1, x2, y2);
442 safeUnlock(imageMutex);
446 //! Dessine un rectangle.
448 * Dessine le rectangle parallèle aux axes et défini par les
449 * coordonnées de deux sommets opposés (x1, y1) et (x2, y2). Utilise
450 * la couleur de dessin courante.
452 * \param x1, y1 coordonnées d'un sommet du rectangle
453 * \param x2, y2 coordonnées du sommet opposé du rectangle
455 * \see fillRect, setColor
457 void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
459 if (x1 == x2 && y1 == y2) {
463 r.setCoords(x1, y1, x2 - 1, y2 - 1);
465 safeLock(imageMutex);
466 painter->drawRect(r);
467 r.adjust(0, 0, 1, 1);
469 safeUnlock(imageMutex);
473 //! Dessine un rectangle plein.
475 * Dessine le rectangle plein parallèle aux axes et défini par les
476 * coordonnées de deux sommets opposés (x1, y1) et (x2, y2). Utilise
477 * la couleur de dessin courante.
479 * \param x1, y1 coordonnées d'un sommet du rectangle
480 * \param x2, y2 coordonnées du sommet opposé du rectangle
482 * \see drawRect, setColor
484 void DrawingWindow::fillRect(int x1, int y1, int x2, int y2)
486 painter->setBrush(getColor());
487 drawRect(x1, y1, x2, y2);
488 painter->setBrush(Qt::NoBrush);
491 //! Dessine un cercle.
493 * Dessine un cercle de centre (x, y) et de rayon r. Utilise la
494 * couleur de dessin courante.
496 * \param x, y coordonnées du centre du cercle
497 * \param r rayon du cercle
499 * \see fillCircle, setColor
501 void DrawingWindow::drawCircle(int x, int y, int r)
504 rect.setCoords(x - r, y - r, x + r - 1, y + r - 1);
505 safeLock(imageMutex);
506 painter->drawEllipse(rect);
507 rect.adjust(0, 0, 1, 1);
509 safeUnlock(imageMutex);
512 //! Dessine un disque.
514 * Dessine un disque (cercle plein) de centre (x, y) et de rayon r.
515 * Utilise la couleur de dessin courante.
517 * \param x, y coordonnées du centre du disque
518 * \param r rayon du disque
520 * \see drawCircle, setColor
522 void DrawingWindow::fillCircle(int x, int y, int r)
524 painter->setBrush(getColor());
526 painter->setBrush(Qt::NoBrush);
529 //! Dessine un triangle.
531 * Dessine un triangle défini par les coordonnées de ses sommets:
532 * (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de dessin
535 * \param x1, y1 coordonnées du premier sommet du triangle
536 * \param x2, y2 coordonnées du deuxième sommet du triangle
537 * \param x3, y3 coordonnées du troisième sommet du triangle
539 * \see fillTriangle, setColor
541 void DrawingWindow::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
544 poly.putPoints(0, 3, x1, y1, x2, y2, x3, y3);
545 safeLock(imageMutex);
546 painter->drawConvexPolygon(poly);
547 dirty(poly.boundingRect());
548 safeUnlock(imageMutex);
551 //! Dessine un triangle plein.
553 * Dessine un triangle plein défini par les coordonnées de ses
554 * sommets: (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de
557 * \param x1, y1 coordonnées du premier sommet du triangle
558 * \param x2, y2 coordonnées du deuxième sommet du triangle
559 * \param x3, y3 coordonnées du troisième sommet du triangle
561 * \see drawTriangle, setColor
563 void DrawingWindow::fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
565 painter->setBrush(getColor());
566 drawTriangle(x1, y1, x2, y2, x3, y3);
567 painter->setBrush(Qt::NoBrush);
572 * Écrit le texte text, aux coordonnées (x, y) et avec les paramètres
573 * d'alignement flags. Le texte est écrit avec la couleur de dessin
574 * courante. Les flags sont une combinaison (ou binaire) de
575 * Qt::AlignLeft, Qt::AligneRight, Qt::AlignHCenter, Qt::AlignTop,
576 * Qt::AlignBottom, Qt::AlignVCenter, Qt::AlignCenter. Par défaut, le
577 * texte est aligné en haut à gauche.
579 * \param x, y coordonnées du texte
580 * \param text texte à écrire
581 * \param flags paramètres d'alignement
583 * \see drawText(int, int, const std::string &, int)
584 * \see drawTextBg, setColor
585 * \see QPainter::drawText
587 void DrawingWindow::drawText(int x, int y, const char *text, int flags)
590 if (!terminateThread) {
591 qApp->postEvent(this, new DrawTextEvent(x, y, text, flags));
592 syncCondition.wait(&syncMutex);
594 safeUnlock(syncMutex);
599 * \see drawText(int, int, const char *, int)
601 void DrawingWindow::drawText(int x, int y, const std::string &text, int flags)
603 drawText(x, y, text.c_str(), flags);
606 //! Écrit du texte sur fond coloré.
608 * Écrit du texte comme drawText, mais l'arrière-plan est coloré avec
609 * la couleur de fond courante.
611 * \param x, y coordonnées du texte
612 * \param text texte à écrire
613 * \param flags paramètres d'alignement
615 * \see drawTextBg(int, int, const std::string &, int)
616 * \see drawText, setColor, setColorBg
618 void DrawingWindow::drawTextBg(int x, int y, const char *text, int flags)
620 painter->setBackgroundMode(Qt::OpaqueMode);
621 drawText(x, y, text, flags);
622 painter->setBackgroundMode(Qt::TransparentMode);
625 //! Écrit du texte sur fond coloré.
627 * \see drawTextBg(int, int, const char *, int)
629 void DrawingWindow::drawTextBg(int x, int y, const std::string &text, int flags)
631 drawTextBg(x, y, text.c_str(), flags);
634 //! Retourne la couleur d'un pixel.
636 * Retourne la couleur du pixel de coordonnées (x, y). La valeur
637 * retournée peut servir de paramètres à setColor(unsigned int) ou
638 * setBgColor(unsigned int).
640 * \param x, y coordonnées du pixel
641 * \return couleur du pixel
643 * \see setColor(unsigned int), setBgColor(unsigned int)
645 unsigned int DrawingWindow::getPointColor(int x, int y) const
647 return image->pixel(x, y);
650 //! Attend l'appui sur un des boutons de la souris.
652 * Attend l'appui sur un des boutons de la souris. Retourne le bouton
653 * qui a été pressé et les coordonnées du pointeur de souris à ce
656 * \param x, y coordonnées du pointeur de souris
657 * \param button numéro du bouton qui a été pressé
658 * (1: gauche, 2: droit, 3: milieu, 0 sinon)
659 * \param time durée maximale de l'attente
660 * \return true si un bouton a été pressé
664 bool DrawingWindow::waitMousePress(int &x, int &y, int &button,
668 safeLock(inputMutex);
669 if (terminateThread) {
672 pressed = inputCondition.wait(&inputMutex, time) && !terminateThread;
676 if (mouseButton & Qt::LeftButton)
678 else if (mouseButton & Qt::RightButton)
680 else if (mouseButton & Qt::MidButton)
686 safeUnlock(inputMutex);
690 //! Synchronise le contenu de la fenêtre.
692 * Pour des raisons d'efficacités, le résultat des fonctions de dessin
693 * n'est pas affiché immédiatement. L'appel à sync permet de
694 * synchroniser le contenu de la fenêtre. Autrement dit, cela bloque
695 * l'exécution du programme jusqu'à ce que le contenu de la fenêtre
698 * \param time durée maximale de l'attente
699 * \return true si la fenêtre a pu être synchronisée
701 bool DrawingWindow::sync(unsigned long time)
705 if (terminateThread) {
708 qApp->postEvent(this, new SyncRequestEvent());
709 synced = syncCondition.wait(&syncMutex, time);
711 safeUnlock(syncMutex);
715 //! Ferme la fenêtre graphique.
716 void DrawingWindow::closeGraph()
718 qApp->postEvent(this, new CloseRequestEvent());
721 //! Suspend l'exécution pendant un certain temps.
723 * \param secs temps d'attente en seconde
725 void DrawingWindow::sleep(unsigned long secs)
727 DrawingThread::sleep(secs);
730 //! Suspend l'exécution pendant un certain temps.
732 * \param msecs temps d'attente en millisecondes
734 void DrawingWindow::msleep(unsigned long msecs)
736 DrawingThread::msleep(msecs);
739 //! Suspend l'exécution pendant un certain temps.
741 * \param usecs temps d'attente en microsecondes
743 void DrawingWindow::usleep(unsigned long usecs)
745 DrawingThread::usleep(usecs);
748 //--- DrawingWindow (protected methods) --------------------------------
749 //! \cond show_protected
754 void DrawingWindow::closeEvent(QCloseEvent *ev)
760 terminateThread = true; // this flag is needed for the case
761 // where the following wakeAll() call
762 // occurs between the
763 // setTerminationEnable(false) and the
764 // mutex lock in safeLock() called
766 syncCondition.wakeAll();
767 inputCondition.wakeAll();
770 QWidget::closeEvent(ev);
771 if (!thread->wait(250)) {
780 void DrawingWindow::customEvent(QEvent *ev)
782 switch ((int )ev->type()) {
789 case DrawTextRequest:
790 DrawTextEvent *tev = dynamic_cast<DrawTextEvent *>(ev);
791 realDrawText(tev->x, tev->y, tev->text, tev->flags);
801 void DrawingWindow::mousePressEvent(QMouseEvent *ev)
804 mousePos = ev->pos();
805 mouseButton = ev->button();
807 inputCondition.wakeAll();
814 void DrawingWindow::keyPressEvent(QKeyEvent *ev)
816 if (ev->key() == Qt::Key_Escape) {
825 void DrawingWindow::paintEvent(QPaintEvent *ev)
827 QPainter widgetPainter(this);
829 QImage imageCopy(*image);
831 QRect rect = ev->rect();
832 widgetPainter.drawImage(rect, imageCopy, rect);
838 void DrawingWindow::showEvent(QShowEvent *ev)
840 QWidget::showEvent(ev);
843 timer.start(paintInterval, this);
844 thread->start_once(QThread::IdlePriority);
850 void DrawingWindow::timerEvent(QTimerEvent *ev)
852 if (ev->timerId() == timer.timerId()) {
854 timer.start(paintInterval, this);
856 QWidget::timerEvent(ev);
862 //--- DrawingWindow (private methods) ----------------------------------
864 //! Fonction d'initialisation.
866 * Fonction appelée par les différents constructeurs.
868 * \param fun fonction de dessin
870 void DrawingWindow::initialize(DrawingWindow::ThreadFunction fun)
872 terminateThread = false;
874 image = new QImage(width, height, QImage::Format_RGB32);
875 painter = new QPainter(image);
876 thread = new DrawingThread(*this, fun);
878 setFocusPolicy(Qt::StrongFocus);
879 setFixedSize(image->size());
880 setAttribute(Qt::WA_OpaquePaintEvent);
890 //! Change la couleur de dessin.
892 * \param color couleur
895 void DrawingWindow::setColor(const QColor &color)
897 QPen pen(painter->pen());
899 painter->setPen(pen);
902 //! Change la couleur de fond.
904 * \param color couleur
907 void DrawingWindow::setBgColor(const QColor &color)
909 painter->setBackground(color);
912 //! Retourne la couleur de dessin courante.
914 * \return couleur de dessin courante
917 QColor DrawingWindow::getColor()
919 return painter->pen().color();
922 //! Retourne la couleur de fond courante.
924 * \return couleur de fond courante
927 QColor DrawingWindow::getBgColor()
929 return painter->background().color();
932 //! Verrouille un mutex.
934 * S'assure que le thread courant ne peut pas être terminé s'il
935 * détient un mutex. Pendant de safeUnlock.
937 * \param mutex le mutex à verrouiller
942 void DrawingWindow::safeLock(QMutex &mutex)
944 if (lockCount++ == 0)
945 thread->setTerminationEnabled(false);
949 //! Déverrouille un mutex.
951 * S'assure que le thread courant ne peut pas être terminé s'il
952 * détient un mutex. Pendant de safeLock.
954 * \param mutex le mutex à déverrouiller
959 void DrawingWindow::safeUnlock(QMutex &mutex)
962 if (--lockCount == 0)
963 thread->setTerminationEnabled(true);
966 //! Marque l'image entière comme non à jour.
968 void DrawingWindow::dirty()
971 dirtyRect = image->rect();
974 //! Marque un point de l'image comme non à jour.
976 * \param x, y coordonnées du point
979 void DrawingWindow::dirty(int x, int y)
981 dirty(QRect(x, y, 1, 1));
984 //! Marque une zone de l'image comme non à jour.
986 * La zone est définie par un rectangle dont les coordonnées de deux
987 * sommets oppposés sont données.
989 * \param x1, y1 coordonnées d'un sommet du rectangle
990 * \param x2, y2 coordonnées du sommet opposé du rectangle
993 void DrawingWindow::dirty(int x1, int y1, int x2, int y2)
996 r.setCoords(x1, y1, x2, y2);
997 dirty(r.normalized());
1000 //! Marque une zone de l'image comme non à jour.
1002 * \param rect rectangle délimitant la zone
1004 void DrawingWindow::dirty(const QRect &rect)
1014 //! Génère un update si besoin.
1016 * Génère une demande de mise à jour de la fenêtre (appel à update)
1017 * s'il y en a besoin.
1019 void DrawingWindow::mayUpdate()
1022 bool dirty = dirtyFlag;
1023 QRect rect = dirtyRect;
1025 imageMutex.unlock();
1030 //! Fonction bas-niveau pour sync.
1032 * Fonction de synchronisation dans le thread principal.
1034 * \see sync, customEvent
1036 void DrawingWindow::realSync()
1039 qApp->sendPostedEvents(this, QEvent::UpdateLater);
1040 qApp->sendPostedEvents(this, QEvent::UpdateRequest);
1041 qApp->sendPostedEvents(this, QEvent::Paint);
1042 qApp->processEvents(QEventLoop::ExcludeUserInputEvents |
1043 QEventLoop::ExcludeSocketNotifiers |
1044 QEventLoop::DeferredDeletion |
1045 QEventLoop::X11ExcludeTimers);
1049 syncCondition.wakeAll();
1053 //! Fonction bas-niveau pour drawText.
1055 * Le rendu de texte doit être fait dans le thread principal. D'où
1056 * les manipulations tordues et la synchronisation qui s'en suit.
1058 * \param x, y, text, flags cf. drawText
1060 * \see drawText, customEvent
1062 void DrawingWindow::realDrawText(int x, int y, const char *text, int flags)
1064 QRect r(image->rect());
1065 switch (flags & Qt::AlignHorizontal_Mask) {
1066 case Qt::AlignRight:
1069 case Qt::AlignHCenter:
1071 r.setLeft(2 * x - width + 1);
1078 switch (flags & Qt::AlignVertical_Mask) {
1079 case Qt::AlignBottom:
1082 case Qt::AlignVCenter:
1084 r.setTop(2 * y - height + 1);
1092 painter->drawText(r, flags, QString::fromUtf8(text), &r);
1094 syncCondition.wakeAll();
1098 //--- DrawingThread ----------------------------------------------------
1101 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
1104 , started_once(false)
1108 //! Démarre le thread si ce n'a pas encore été fait.
1109 void DrawingThread::start_once(Priority priority)
1111 if (!started_once) {
1112 started_once = true;
1117 //! La vraie fonction pour le thread.
1118 void DrawingThread::run()
1120 threadFunction(drawingWindow);