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_DECLARE_CLASS(
00039     mapviz_plugins,
00040     string,
00041     mapviz_plugins::StringPlugin,
00042     mapviz::MapvizPlugin)
00043 
00044 namespace mapviz_plugins
00045 {
00046   const char* StringPlugin::COLOR_KEY = "color";
00047   const char* StringPlugin::FONT_KEY = "font";
00048   const char* StringPlugin::TOPIC_KEY = "topic";
00049   const char* StringPlugin::ANCHOR_KEY = "anchor";
00050   const char* StringPlugin::UNITS_KEY = "units";
00051   const char* StringPlugin::OFFSET_X_KEY = "offset_x";
00052   const char* StringPlugin::OFFSET_Y_KEY = "offset_y";
00053 
00054   StringPlugin::StringPlugin() :
00055     config_widget_(new QWidget()),
00056     anchor_(TOP_LEFT),
00057     units_(PIXELS),
00058     offset_x_(0),
00059     offset_y_(0),
00060     has_message_(false),
00061     has_painted_(false),
00062     color_(Qt::black)
00063   {
00064     ui_.setupUi(config_widget_);
00065     // Set background white
00066     QPalette p(config_widget_->palette());
00067     p.setColor(QPalette::Background, Qt::white);
00068     config_widget_->setPalette(p);
00069 
00070     // Set status text red
00071     QPalette p3(ui_.status->palette());
00072     p3.setColor(QPalette::Text, Qt::red);
00073     ui_.status->setPalette(p3);
00074 
00075     QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
00076     QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
00077     QObject::connect(ui_.anchor, SIGNAL(activated(QString)), this, SLOT(SetAnchor(QString)));
00078     QObject::connect(ui_.units, SIGNAL(activated(QString)), this, SLOT(SetUnits(QString)));
00079     QObject::connect(ui_.offsetx, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetX(int)));
00080     QObject::connect(ui_.offsety, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetY(int)));
00081     QObject::connect(ui_.font_button, SIGNAL(clicked()), this, SLOT(SelectFont()));
00082     QObject::connect(ui_.color, SIGNAL(colorEdited(const QColor &)), this, SLOT(SelectColor()));
00083 
00084     font_.setFamily(tr("Helvetica"));
00085     ui_.font_button->setFont(font_);
00086     ui_.font_button->setText(font_.family());
00087 
00088     ui_.color->setColor(color_);
00089   }
00090 
00091   StringPlugin::~StringPlugin()
00092   {
00093   }
00094 
00095   bool StringPlugin::Initialize(QGLWidget* canvas)
00096   {
00097     canvas_ = canvas;
00098     return true;
00099   }
00100 
00101   void StringPlugin::Draw(double x, double y, double scale)
00102   {
00103     // This plugin doesn't do any  OpenGL drawing.
00104   }
00105 
00106   void StringPlugin::Paint(QPainter* painter, double x, double y, double scale)
00107   {
00108     if (has_message_)
00109     {
00110       painter->save();
00111       painter->resetTransform();
00112       painter->setFont(font_);
00113 
00114       if (!has_painted_)
00115       {
00116         // After the first time we get a new message, we do not know how wide it's
00117         // going to be when rendered, so we can't accurately calculate the top left
00118         // coordinate if it's offset from the right or bottom borders.
00119         // The easiest workaround I've found for this is to draw it once using
00120         // a completely transparent pen, which will cause the QStaticText class to
00121         // know how wide it is; then we can recalculate the offsets and draw it
00122         // again with a visible pen.
00123         QPen invisPen(QBrush(Qt::transparent), 1);
00124         painter->setPen(invisPen);
00125         PaintText(painter);
00126         has_painted_ = true;
00127       }
00128       QPen pen(QBrush(color_), 1);
00129       painter->setPen(pen);
00130       PaintText(painter);
00131 
00132       painter->restore();
00133       PrintInfo("OK");
00134     }
00135     else
00136     {
00137       PrintWarning("No messages received.");
00138     }
00139   }
00140 
00141   void StringPlugin::PaintText(QPainter* painter)
00142   {
00143     // Calculate the correct offsets and dimensions
00144     int x_offset = offset_x_;
00145     int y_offset = offset_y_;
00146     if (units_ == PERCENT)
00147     {
00148       x_offset = static_cast<int>((float)(offset_x_ * canvas_->width()) / 100.0);
00149       y_offset = static_cast<int>((float)(offset_y_ * canvas_->height()) / 100.0);
00150     }
00151 
00152     int right = static_cast<int>((float)canvas_->width() - message_.size().width()) - x_offset;
00153     int bottom = static_cast<int>((float)canvas_->height() - message_.size().height()) - y_offset;
00154     int yCenter = static_cast<int>((float)canvas_->height() / 2.0 - message_.size().height()/2.0);
00155     int xCenter = static_cast<int>((float)canvas_->width() / 2.0 - message_.size().width()/2.0);
00156 
00157     QPoint ulPoint;
00158 
00159     switch (anchor_)
00160     {
00161       case TOP_LEFT:
00162         ulPoint.setX(x_offset);
00163         ulPoint.setY(y_offset);
00164         break;
00165       case TOP_CENTER:
00166         ulPoint.setX(xCenter);
00167         ulPoint.setY(y_offset);
00168         break;
00169       case TOP_RIGHT:
00170         ulPoint.setX(right);
00171         ulPoint.setY(y_offset);
00172         break;
00173       case CENTER_LEFT:
00174         ulPoint.setX(x_offset);
00175         ulPoint.setY(yCenter);
00176         break;
00177       case CENTER:
00178         ulPoint.setX(xCenter);
00179         ulPoint.setY(yCenter);
00180         break;
00181       case CENTER_RIGHT:
00182         ulPoint.setX(right);
00183         ulPoint.setY(yCenter);
00184         break;
00185       case BOTTOM_LEFT:
00186         ulPoint.setX(x_offset);
00187         ulPoint.setY(bottom);
00188         break;
00189       case BOTTOM_CENTER:
00190         ulPoint.setX(xCenter);
00191         ulPoint.setY(bottom);
00192         break;
00193       case BOTTOM_RIGHT:
00194         ulPoint.setX(right);
00195         ulPoint.setY(bottom);
00196         break;
00197     }
00198     painter->drawStaticText(ulPoint, message_);
00199   }
00200 
00201   void StringPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00202   {
00203     if (node[TOPIC_KEY])
00204     {
00205       ui_.topic->setText(QString(node[TOPIC_KEY].as<std::string>().c_str()));
00206       TopicEdited();
00207     }
00208 
00209     if (node[FONT_KEY])
00210     {
00211       font_.fromString(QString(node[FONT_KEY].as<std::string>().c_str()));
00212       ui_.font_button->setFont(font_);
00213       ui_.font_button->setText(font_.family());
00214     }
00215 
00216     if (node[COLOR_KEY])
00217     {
00218       color_ = QColor(node[COLOR_KEY].as<std::string>().c_str());
00219       ui_.color->setColor(QColor(color_.name().toStdString().c_str()));
00220     }
00221 
00222     if (node[ANCHOR_KEY])
00223     {
00224       std::string anchor = node[ANCHOR_KEY].as<std::string>();
00225       ui_.anchor->setCurrentIndex(ui_.anchor->findText(anchor.c_str()));
00226       SetAnchor(anchor.c_str());
00227     }
00228 
00229     if (node[UNITS_KEY])
00230     {
00231       std::string units = node[UNITS_KEY].as<std::string>();
00232       ui_.units->setCurrentIndex(ui_.units->findText(units.c_str()));
00233       SetUnits(units.c_str());
00234     }
00235 
00236     if (node[OFFSET_X_KEY])
00237     {
00238       offset_x_ = node[OFFSET_X_KEY].as<int>();
00239       ui_.offsetx->setValue(offset_x_);
00240     }
00241 
00242     if (node[OFFSET_Y_KEY])
00243     {
00244       offset_y_ = node[OFFSET_Y_KEY].as<int>();
00245       ui_.offsety->setValue(offset_y_);
00246     }
00247   }
00248 
00249   void StringPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00250   {
00251     emitter << YAML::Key << FONT_KEY << YAML::Value << font_.toString().toStdString();
00252     emitter << YAML::Key << COLOR_KEY << YAML::Value << color_.name().toStdString();
00253     emitter << YAML::Key << TOPIC_KEY << YAML::Value << ui_.topic->text().toStdString();
00254     emitter << YAML::Key << ANCHOR_KEY << YAML::Value << AnchorToString(anchor_);
00255     emitter << YAML::Key << UNITS_KEY << YAML::Value << UnitsToString(units_);
00256     emitter << YAML::Key << OFFSET_X_KEY << YAML::Value << offset_x_;
00257     emitter << YAML::Key << OFFSET_Y_KEY << YAML::Value << offset_y_;
00258   }
00259 
00260   QWidget* StringPlugin::GetConfigWidget(QWidget* parent)
00261   {
00262     config_widget_->setParent(parent);
00263     return config_widget_;
00264   }
00265 
00266   void StringPlugin::PrintError(const std::string& message)
00267   {
00268     if (message == ui_.status->text().toStdString())
00269     {
00270       return;
00271     }
00272 
00273     ROS_ERROR("Error: %s", message.c_str());
00274     QPalette p(ui_.status->palette());
00275     p.setColor(QPalette::Text, Qt::red);
00276     ui_.status->setPalette(p);
00277     ui_.status->setText(message.c_str());
00278   }
00279 
00280   void StringPlugin::PrintInfo(const std::string& message)
00281   {
00282     if (message == ui_.status->text().toStdString())
00283     {
00284       return;
00285     }
00286 
00287     ROS_INFO("%s", message.c_str());
00288     QPalette p(ui_.status->palette());
00289     p.setColor(QPalette::Text, Qt::green);
00290     ui_.status->setPalette(p);
00291     ui_.status->setText(message.c_str());
00292   }
00293 
00294   void StringPlugin::PrintWarning(const std::string& message)
00295   {
00296     if (message == ui_.status->text().toStdString())
00297     {
00298       return;
00299     }
00300 
00301     ROS_WARN("%s", message.c_str());
00302     QPalette p(ui_.status->palette());
00303     p.setColor(QPalette::Text, Qt::darkYellow);
00304     ui_.status->setPalette(p);
00305     ui_.status->setText(message.c_str());
00306   }
00307 
00308   void StringPlugin::SelectColor()
00309   {
00310     color_ = ui_.color->color();
00311   }
00312 
00313   void StringPlugin::SelectFont()
00314   {
00315     bool ok;
00316     QFont font = QFontDialog::getFont(&ok, font_, canvas_);
00317     if (ok)
00318     {
00319       font_ = font;
00320       message_.prepare(QTransform(), font_);
00321       ui_.font_button->setFont(font_);
00322       ui_.font_button->setText(font_.family());
00323     }
00324   }
00325 
00326   void StringPlugin::SelectTopic()
00327   {
00328     ros::master::TopicInfo topic = mapviz::SelectTopicDialog::selectTopic(
00329         "std_msgs/String");
00330 
00331     if (!topic.name.empty())
00332     {
00333       ui_.topic->setText(QString::fromStdString(topic.name));
00334       TopicEdited();
00335     }
00336   }
00337 
00338   void StringPlugin::TopicEdited()
00339   {
00340     std::string topic = ui_.topic->text().trimmed().toStdString();
00341     if (topic != topic_)
00342     {
00343       initialized_ = false;
00344       has_message_ = false;
00345       PrintWarning("No messages received.");
00346 
00347       string_sub_.shutdown();
00348 
00349       topic_ = topic;
00350       if (!topic.empty())
00351       {
00352         string_sub_ = node_.subscribe(topic_, 1, &StringPlugin::stringCallback, this);
00353 
00354         ROS_INFO("Subscribing to %s", topic_.c_str());
00355       }
00356     }
00357   }
00358 
00359   void StringPlugin::SetAnchor(QString anchor)
00360   {
00361     if (anchor == "top left")
00362     {
00363       anchor_ = TOP_LEFT;
00364     }
00365     else if (anchor == "top center")
00366     {
00367       anchor_ = TOP_CENTER;
00368     }
00369     else if (anchor == "top right")
00370     {
00371       anchor_ = TOP_RIGHT;
00372     }
00373     else if (anchor == "center left")
00374     {
00375       anchor_ = CENTER_LEFT;
00376     }
00377     else if (anchor == "center")
00378     {
00379       anchor_ = CENTER;
00380     }
00381     else if (anchor == "center right")
00382     {
00383       anchor_ = CENTER_RIGHT;
00384     }
00385     else if (anchor == "bottom left")
00386     {
00387       anchor_ = BOTTOM_LEFT;
00388     }
00389     else if (anchor == "bottom center")
00390     {
00391       anchor_ = BOTTOM_CENTER;
00392     }
00393     else if (anchor == "bottom right")
00394     {
00395       anchor_ = BOTTOM_RIGHT;
00396     }
00397   }
00398 
00399   void StringPlugin::SetUnits(QString units)
00400   {
00401     if (units == "pixels")
00402     {
00403       units_ = PIXELS;
00404     }
00405     else if (units == "percent")
00406     {
00407       units_ = PERCENT;
00408     }
00409   }
00410 
00411   void StringPlugin::SetOffsetX(int offset)
00412   {
00413     offset_x_ = offset;
00414   }
00415 
00416   void StringPlugin::SetOffsetY(int offset)
00417   {
00418     offset_y_ = offset;
00419   }
00420 
00421   void StringPlugin::stringCallback(const std_msgs::StringConstPtr& str)
00422   {
00423     message_.setText(QString(str->data.c_str()));
00424     message_.prepare(QTransform(), font_);
00425 
00426     has_message_ = true;
00427     has_painted_ = false;
00428     initialized_ = true;
00429   }
00430 
00431   std::string StringPlugin::AnchorToString(StringPlugin::Anchor anchor)
00432   {
00433     std::string anchor_string = "top left";
00434 
00435     if (anchor == TOP_LEFT)
00436     {
00437       anchor_string = "top left";
00438     }
00439     else if (anchor == TOP_CENTER)
00440     {
00441       anchor_string = "top center";
00442     }
00443     else if (anchor == TOP_RIGHT)
00444     {
00445       anchor_string = "top right";
00446     }
00447     else if (anchor == CENTER_LEFT)
00448     {
00449       anchor_string = "center left";
00450     }
00451     else if (anchor == CENTER)
00452     {
00453       anchor_string = "center";
00454     }
00455     else if (anchor == CENTER_RIGHT)
00456     {
00457       anchor_string = "center right";
00458     }
00459     else if (anchor == BOTTOM_LEFT)
00460     {
00461       anchor_string = "bottom left";
00462     }
00463     else if (anchor == BOTTOM_CENTER)
00464     {
00465       anchor_string = "bottom center";
00466     }
00467     else if (anchor == BOTTOM_RIGHT)
00468     {
00469       anchor_string = "bottom right";
00470     }
00471 
00472     return anchor_string;
00473   }
00474 
00475   std::string StringPlugin::UnitsToString(StringPlugin::Units units)
00476   {
00477     std::string units_string = "pixels";
00478 
00479     if (units == PIXELS)
00480     {
00481       units_string = "pixels";
00482     }
00483     else if (units == PERCENT)
00484     {
00485       units_string = "percent";
00486     }
00487 
00488     return units_string;
00489   }
00490 }


mapviz_plugins
Author(s): Marc Alban
autogenerated on Thu Aug 24 2017 02:46:09