[qet] [833] Ajout d'un widget permettant d'editer l'angle d'orientation d' un texte plus intuitivement. |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/qet Archives
]
Revision: 833
Author: xavier
Date: 2010-01-03 20:45:33 +0100 (Sun, 03 Jan 2010)
Log Message:
-----------
Ajout d'un widget permettant d'editer l'angle d'orientation d'un texte plus intuitivement.
Modified Paths:
--------------
branches/0.3/sources/editor/textfieldeditor.cpp
branches/0.3/sources/editor/textfieldeditor.h
Added Paths:
-----------
branches/0.3/sources/qtextorientationwidget.cpp
branches/0.3/sources/qtextorientationwidget.h
Modified: branches/0.3/sources/editor/textfieldeditor.cpp
===================================================================
--- branches/0.3/sources/editor/textfieldeditor.cpp 2010-01-03 19:33:41 UTC (rev 832)
+++ branches/0.3/sources/editor/textfieldeditor.cpp 2010-01-03 19:45:33 UTC (rev 833)
@@ -17,7 +17,8 @@
*/
#include "textfieldeditor.h"
#include "parttextfield.h"
-
+#include "qtextorientationwidget.h"
+#include "qetapp.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@@ -36,8 +37,20 @@
rotate -> setChecked(true);
rotation_angle_ = new QDoubleSpinBox();
rotation_angle_ -> setRange(-360.0, 360.0);
- rotation_angle_ -> setSingleStep(-90.0);
rotation_angle_ -> setSuffix("\260");
+ rotation_widget_ = new QTextOrientationWidget();
+ rotation_widget_ -> setFont(QETApp::diagramTextsFont());
+ rotation_widget_ -> setUsableTexts(QList<QString>()
+ << tr("Q", "Single-letter example text - translate length, not meaning")
+ << tr("QET", "Small example text - translate length, not meaning")
+ << tr("Schema", "Normal example text - translate length, not meaning")
+ << tr("Electrique", "Normal example text - translate length, not meaning")
+ << tr("QElectroTech", "Long example text - translate length, not meaning")
+ );
+ rotation_widget_ -> setMinimumSize(90.0, 90.0);
+ connect(rotation_angle_, SIGNAL(valueChanged(double)), rotation_widget_, SLOT(setOrientation(double)));
+ connect(rotation_widget_, SIGNAL(orientationChanged(double)), rotation_angle_, SLOT(setValue(double)));
+ connect(rotation_widget_, SIGNAL(orientationChanged(double)), rotation_angle_, SIGNAL(editingFinished()));
qle_x -> setValidator(new QDoubleValidator(qle_x));
qle_y -> setValidator(new QDoubleValidator(qle_y));
@@ -64,6 +77,7 @@
QHBoxLayout *rotation_angle_layout = new QHBoxLayout();
rotation_angle_layout -> addWidget(new QLabel(tr("Angle de rotation par d\351faut : ")));
+ rotation_angle_layout -> addWidget(rotation_widget_);
rotation_angle_layout -> addWidget(rotation_angle_);
main_layout -> addLayout(rotation_angle_layout);
@@ -113,7 +127,8 @@
qle_text -> setText(part -> property("text").toString());
font_size -> setValue(part -> property("size").toInt());
rotate -> setChecked(!part -> property("rotate").toBool());
- rotation_angle_ -> setValue(part -> property("rotation angle").toInt());
+ rotation_angle_ -> setValue(part -> property("rotation angle").toDouble());
+ rotation_widget_ -> setOrientation(part -> property("rotation angle").toDouble());
activeConnections(true);
}
Modified: branches/0.3/sources/editor/textfieldeditor.h
===================================================================
--- branches/0.3/sources/editor/textfieldeditor.h 2010-01-03 19:33:41 UTC (rev 832)
+++ branches/0.3/sources/editor/textfieldeditor.h 2010-01-03 19:45:33 UTC (rev 833)
@@ -20,6 +20,7 @@
#include <QtGui>
#include "elementitemeditor.h"
class PartTextField;
+class QTextOrientationWidget;
/**
Cette classe represente un editeur de champ de texte
Elle permet d'editer a travers une interface graphique les
@@ -42,6 +43,7 @@
QSpinBox *font_size;
QCheckBox *rotate;
QDoubleSpinBox *rotation_angle_;
+ QTextOrientationWidget *rotation_widget_;
// methodes
public slots:
Added: branches/0.3/sources/qtextorientationwidget.cpp
===================================================================
--- branches/0.3/sources/qtextorientationwidget.cpp (rev 0)
+++ branches/0.3/sources/qtextorientationwidget.cpp 2010-01-03 19:45:33 UTC (rev 833)
@@ -0,0 +1,349 @@
+/*
+ Copyright 2006-2010 Xavier Guerrin
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "qtextorientationwidget.h"
+
+/**
+ Constructeur
+ Par defaut, ce widget met en valeur les angles multiples de 45 degres
+ et presente un texte oriente a 0 degre, avec la police par defaut de
+ l'application. Le texte affiche est
+ @param parent Widget parent
+*/
+QTextOrientationWidget::QTextOrientationWidget(QWidget *parent) :
+ QWidget(parent),
+ squares_interval_(45.0),
+ current_orientation_(0.0),
+ display_text_(true),
+ must_highlight_angle_(false),
+ read_only_(false)
+{
+ // chaines par defaut
+ text_size_hash_.insert(tr("Ex.", "Short example string"), -1);
+ text_size_hash_.insert(tr("Exemple", "Longer example string"), -1);
+
+ // definit la politique de gestion de la taille de ce widget :
+ // on prefere la sizeHint()
+ QSizePolicy size_policy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ // on souhaite conserver le rapport entre sa hauteur et sa largeur
+ size_policy.setHeightForWidth(true);
+ setSizePolicy(size_policy);
+
+ // suivi de la souris : permet de recevoir les evenements relatifs aux
+ // mouvement de la souris sans que l'utilisateur n'ait a cliquer
+ setMouseTracking(true);
+}
+
+/**
+ Destructeur
+*/
+QTextOrientationWidget::~QTextOrientationWidget() {
+}
+
+/**
+ @param angle la nouvelle orientation / le nouvel angle selectionne(e)
+ 0 degre correspond a un texte horizontal, de gauche a droite
+ 90 degres correspondent a un texte vertical de haut en bas
+*/
+void QTextOrientationWidget::setOrientation(const double &angle) {
+ current_orientation_ = angle;
+ update();
+}
+
+/**
+ @return l'orientation / l'angle actuellement selectionne(e)
+ 0 degre correspond a un texte horizontal, de gauche a droite
+ 90 degres correspondent a un texte vertical de haut en bas
+*/
+double QTextOrientationWidget::orientation() const {
+ return(current_orientation_);
+}
+
+/**
+ Definit la police de caracteres a utiliser pour le texte affiche
+ @param font Une police de caracteres
+*/
+void QTextOrientationWidget::setFont(const QFont &font) {
+ text_font_ = font;
+
+ // invalide le cache contenant les longueurs des textes a disposition
+ foreach(QString text, text_size_hash_.keys()) {
+ text_size_hash_[text] = -1;
+ }
+}
+
+/**
+ @return la police utilisee pour le texte affiche
+*/
+QFont QTextOrientationWidget::font() const {
+ return(text_font_);
+}
+
+/**
+ @param display_text true pour afficher un texte, false sinon
+*/
+void QTextOrientationWidget::setDisplayText(bool display_text) {
+ display_text_ = display_text;
+}
+
+/**
+ @return la police utilisee pour le texte affiche
+*/
+bool QTextOrientationWidget::textDisplayed() const {
+ return(display_text_);
+}
+
+/**
+ @param texts_list Une liste de chaines de caracteres utilisables par le
+ widget afin d'afficher un texte en guise d'exemple. Le widget choisit la
+ chaine la plus appropriee en fonction de sa taille.
+ Note : la liste fournie ne doit pas etre vide. Utilisez setDisplayText si
+ vous ne voulez plus afficher de texte.
+*/
+void QTextOrientationWidget::setUsableTexts(const QStringList &texts_list) {
+ if (texts_list.isEmpty()) return;
+
+ // on oublie les anciennes chaines
+ foreach(QString text, text_size_hash_.keys()) {
+ // il faut oublier les anciennes chaines
+ if (!texts_list.contains(text)) {
+ text_size_hash_.remove(text);
+ }
+ }
+
+ // on ajoute les nouvelles, sans les calculer (on met -1 en guise de longueur)
+ foreach(QString text, texts_list) {
+ if (!text_size_hash_.contains(text)) {
+ text_size_hash_[text] = -1;
+ }
+ }
+}
+
+/**
+ @return la liste des chaines dont le widget dispose pour afficher un texte
+*/
+QStringList QTextOrientationWidget::usableTexts() const {
+ return(text_size_hash_.keys());
+}
+
+/**
+ @return true si le widget est en mode "lecture seule", false sinon
+*/
+bool QTextOrientationWidget::isReadOnly() const {
+ return(read_only_);
+}
+
+/**
+ @param ro true pour passer le widget en mode "lecture seule", false sinon
+*/
+void QTextOrientationWidget::setReadOnly(bool ro) {
+ read_only_ = ro;
+}
+
+/**
+ @return la taille recommandee pour ce widget
+*/
+QSize QTextOrientationWidget::sizeHint() const {
+ return(QSize(50, 50));
+}
+
+/**
+ @param w une largeur donnee
+ @return la hauteur preferee pour une largeur donnee
+ Pour ce widget : retourne la largeur fournie afin de maintenir le widget carre
+*/
+int QTextOrientationWidget::heightForWidth(int w) const {
+ return(w);
+}
+
+/**
+ Effectue le rendu du widget
+ @param event Evenement decrivant la demande de rendu du widget
+*/
+void QTextOrientationWidget::paintEvent(QPaintEvent *event) {
+ Q_UNUSED(event);
+
+ // rectangle de travail avec son centre et son rayon
+ QRect drawing_rectangle(QPoint(0, 0), size());
+ drawing_rectangle.adjust(5, 5, -5, -5);
+
+ QPointF drawing_rectangle_center(drawing_rectangle.center());
+ qreal drawing_rectangle_radius = drawing_rectangle.width() / 2.0;
+
+ QPainter p;
+ p.begin(this);
+
+ p.setRenderHint(QPainter::Antialiasing, true);
+ p.setRenderHint(QPainter::TextAntialiasing, true);
+
+ // cercle gris a fond jaune
+ p.setPen(QPen(QBrush(QColor("#9FA8A8")), 2.0));
+ p.setBrush(QBrush(QColor("#ffffaa")));
+ p.drawEllipse(drawing_rectangle);
+
+ // ligne rouge indiquant l'angle actuel
+ p.setPen(QPen(QBrush(Qt::red), 1.0));
+ p.translate(drawing_rectangle_center);
+ p.rotate(current_orientation_);
+ p.drawLine(QLineF(QPointF(), QPointF(drawing_rectangle_radius, 0.0)));
+
+ // texte optionnel
+ if (display_text_) {
+ // determine le texte a afficher
+ QString chosen_text = getMostUsableStringForRadius(drawing_rectangle_radius);
+ if (!chosen_text.isEmpty()) {
+ p.resetTransform();
+ p.setPen(Qt::black);
+ p.setFont(text_font_);
+ p.translate(drawing_rectangle_center);
+ p.rotate(current_orientation_);
+ p.drawText(QPoint(), chosen_text);
+ }
+ }
+
+ // carres verts a fond vert
+ qreal squares_size = size().width() / 15.0;
+ qreal square_offset = - squares_size / 2.0;
+ QRectF square_qrect = QRect(square_offset, square_offset, squares_size, squares_size);
+ p.setPen(Qt::NoPen);
+ p.setBrush(QBrush(QColor("#248A34")));
+ for (double drawing_angle = 0.0 ; drawing_angle < 360.0 ; drawing_angle += squares_interval_) {
+ if (must_highlight_angle_ && highlight_angle_ == drawing_angle && underMouse()) {
+ p.setBrush(QBrush(QColor("#43FF5F")));
+ }
+ p.resetTransform();
+ p.translate(drawing_rectangle_center);
+ p.rotate(drawing_angle);
+ p.translate(drawing_rectangle_radius - 1.0, 0.0);
+ p.rotate(-45.0);
+ p.drawRect(square_qrect);
+ if (must_highlight_angle_ && highlight_angle_ == drawing_angle) {
+ p.setBrush(QBrush(QColor("#248A34")));
+ }
+ }
+
+ p.end();
+}
+
+/**
+ Gere les mouvements de la souris sur ce widget
+ @param event Evenement decrivant le mouvement de la souris
+*/
+void QTextOrientationWidget::mouseMoveEvent(QMouseEvent *event) {
+ if (read_only_) return;
+
+ bool drawn_angle_hovered = positionIsASquare(event -> posF(), &highlight_angle_);
+
+ if (must_highlight_angle_ != drawn_angle_hovered) {
+ must_highlight_angle_ = drawn_angle_hovered;
+ update();
+ }
+}
+
+/**
+ Gere les relachements de la souris sur ce widget
+ @param event Evenement decrivant le relachement de la souris
+*/
+void QTextOrientationWidget::mouseReleaseEvent(QMouseEvent *event) {
+ if (read_only_) return;
+
+ double clicked_angle;
+ bool drawn_angle_clicked = positionIsASquare(event -> posF(), &clicked_angle);
+
+ if (drawn_angle_clicked) {
+ setOrientation(clicked_angle);
+ emit(orientationChanged(clicked_angle));
+ must_highlight_angle_ = false;
+ update();
+ }
+}
+
+/**
+ @param radius Rayon du cercle qui limitera le rendu du texte
+ @return la chaine la plus appropriee en fonction de la taille du widget.
+*/
+QString QTextOrientationWidget::getMostUsableStringForRadius(const qreal &radius) {
+ // s'assure que l'on connait la longueur de chaque texte a disposition
+ generateTextSizeHash();
+
+ // recupere les longueurs a disposition
+ QList<qreal> available_lengths = text_size_hash_.values();
+ // trie les longueurs par ordre croissant
+ qSort(available_lengths.begin(), available_lengths.end());
+ // recherche la position ou l'on insererait le rayon
+ QList<qreal>::const_iterator i = qUpperBound(available_lengths, radius);
+
+ // la valeur precedent cette position est donc celle qui nous interesse
+ if (i == available_lengths.begin()) {
+ // nous sommes au debut de la liste - nous ne pouvons donc pas afficher de chaine
+ return(QString());
+ } else {
+ -- i;
+ qreal final_length = *i;
+ QString final_string = text_size_hash_.keys(final_length).first();
+ return(final_string);
+ }
+}
+
+/**
+ S'assure que le hash associant les textes utilisables a leur taille soit
+ correctement rempli.
+*/
+void QTextOrientationWidget::generateTextSizeHash() {
+ QFontMetrics font_metrics(text_font_);
+ foreach(QString text, text_size_hash_.keys()) {
+ if (text_size_hash_[text] == -1) {
+ text_size_hash_[text] = font_metrics.boundingRect(text).width();
+ }
+ }
+}
+
+/**
+ Determine si une position donnee correspond a un des carres representant un
+ angle pertinent.
+ @param pos Position donnee
+ @param angle_value_ptr Si different de 0, le double pointe par ce parametre
+ vaudra l'angle pertinent concerne
+*/
+bool QTextOrientationWidget::positionIsASquare(const QPointF &pos, double *angle_value_ptr) {
+ // rectangle de travail avec son centre et son rayon
+ QRect drawing_rectangle(QPoint(0, 0), size());
+ drawing_rectangle.adjust(5, 5, -5, -5);
+
+ QPointF drawing_rectangle_center(drawing_rectangle.center());
+ qreal drawing_rectangle_radius = drawing_rectangle.width() / 2.0;
+
+ qreal squares_size = size().width() / 15.0;
+ qreal square_offset = - squares_size / 2.0;
+ QRectF square_qrect = QRect(square_offset, square_offset, squares_size, squares_size);
+
+ for (double drawing_angle = 0.0 ; drawing_angle < 360.0 ; drawing_angle += squares_interval_) {
+ QTransform transform = QTransform()
+ .translate(drawing_rectangle_center.x(), drawing_rectangle_center.y())
+ .rotate(drawing_angle)
+ .translate(drawing_rectangle_radius - 1.0, 0.0)
+ .rotate(-45.0);
+
+ QRectF mapped_rectangle = transform.mapRect(square_qrect);
+ if (mapped_rectangle.contains(pos)) {
+ if (angle_value_ptr) *angle_value_ptr = drawing_angle;
+ return(true);
+ }
+ }
+
+ return(false);
+}
Added: branches/0.3/sources/qtextorientationwidget.h
===================================================================
--- branches/0.3/sources/qtextorientationwidget.h (rev 0)
+++ branches/0.3/sources/qtextorientationwidget.h 2010-01-03 19:45:33 UTC (rev 833)
@@ -0,0 +1,91 @@
+/*
+ Copyright 2006-2010 Xavier Guerrin
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef Q_TEXT_ORIENTATION_WIDGET_H
+#define Q_TEXT_ORIENTATION_WIDGET_H
+#include <QtGui>
+/**
+ Cette classe permet de representer graphiquement l'orientation d'un texte.
+*/
+class QTextOrientationWidget : public QWidget {
+ Q_OBJECT
+
+ // constructeurs, destructeur
+ public:
+ QTextOrientationWidget(QWidget * = 0);
+ virtual ~QTextOrientationWidget();
+ private:
+ QTextOrientationWidget(const QTextOrientationWidget &);
+ QTextOrientationWidget &operator=(const QTextOrientationWidget &);
+
+ // methodes publiques
+ public:
+ double orientation() const;
+ void setFont(const QFont &);
+ QFont font() const;
+ void setDisplayText(bool);
+ bool textDisplayed() const;
+ void setUsableTexts(const QStringList &);
+ QStringList usableTexts() const;
+ bool isReadOnly() const;
+ void setReadOnly(bool);
+
+ // slots publics
+ public slots:
+ void setOrientation(const double &);
+
+ protected:
+ virtual QSize sizeHint () const;
+ int heightForWidth(int) const;
+ virtual void paintEvent(QPaintEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+
+ // signaux
+ signals:
+ /**
+ Signal emis lorsque l'utilisateur specifie une orientation en cliquant
+ sur le widget
+ */
+ void orientationChanged(double);
+
+ // attributs prives
+ private:
+ /// Intervalle entre les petits angles privilegies, en degres
+ double squares_interval_;
+ /// angle represente
+ double current_orientation_;
+ /// Booleen indiquant s'il faut afficher ou non un texte
+ bool display_text_;
+ /// Police utilisee pour le texte affiche
+ QFont text_font_;
+ /// Hash associant les textes disponible a leur longueur en pixels
+ QHash<QString, qreal> text_size_hash_;
+ /// Angle specifique a mettre en valeur
+ double highlight_angle_;
+ /// Booleen indiquant s'il faut mettre en valeur un des angles
+ bool must_highlight_angle_;
+ /// Booleen indiquant si le widget est en mode "lecture seule" ou non
+ bool read_only_;
+
+ // methodes privees
+ private:
+ QString getMostUsableStringForRadius(const qreal &);
+ void generateTextSizeHash();
+ bool positionIsASquare(const QPointF &, double * = 0);
+};
+#endif