string_plugin.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2015, Southwest Research Institute® (SwRI®)
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * 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 // * Neither the name of Southwest Research Institute® (SwRI®) nor the
14 // names of its contributors may be used to endorse or promote products
15 // derived from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL Southwest Research Institute® BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 // DAMAGE.
28 //
29 // *****************************************************************************
30 
32 
35 
36 #include <QFontDialog>
37 
39 
40 namespace mapviz_plugins
41 {
42  const char* StringPlugin::COLOR_KEY = "color";
43  const char* StringPlugin::FONT_KEY = "font";
44  const char* StringPlugin::TOPIC_KEY = "topic";
45  const char* StringPlugin::ANCHOR_KEY = "anchor";
46  const char* StringPlugin::UNITS_KEY = "units";
47  const char* StringPlugin::OFFSET_X_KEY = "offset_x";
48  const char* StringPlugin::OFFSET_Y_KEY = "offset_y";
49 
50  StringPlugin::StringPlugin() :
51  config_widget_(new QWidget()),
52  anchor_(TOP_LEFT),
53  units_(PIXELS),
54  offset_x_(0),
55  offset_y_(0),
56  has_message_(false),
57  has_painted_(false),
58  color_(Qt::black)
59  {
60  ui_.setupUi(config_widget_);
61  // Set background white
62  QPalette p(config_widget_->palette());
63  p.setColor(QPalette::Background, Qt::white);
64  config_widget_->setPalette(p);
65 
66  // Set status text red
67  QPalette p3(ui_.status->palette());
68  p3.setColor(QPalette::Text, Qt::red);
69  ui_.status->setPalette(p3);
70 
71  QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
72  QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
73  QObject::connect(ui_.anchor, SIGNAL(activated(QString)), this, SLOT(SetAnchor(QString)));
74  QObject::connect(ui_.units, SIGNAL(activated(QString)), this, SLOT(SetUnits(QString)));
75  QObject::connect(ui_.offsetx, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetX(int)));
76  QObject::connect(ui_.offsety, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetY(int)));
77  QObject::connect(ui_.font_button, SIGNAL(clicked()), this, SLOT(SelectFont()));
78  QObject::connect(ui_.color, SIGNAL(colorEdited(const QColor &)), this, SLOT(SelectColor()));
79 
80  font_.setFamily(tr("Helvetica"));
81  ui_.font_button->setFont(font_);
82  ui_.font_button->setText(font_.family());
83 
84  ui_.color->setColor(color_);
85  }
86 
88  {
89  }
90 
91  bool StringPlugin::Initialize(QGLWidget* canvas)
92  {
93  canvas_ = canvas;
94  return true;
95  }
96 
97  void StringPlugin::Draw(double x, double y, double scale)
98  {
99  // This plugin doesn't do any OpenGL drawing.
100  }
101 
102  void StringPlugin::Paint(QPainter* painter, double x, double y, double scale)
103  {
104  if (has_message_)
105  {
106  painter->save();
107  painter->resetTransform();
108  painter->setFont(font_);
109 
110  if (!has_painted_)
111  {
112  // After the first time we get a new message, we do not know how wide it's
113  // going to be when rendered, so we can't accurately calculate the top left
114  // coordinate if it's offset from the right or bottom borders.
115  // The easiest workaround I've found for this is to draw it once using
116  // a completely transparent pen, which will cause the QStaticText class to
117  // know how wide it is; then we can recalculate the offsets and draw it
118  // again with a visible pen.
119  QPen invisPen(QBrush(Qt::transparent), 1);
120  painter->setPen(invisPen);
121  PaintText(painter);
122  has_painted_ = true;
123  }
124  QPen pen(QBrush(color_), 1);
125  painter->setPen(pen);
126  PaintText(painter);
127 
128  painter->restore();
129  PrintInfo("OK");
130  }
131  else
132  {
133  PrintWarning("No messages received.");
134  }
135  }
136 
137  void StringPlugin::PaintText(QPainter* painter)
138  {
139  // Calculate the correct offsets and dimensions
140  int x_offset = offset_x_;
141  int y_offset = offset_y_;
142  if (units_ == PERCENT)
143  {
144  x_offset = static_cast<int>((float)(offset_x_ * canvas_->width()) / 100.0);
145  y_offset = static_cast<int>((float)(offset_y_ * canvas_->height()) / 100.0);
146  }
147 
148  int right = static_cast<int>((float)canvas_->width() - message_.size().width()) - x_offset;
149  int bottom = static_cast<int>((float)canvas_->height() - message_.size().height()) - y_offset;
150  int yCenter = static_cast<int>((float)canvas_->height() / 2.0 - message_.size().height()/2.0);
151  int xCenter = static_cast<int>((float)canvas_->width() / 2.0 - message_.size().width()/2.0);
152 
153  QPoint ulPoint;
154 
155  switch (anchor_)
156  {
157  case TOP_LEFT:
158  ulPoint.setX(x_offset);
159  ulPoint.setY(y_offset);
160  break;
161  case TOP_CENTER:
162  ulPoint.setX(xCenter);
163  ulPoint.setY(y_offset);
164  break;
165  case TOP_RIGHT:
166  ulPoint.setX(right);
167  ulPoint.setY(y_offset);
168  break;
169  case CENTER_LEFT:
170  ulPoint.setX(x_offset);
171  ulPoint.setY(yCenter);
172  break;
173  case CENTER:
174  ulPoint.setX(xCenter);
175  ulPoint.setY(yCenter);
176  break;
177  case CENTER_RIGHT:
178  ulPoint.setX(right);
179  ulPoint.setY(yCenter);
180  break;
181  case BOTTOM_LEFT:
182  ulPoint.setX(x_offset);
183  ulPoint.setY(bottom);
184  break;
185  case BOTTOM_CENTER:
186  ulPoint.setX(xCenter);
187  ulPoint.setY(bottom);
188  break;
189  case BOTTOM_RIGHT:
190  ulPoint.setX(right);
191  ulPoint.setY(bottom);
192  break;
193  }
194  painter->drawStaticText(ulPoint, message_);
195  }
196 
197  void StringPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
198  {
199  if (node[TOPIC_KEY])
200  {
201  ui_.topic->setText(QString(node[TOPIC_KEY].as<std::string>().c_str()));
202  TopicEdited();
203  }
204 
205  if (node[FONT_KEY])
206  {
207  font_.fromString(QString(node[FONT_KEY].as<std::string>().c_str()));
208  ui_.font_button->setFont(font_);
209  ui_.font_button->setText(font_.family());
210  }
211 
212  if (node[COLOR_KEY])
213  {
214  color_ = QColor(node[COLOR_KEY].as<std::string>().c_str());
215  ui_.color->setColor(QColor(color_.name().toStdString().c_str()));
216  }
217 
218  if (node[ANCHOR_KEY])
219  {
220  std::string anchor = node[ANCHOR_KEY].as<std::string>();
221  ui_.anchor->setCurrentIndex(ui_.anchor->findText(anchor.c_str()));
222  SetAnchor(anchor.c_str());
223  }
224 
225  if (node[UNITS_KEY])
226  {
227  std::string units = node[UNITS_KEY].as<std::string>();
228  ui_.units->setCurrentIndex(ui_.units->findText(units.c_str()));
229  SetUnits(units.c_str());
230  }
231 
232  if (node[OFFSET_X_KEY])
233  {
234  offset_x_ = node[OFFSET_X_KEY].as<int>();
235  ui_.offsetx->setValue(offset_x_);
236  }
237 
238  if (node[OFFSET_Y_KEY])
239  {
240  offset_y_ = node[OFFSET_Y_KEY].as<int>();
241  ui_.offsety->setValue(offset_y_);
242  }
243  }
244 
245  void StringPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
246  {
247  emitter << YAML::Key << FONT_KEY << YAML::Value << font_.toString().toStdString();
248  emitter << YAML::Key << COLOR_KEY << YAML::Value << color_.name().toStdString();
249  emitter << YAML::Key << TOPIC_KEY << YAML::Value << ui_.topic->text().toStdString();
250  emitter << YAML::Key << ANCHOR_KEY << YAML::Value << AnchorToString(anchor_);
251  emitter << YAML::Key << UNITS_KEY << YAML::Value << UnitsToString(units_);
252  emitter << YAML::Key << OFFSET_X_KEY << YAML::Value << offset_x_;
253  emitter << YAML::Key << OFFSET_Y_KEY << YAML::Value << offset_y_;
254  }
255 
256  QWidget* StringPlugin::GetConfigWidget(QWidget* parent)
257  {
258  config_widget_->setParent(parent);
259  return config_widget_;
260  }
261 
262  void StringPlugin::PrintError(const std::string& message)
263  {
264  PrintErrorHelper(ui_.status, message);
265  }
266 
267  void StringPlugin::PrintInfo(const std::string& message)
268  {
269  PrintInfoHelper(ui_.status, message);
270  }
271 
272  void StringPlugin::PrintWarning(const std::string& message)
273  {
274  PrintWarningHelper(ui_.status, message);
275  }
276 
278  {
279  color_ = ui_.color->color();
280  }
281 
283  {
284  bool ok;
285  QFont font = QFontDialog::getFont(&ok, font_, canvas_);
286  if (ok)
287  {
288  font_ = font;
289  message_.prepare(QTransform(), font_);
290  ui_.font_button->setFont(font_);
291  ui_.font_button->setText(font_.family());
292  }
293  }
294 
296  {
298  "std_msgs/String", "marti_common_msgs/StringStamped");
299 
300  if (!topic.name.empty())
301  {
302  ui_.topic->setText(QString::fromStdString(topic.name));
303  TopicEdited();
304  }
305  }
306 
308  {
309  std::string topic = ui_.topic->text().trimmed().toStdString();
310  if (topic != topic_)
311  {
312  initialized_ = false;
313  has_message_ = false;
314  PrintWarning("No messages received.");
315 
317 
318  topic_ = topic;
319  if (!topic.empty())
320  {
322 
323  ROS_INFO("Subscribing to %s", topic_.c_str());
324  }
325  }
326  }
327 
328  void StringPlugin::SetAnchor(QString anchor)
329  {
330  if (anchor == "top left")
331  {
332  anchor_ = TOP_LEFT;
333  }
334  else if (anchor == "top center")
335  {
337  }
338  else if (anchor == "top right")
339  {
340  anchor_ = TOP_RIGHT;
341  }
342  else if (anchor == "center left")
343  {
345  }
346  else if (anchor == "center")
347  {
348  anchor_ = CENTER;
349  }
350  else if (anchor == "center right")
351  {
353  }
354  else if (anchor == "bottom left")
355  {
357  }
358  else if (anchor == "bottom center")
359  {
361  }
362  else if (anchor == "bottom right")
363  {
365  }
366  }
367 
368  void StringPlugin::SetUnits(QString units)
369  {
370  if (units == "pixels")
371  {
372  units_ = PIXELS;
373  }
374  else if (units == "percent")
375  {
376  units_ = PERCENT;
377  }
378  }
379 
380  void StringPlugin::SetOffsetX(int offset)
381  {
382  offset_x_ = offset;
383  }
384 
385  void StringPlugin::SetOffsetY(int offset)
386  {
387  offset_y_ = offset;
388  }
389 
390  template <class T, class M>
391  bool is_instance(const M& msg)
392  {
393  return msg->getDataType() == ros::message_traits::datatype<T>();
394  }
395 
397  {
398  if (is_instance<std_msgs::String>(msg))
399  {
400  message_.setText(QString(msg->instantiate<std_msgs::String>()->data.c_str()));
401  }
402  else if (is_instance<marti_common_msgs::StringStamped>(msg))
403  {
404  message_.setText(QString(msg->instantiate<marti_common_msgs::StringStamped>()->value.c_str()));
405  }
406 
407  message_.prepare(QTransform(), font_);
408 
409  has_message_ = true;
410  has_painted_ = false;
411  initialized_ = true;
412  }
413 
415  {
416  std::string anchor_string = "top left";
417 
418  if (anchor == TOP_LEFT)
419  {
420  anchor_string = "top left";
421  }
422  else if (anchor == TOP_CENTER)
423  {
424  anchor_string = "top center";
425  }
426  else if (anchor == TOP_RIGHT)
427  {
428  anchor_string = "top right";
429  }
430  else if (anchor == CENTER_LEFT)
431  {
432  anchor_string = "center left";
433  }
434  else if (anchor == CENTER)
435  {
436  anchor_string = "center";
437  }
438  else if (anchor == CENTER_RIGHT)
439  {
440  anchor_string = "center right";
441  }
442  else if (anchor == BOTTOM_LEFT)
443  {
444  anchor_string = "bottom left";
445  }
446  else if (anchor == BOTTOM_CENTER)
447  {
448  anchor_string = "bottom center";
449  }
450  else if (anchor == BOTTOM_RIGHT)
451  {
452  anchor_string = "bottom right";
453  }
454 
455  return anchor_string;
456  }
457 
459  {
460  std::string units_string = "pixels";
461 
462  if (units == PIXELS)
463  {
464  units_string = "pixels";
465  }
466  else if (units == PERCENT)
467  {
468  units_string = "percent";
469  }
470 
471  return units_string;
472  }
473 }
msg
QWidget * GetConfigWidget(QWidget *parent)
static ros::master::TopicInfo selectTopic(const std::string &datatype, QWidget *parent=0)
void PrintInfo(const std::string &message)
void stringCallback(const topic_tools::ShapeShifter::ConstPtr &msg)
ros::NodeHandle node_
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void PrintError(const std::string &message)
static const char * COLOR_KEY
std::string AnchorToString(Anchor anchor)
static void PrintWarningHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
static void PrintErrorHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
bool Initialize(QGLWidget *canvas)
void SaveConfig(YAML::Emitter &emitter, const std::string &path)
static void PrintInfoHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
static const char * ANCHOR_KEY
static const char * TOPIC_KEY
void PaintText(QPainter *painter)
#define ROS_INFO(...)
void SetUnits(QString units)
void Paint(QPainter *painter, double x, double y, double scale)
static const char * FONT_KEY
static const char * UNITS_KEY
static const char * OFFSET_Y_KEY
void Draw(double x, double y, double scale)
void LoadConfig(const YAML::Node &node, const std::string &path)
std::string UnitsToString(Units units)
static const char * OFFSET_X_KEY
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void SetAnchor(QString anchor)
void PrintWarning(const std::string &message)
bool is_instance(const M &msg)


mapviz_plugins
Author(s): Marc Alban
autogenerated on Fri Mar 19 2021 02:44:32