string_plugin.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2015, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL Southwest Research Institute® BE LIABLE 
00021 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
00022 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00023 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00024 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00025 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00026 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00027 // DAMAGE.
00028 //
00029 // *****************************************************************************
00030 
00031 #include <mapviz_plugins/string_plugin.h>
00032 
00033 #include <pluginlib/class_list_macros.h>
00034 #include <mapviz/select_topic_dialog.h>
00035 
00036 #include <QFontDialog>
00037 
00038 PLUGINLIB_EXPORT_CLASS(mapviz_plugins::StringPlugin, mapviz::MapvizPlugin)
00039 
00040 namespace mapviz_plugins
00041 {
00042   const char* StringPlugin::COLOR_KEY = "color";
00043   const char* StringPlugin::FONT_KEY = "font";
00044   const char* StringPlugin::TOPIC_KEY = "topic";
00045   const char* StringPlugin::ANCHOR_KEY = "anchor";
00046   const char* StringPlugin::UNITS_KEY = "units";
00047   const char* StringPlugin::OFFSET_X_KEY = "offset_x";
00048   const char* StringPlugin::OFFSET_Y_KEY = "offset_y";
00049 
00050   StringPlugin::StringPlugin() :
00051     config_widget_(new QWidget()),
00052     anchor_(TOP_LEFT),
00053     units_(PIXELS),
00054     offset_x_(0),
00055     offset_y_(0),
00056     has_message_(false),
00057     has_painted_(false),
00058     color_(Qt::black)
00059   {
00060     ui_.setupUi(config_widget_);
00061     // Set background white
00062     QPalette p(config_widget_->palette());
00063     p.setColor(QPalette::Background, Qt::white);
00064     config_widget_->setPalette(p);
00065 
00066     // Set status text red
00067     QPalette p3(ui_.status->palette());
00068     p3.setColor(QPalette::Text, Qt::red);
00069     ui_.status->setPalette(p3);
00070 
00071     QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
00072     QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
00073     QObject::connect(ui_.anchor, SIGNAL(activated(QString)), this, SLOT(SetAnchor(QString)));
00074     QObject::connect(ui_.units, SIGNAL(activated(QString)), this, SLOT(SetUnits(QString)));
00075     QObject::connect(ui_.offsetx, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetX(int)));
00076     QObject::connect(ui_.offsety, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetY(int)));
00077     QObject::connect(ui_.font_button, SIGNAL(clicked()), this, SLOT(SelectFont()));
00078     QObject::connect(ui_.color, SIGNAL(colorEdited(const QColor &)), this, SLOT(SelectColor()));
00079 
00080     font_.setFamily(tr("Helvetica"));
00081     ui_.font_button->setFont(font_);
00082     ui_.font_button->setText(font_.family());
00083 
00084     ui_.color->setColor(color_);
00085   }
00086 
00087   StringPlugin::~StringPlugin()
00088   {
00089   }
00090 
00091   bool StringPlugin::Initialize(QGLWidget* canvas)
00092   {
00093     canvas_ = canvas;
00094     return true;
00095   }
00096 
00097   void StringPlugin::Draw(double x, double y, double scale)
00098   {
00099     // This plugin doesn't do any  OpenGL drawing.
00100   }
00101 
00102   void StringPlugin::Paint(QPainter* painter, double x, double y, double scale)
00103   {
00104     if (has_message_)
00105     {
00106       painter->save();
00107       painter->resetTransform();
00108       painter->setFont(font_);
00109 
00110       if (!has_painted_)
00111       {
00112         // After the first time we get a new message, we do not know how wide it's
00113         // going to be when rendered, so we can't accurately calculate the top left
00114         // coordinate if it's offset from the right or bottom borders.
00115         // The easiest workaround I've found for this is to draw it once using
00116         // a completely transparent pen, which will cause the QStaticText class to
00117         // know how wide it is; then we can recalculate the offsets and draw it
00118         // again with a visible pen.
00119         QPen invisPen(QBrush(Qt::transparent), 1);
00120         painter->setPen(invisPen);
00121         PaintText(painter);
00122         has_painted_ = true;
00123       }
00124       QPen pen(QBrush(color_), 1);
00125       painter->setPen(pen);
00126       PaintText(painter);
00127 
00128       painter->restore();
00129       PrintInfo("OK");
00130     }
00131     else
00132     {
00133       PrintWarning("No messages received.");
00134     }
00135   }
00136 
00137   void StringPlugin::PaintText(QPainter* painter)
00138   {
00139     // Calculate the correct offsets and dimensions
00140     int x_offset = offset_x_;
00141     int y_offset = offset_y_;
00142     if (units_ == PERCENT)
00143     {
00144       x_offset = static_cast<int>((float)(offset_x_ * canvas_->width()) / 100.0);
00145       y_offset = static_cast<int>((float)(offset_y_ * canvas_->height()) / 100.0);
00146     }
00147 
00148     int right = static_cast<int>((float)canvas_->width() - message_.size().width()) - x_offset;
00149     int bottom = static_cast<int>((float)canvas_->height() - message_.size().height()) - y_offset;
00150     int yCenter = static_cast<int>((float)canvas_->height() / 2.0 - message_.size().height()/2.0);
00151     int xCenter = static_cast<int>((float)canvas_->width() / 2.0 - message_.size().width()/2.0);
00152 
00153     QPoint ulPoint;
00154 
00155     switch (anchor_)
00156     {
00157       case TOP_LEFT:
00158         ulPoint.setX(x_offset);
00159         ulPoint.setY(y_offset);
00160         break;
00161       case TOP_CENTER:
00162         ulPoint.setX(xCenter);
00163         ulPoint.setY(y_offset);
00164         break;
00165       case TOP_RIGHT:
00166         ulPoint.setX(right);
00167         ulPoint.setY(y_offset);
00168         break;
00169       case CENTER_LEFT:
00170         ulPoint.setX(x_offset);
00171         ulPoint.setY(yCenter);
00172         break;
00173       case CENTER:
00174         ulPoint.setX(xCenter);
00175         ulPoint.setY(yCenter);
00176         break;
00177       case CENTER_RIGHT:
00178         ulPoint.setX(right);
00179         ulPoint.setY(yCenter);
00180         break;
00181       case BOTTOM_LEFT:
00182         ulPoint.setX(x_offset);
00183         ulPoint.setY(bottom);
00184         break;
00185       case BOTTOM_CENTER:
00186         ulPoint.setX(xCenter);
00187         ulPoint.setY(bottom);
00188         break;
00189       case BOTTOM_RIGHT:
00190         ulPoint.setX(right);
00191         ulPoint.setY(bottom);
00192         break;
00193     }
00194     painter->drawStaticText(ulPoint, message_);
00195   }
00196 
00197   void StringPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00198   {
00199     if (node[TOPIC_KEY])
00200     {
00201       ui_.topic->setText(QString(node[TOPIC_KEY].as<std::string>().c_str()));
00202       TopicEdited();
00203     }
00204 
00205     if (node[FONT_KEY])
00206     {
00207       font_.fromString(QString(node[FONT_KEY].as<std::string>().c_str()));
00208       ui_.font_button->setFont(font_);
00209       ui_.font_button->setText(font_.family());
00210     }
00211 
00212     if (node[COLOR_KEY])
00213     {
00214       color_ = QColor(node[COLOR_KEY].as<std::string>().c_str());
00215       ui_.color->setColor(QColor(color_.name().toStdString().c_str()));
00216     }
00217 
00218     if (node[ANCHOR_KEY])
00219     {
00220       std::string anchor = node[ANCHOR_KEY].as<std::string>();
00221       ui_.anchor->setCurrentIndex(ui_.anchor->findText(anchor.c_str()));
00222       SetAnchor(anchor.c_str());
00223     }
00224 
00225     if (node[UNITS_KEY])
00226     {
00227       std::string units = node[UNITS_KEY].as<std::string>();
00228       ui_.units->setCurrentIndex(ui_.units->findText(units.c_str()));
00229       SetUnits(units.c_str());
00230     }
00231 
00232     if (node[OFFSET_X_KEY])
00233     {
00234       offset_x_ = node[OFFSET_X_KEY].as<int>();
00235       ui_.offsetx->setValue(offset_x_);
00236     }
00237 
00238     if (node[OFFSET_Y_KEY])
00239     {
00240       offset_y_ = node[OFFSET_Y_KEY].as<int>();
00241       ui_.offsety->setValue(offset_y_);
00242     }
00243   }
00244 
00245   void StringPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00246   {
00247     emitter << YAML::Key << FONT_KEY << YAML::Value << font_.toString().toStdString();
00248     emitter << YAML::Key << COLOR_KEY << YAML::Value << color_.name().toStdString();
00249     emitter << YAML::Key << TOPIC_KEY << YAML::Value << ui_.topic->text().toStdString();
00250     emitter << YAML::Key << ANCHOR_KEY << YAML::Value << AnchorToString(anchor_);
00251     emitter << YAML::Key << UNITS_KEY << YAML::Value << UnitsToString(units_);
00252     emitter << YAML::Key << OFFSET_X_KEY << YAML::Value << offset_x_;
00253     emitter << YAML::Key << OFFSET_Y_KEY << YAML::Value << offset_y_;
00254   }
00255 
00256   QWidget* StringPlugin::GetConfigWidget(QWidget* parent)
00257   {
00258     config_widget_->setParent(parent);
00259     return config_widget_;
00260   }
00261 
00262   void StringPlugin::PrintError(const std::string& message)
00263   {
00264     PrintErrorHelper(ui_.status, message);
00265   }
00266 
00267   void StringPlugin::PrintInfo(const std::string& message)
00268   {
00269     PrintInfoHelper(ui_.status, message);
00270   }
00271 
00272   void StringPlugin::PrintWarning(const std::string& message)
00273   {
00274     PrintWarningHelper(ui_.status, message);
00275   }
00276 
00277   void StringPlugin::SelectColor()
00278   {
00279     color_ = ui_.color->color();
00280   }
00281 
00282   void StringPlugin::SelectFont()
00283   {
00284     bool ok;
00285     QFont font = QFontDialog::getFont(&ok, font_, canvas_);
00286     if (ok)
00287     {
00288       font_ = font;
00289       message_.prepare(QTransform(), font_);
00290       ui_.font_button->setFont(font_);
00291       ui_.font_button->setText(font_.family());
00292     }
00293   }
00294 
00295   void StringPlugin::SelectTopic()
00296   {
00297     ros::master::TopicInfo topic = mapviz::SelectTopicDialog::selectTopic(
00298         "std_msgs/String");
00299 
00300     if (!topic.name.empty())
00301     {
00302       ui_.topic->setText(QString::fromStdString(topic.name));
00303       TopicEdited();
00304     }
00305   }
00306 
00307   void StringPlugin::TopicEdited()
00308   {
00309     std::string topic = ui_.topic->text().trimmed().toStdString();
00310     if (topic != topic_)
00311     {
00312       initialized_ = false;
00313       has_message_ = false;
00314       PrintWarning("No messages received.");
00315 
00316       string_sub_.shutdown();
00317 
00318       topic_ = topic;
00319       if (!topic.empty())
00320       {
00321         string_sub_ = node_.subscribe(topic_, 1, &StringPlugin::stringCallback, this);
00322 
00323         ROS_INFO("Subscribing to %s", topic_.c_str());
00324       }
00325     }
00326   }
00327 
00328   void StringPlugin::SetAnchor(QString anchor)
00329   {
00330     if (anchor == "top left")
00331     {
00332       anchor_ = TOP_LEFT;
00333     }
00334     else if (anchor == "top center")
00335     {
00336       anchor_ = TOP_CENTER;
00337     }
00338     else if (anchor == "top right")
00339     {
00340       anchor_ = TOP_RIGHT;
00341     }
00342     else if (anchor == "center left")
00343     {
00344       anchor_ = CENTER_LEFT;
00345     }
00346     else if (anchor == "center")
00347     {
00348       anchor_ = CENTER;
00349     }
00350     else if (anchor == "center right")
00351     {
00352       anchor_ = CENTER_RIGHT;
00353     }
00354     else if (anchor == "bottom left")
00355     {
00356       anchor_ = BOTTOM_LEFT;
00357     }
00358     else if (anchor == "bottom center")
00359     {
00360       anchor_ = BOTTOM_CENTER;
00361     }
00362     else if (anchor == "bottom right")
00363     {
00364       anchor_ = BOTTOM_RIGHT;
00365     }
00366   }
00367 
00368   void StringPlugin::SetUnits(QString units)
00369   {
00370     if (units == "pixels")
00371     {
00372       units_ = PIXELS;
00373     }
00374     else if (units == "percent")
00375     {
00376       units_ = PERCENT;
00377     }
00378   }
00379 
00380   void StringPlugin::SetOffsetX(int offset)
00381   {
00382     offset_x_ = offset;
00383   }
00384 
00385   void StringPlugin::SetOffsetY(int offset)
00386   {
00387     offset_y_ = offset;
00388   }
00389 
00390   void StringPlugin::stringCallback(const std_msgs::StringConstPtr& str)
00391   {
00392     message_.setText(QString(str->data.c_str()));
00393     message_.prepare(QTransform(), font_);
00394 
00395     has_message_ = true;
00396     has_painted_ = false;
00397     initialized_ = true;
00398   }
00399 
00400   std::string StringPlugin::AnchorToString(StringPlugin::Anchor anchor)
00401   {
00402     std::string anchor_string = "top left";
00403 
00404     if (anchor == TOP_LEFT)
00405     {
00406       anchor_string = "top left";
00407     }
00408     else if (anchor == TOP_CENTER)
00409     {
00410       anchor_string = "top center";
00411     }
00412     else if (anchor == TOP_RIGHT)
00413     {
00414       anchor_string = "top right";
00415     }
00416     else if (anchor == CENTER_LEFT)
00417     {
00418       anchor_string = "center left";
00419     }
00420     else if (anchor == CENTER)
00421     {
00422       anchor_string = "center";
00423     }
00424     else if (anchor == CENTER_RIGHT)
00425     {
00426       anchor_string = "center right";
00427     }
00428     else if (anchor == BOTTOM_LEFT)
00429     {
00430       anchor_string = "bottom left";
00431     }
00432     else if (anchor == BOTTOM_CENTER)
00433     {
00434       anchor_string = "bottom center";
00435     }
00436     else if (anchor == BOTTOM_RIGHT)
00437     {
00438       anchor_string = "bottom right";
00439     }
00440 
00441     return anchor_string;
00442   }
00443 
00444   std::string StringPlugin::UnitsToString(StringPlugin::Units units)
00445   {
00446     std::string units_string = "pixels";
00447 
00448     if (units == PIXELS)
00449     {
00450       units_string = "pixels";
00451     }
00452     else if (units == PERCENT)
00453     {
00454       units_string = "percent";
00455     }
00456 
00457     return units_string;
00458   }
00459 }


mapviz_plugins
Author(s): Marc Alban
autogenerated on Thu Jun 6 2019 18:51:07