QElectroTech  0.70
qtextorientationwidget.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2006-2019 The QElectroTech Team
3  This file is part of QElectroTech.
4 
5  QElectroTech is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  QElectroTech is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "qtextorientationwidget.h"
19 #include <algorithm>
20 
29  QWidget(parent),
30  squares_interval_(45.0),
31  current_orientation_(0.0),
32  display_text_(true),
33  must_highlight_angle_(false),
34  read_only_(false)
35 {
36  // chaines par defaut
37  text_size_hash_.insert(tr("Ex.", "Short example string"), -1);
38  text_size_hash_.insert(tr("Exemple", "Longer example string"), -1);
39 
40  // definit la politique de gestion de la taille de ce widget :
41  // on prefere la sizeHint()
42  QSizePolicy size_policy(QSizePolicy::Minimum, QSizePolicy::Minimum);
43  // on souhaite conserver le rapport entre sa hauteur et sa largeur
44  size_policy.setHeightForWidth(true);
45  setSizePolicy(size_policy);
46 
47  // suivi de la souris : permet de recevoir les evenements relatifs aux
48  // mouvement de la souris sans que l'utilisateur n'ait a cliquer
49  setMouseTracking(true);
50 }
51 
56 }
57 
63 void QTextOrientationWidget::setOrientation(const double &angle) {
64  current_orientation_ = angle;
65  update();
66 }
67 
74  return(current_orientation_);
75 }
76 
81 void QTextOrientationWidget::setFont(const QFont &font) {
82  text_font_ = font;
83 
84  // invalide le cache contenant les longueurs des textes a disposition
85  foreach(QString text, text_size_hash_.keys()) {
86  text_size_hash_[text] = -1;
87  }
88 }
89 
94  return(text_font_);
95 }
96 
100 void QTextOrientationWidget::setDisplayText(bool display_text) {
101  display_text_ = display_text;
102 }
103 
108  return(display_text_);
109 }
110 
118 void QTextOrientationWidget::setUsableTexts(const QStringList &texts_list) {
119  if (texts_list.isEmpty()) return;
120 
121  // on oublie les anciennes chaines
122  foreach(QString text, text_size_hash_.keys()) {
123  // il faut oublier les anciennes chaines
124  if (!texts_list.contains(text)) {
125  text_size_hash_.remove(text);
126  }
127  }
128 
129  // on ajoute les nouvelles, sans les calculer (on met -1 en guise de longueur)
130  foreach(QString text, texts_list) {
131  if (!text_size_hash_.contains(text)) {
132  text_size_hash_[text] = -1;
133  }
134  }
135 }
136 
141  return(text_size_hash_.keys());
142 }
143 
148  return(read_only_);
149 }
150 
155  read_only_ = ro;
156 }
157 
162  return(QSize(50, 50));
163 }
164 
171  return(w);
172 }
173 
178 void QTextOrientationWidget::paintEvent(QPaintEvent *event) {
179  Q_UNUSED(event);
180 
181  // rectangle de travail avec son centre et son rayon
182  QRect drawing_rectangle(QPoint(0, 0), size());
183  drawing_rectangle.adjust(5, 5, -5, -5);
184 
185  QPointF drawing_rectangle_center(drawing_rectangle.center());
186  qreal drawing_rectangle_radius = drawing_rectangle.width() / 2.0;
187 
188  QPainter p;
189  p.begin(this);
190 
191  p.setRenderHint(QPainter::Antialiasing, true);
192  p.setRenderHint(QPainter::TextAntialiasing, true);
193 
194  // cercle gris a fond jaune
195  p.setPen(QPen(QBrush(QColor("#9FA8A8")), 2.0));
196  p.setBrush(QBrush(QColor("#ffffaa")));
197  p.drawEllipse(drawing_rectangle);
198 
199  // ligne rouge indiquant l'angle actuel
200  p.setPen(QPen(QBrush(Qt::red), 1.0));
201  p.translate(drawing_rectangle_center);
202  p.rotate(current_orientation_);
203  p.drawLine(QLineF(QPointF(), QPointF(drawing_rectangle_radius, 0.0)));
204 
205  // texte optionnel
206  if (display_text_) {
207  // determine le texte a afficher
208  QString chosen_text = getMostUsableStringForRadius(drawing_rectangle_radius);
209  if (!chosen_text.isEmpty()) {
210  p.resetTransform();
211  p.setPen(Qt::black);
212  p.setFont(text_font_);
213  p.translate(drawing_rectangle_center);
214  p.rotate(current_orientation_);
215  p.drawText(QPoint(), chosen_text);
216  }
217  }
218 
219  // carres verts a fond vert
220  qreal squares_size = size().width() / 15.0;
221  qreal square_offset = - squares_size / 2.0;
222  QRectF square_qrect = QRect(square_offset, square_offset, squares_size, squares_size);
223  p.setPen(Qt::NoPen);
224  p.setBrush(QBrush(QColor("#248A34")));
225  for (double drawing_angle = 0.0 ; drawing_angle < 360.0 ; drawing_angle += squares_interval_) {
226  if (must_highlight_angle_ && highlight_angle_ == drawing_angle && underMouse()) {
227  p.setBrush(QBrush(QColor("#43FF5F")));
228  }
229  p.resetTransform();
230  p.translate(drawing_rectangle_center);
231  p.rotate(drawing_angle);
232  p.translate(drawing_rectangle_radius - 1.0, 0.0);
233  p.rotate(-45.0);
234  p.drawRect(square_qrect);
235  if (must_highlight_angle_ && highlight_angle_ == drawing_angle) {
236  p.setBrush(QBrush(QColor("#248A34")));
237  }
238  }
239 
240  p.end();
241 }
242 
247 void QTextOrientationWidget::mouseMoveEvent(QMouseEvent *event) {
248  if (read_only_) return;
249 
250  bool drawn_angle_hovered = positionIsASquare(event -> localPos(), &highlight_angle_);
251 
252  if (must_highlight_angle_ != drawn_angle_hovered) {
253  must_highlight_angle_ = drawn_angle_hovered;
254  update();
255  }
256 }
257 
263  if (read_only_) return;
264 
265  double clicked_angle;
266  bool drawn_angle_clicked = positionIsASquare(event -> localPos(), &clicked_angle);
267 
268  if (drawn_angle_clicked) {
269  setOrientation(clicked_angle);
270  emit(orientationChanged(clicked_angle));
271  must_highlight_angle_ = false;
272  update();
273  }
274 }
275 
281  // s'assure que l'on connait la longueur de chaque texte a disposition
283 
284  // recupere les longueurs a disposition
285  QList<qreal> available_lengths = text_size_hash_.values();
286  // trie les longueurs par ordre croissant
287  std::sort(available_lengths.begin(), available_lengths.end());
288  // recherche la position ou l'on insererait le rayon
289  QList<qreal>::const_iterator i = qUpperBound(available_lengths, radius);
290 
291  // la valeur precedent cette position est donc celle qui nous interesse
292  if (i == available_lengths.begin()) {
293  // nous sommes au debut de la liste - nous ne pouvons donc pas afficher de chaine
294  return(QString());
295  } else {
296  -- i;
297  qreal final_length = *i;
298  QString final_string = text_size_hash_.keys(final_length).first();
299  return(final_string);
300  }
301 }
302 
308  QFontMetrics font_metrics(text_font_);
309  foreach(QString text, text_size_hash_.keys()) {
310  if (text_size_hash_[text] == -1) {
311  text_size_hash_[text] = font_metrics.boundingRect(text).width();
312  }
313  }
314 }
315 
323 bool QTextOrientationWidget::positionIsASquare(const QPointF &pos, double *angle_value_ptr) {
324  // rectangle de travail avec son centre et son rayon
325  QRect drawing_rectangle(QPoint(0, 0), size());
326  drawing_rectangle.adjust(5, 5, -5, -5);
327 
328  QPointF drawing_rectangle_center(drawing_rectangle.center());
329  qreal drawing_rectangle_radius = drawing_rectangle.width() / 2.0;
330 
331  qreal squares_size = size().width() / 15.0;
332  qreal square_offset = - squares_size / 2.0;
333  QRectF square_qrect = QRect(square_offset, square_offset, squares_size, squares_size);
334 
335  for (double drawing_angle = 0.0 ; drawing_angle < 360.0 ; drawing_angle += squares_interval_) {
336  QTransform transform = QTransform()
337  .translate(drawing_rectangle_center.x(), drawing_rectangle_center.y())
338  .rotate(drawing_angle)
339  .translate(drawing_rectangle_radius - 1.0, 0.0)
340  .rotate(-45.0);
341 
342  QRectF mapped_rectangle = transform.mapRect(square_qrect);
343  if (mapped_rectangle.contains(pos)) {
344  if (angle_value_ptr) *angle_value_ptr = drawing_angle;
345  return(true);
346  }
347  }
348 
349  return(false);
350 }
double squares_interval_
Interval between commonly used angles (represented by squares), in degrees.
double highlight_angle_
Specific angle to be highlighted.
QString getMostUsableStringForRadius(const qreal &)
void paintEvent(QPaintEvent *) override
double current_orientation_
current angle
void setOrientation(const double &)
bool display_text_
Whether to display an example text.
void setUsableTexts(const QStringList &)
void mouseReleaseEvent(QMouseEvent *) override
QHash< QString, qreal > text_size_hash_
Associate available example texts with their length (in pixels)
bool read_only_
Whether this widget is read only.
QIcon tr
Definition: qeticons.cpp:204
void mouseMoveEvent(QMouseEvent *) override
int heightForWidth(int) const override
bool positionIsASquare(const QPointF &, double *=nullptr)
QIcon ro
Definition: qeticons.cpp:199
QSize sizeHint() const override
bool must_highlight_angle_
Whether to highlight a specific angle.
QTextOrientationWidget(QWidget *=nullptr)
void orientationChanged(double)
QFont text_font_
Font used to render the example text.