[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


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/