00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 #include "overlay_text_display.h"
00037 #include <OGRE/OgreMaterialManager.h>
00038 #include <rviz/uniform_string_stream.h>
00039 #include <OGRE/OgreTexture.h>
00040 #include <OGRE/OgreHardwarePixelBuffer.h>
00041 #include <QFontDatabase>
00042 #include <QPainter>
00043 #include <QStaticText>
00044 #include <QTextDocument>
00045 #include <boost/algorithm/string.hpp>
00046 #include <boost/format.hpp>
00047 #include <jsk_topic_tools/log_utils.h>
00048 
00049 namespace jsk_rviz_plugins
00050 {
00051   OverlayTextDisplay::OverlayTextDisplay() : Display(),
00052                                              texture_width_(0), texture_height_(0),
00053                                              text_size_(14),
00054                                              line_width_(2),
00055                                              text_(""), font_(""),
00056                                              bg_color_(0, 0, 0, 0),
00057                                              fg_color_(255, 255, 255, 255.0),
00058                                              require_update_texture_(false)
00059   {
00060     update_topic_property_ = new rviz::RosTopicProperty(
00061       "Topic", "",
00062       ros::message_traits::datatype<jsk_rviz_plugins::OverlayText>(),
00063       "jsk_rviz_plugins::OverlayText topic to subscribe to.",
00064       this, SLOT( updateTopic() ));
00065     overtake_position_properties_property_ = new rviz::BoolProperty(
00066       "Overtake Position Properties", false,
00067       "overtake position properties specified by message such as left, top and font",
00068       this, SLOT(updateOvertakePositionProperties()));
00069     overtake_color_properties_property_ = new rviz::BoolProperty(
00070       "Overtake Color Properties", false,
00071       "overtake color properties specified by message such as foreground/background color and alpha",
00072       this, SLOT(updateOvertakeColorProperties()));
00073     align_bottom_property_ = new rviz::BoolProperty(
00074       "Align Bottom", false,
00075       "align text with the bottom of the overlay region",
00076       this, SLOT(updateAlignBottom()));
00077     top_property_ = new rviz::IntProperty(
00078       "top", 0,
00079       "top position",
00080       this, SLOT(updateTop()));
00081     top_property_->setMin(0);
00082     left_property_ = new rviz::IntProperty(
00083       "left", 0,
00084       "left position",
00085       this, SLOT(updateLeft()));
00086     left_property_->setMin(0);
00087     width_property_ = new rviz::IntProperty(
00088       "width", 128,
00089       "width position",
00090       this, SLOT(updateWidth()));
00091     width_property_->setMin(0);
00092     height_property_ = new rviz::IntProperty(
00093       "height", 128,
00094       "height position",
00095       this, SLOT(updateHeight()));
00096     height_property_->setMin(0);
00097     text_size_property_ = new rviz::IntProperty(
00098       "text size", 12,
00099       "text size",
00100       this, SLOT(updateTextSize()));
00101     text_size_property_->setMin(0);
00102     line_width_property_ = new rviz::IntProperty(
00103       "line width", 2,
00104       "line width",
00105       this, SLOT(updateLineWidth()));
00106     line_width_property_->setMin(0);
00107     fg_color_property_ = new rviz::ColorProperty(
00108       "Foreground Color", QColor(25, 255, 240),
00109       "Foreground Color",
00110       this, SLOT(updateFGColor()));
00111     fg_alpha_property_ = new rviz::FloatProperty(
00112       "Foreground Alpha", 0.8, "Foreground Alpha",
00113       this, SLOT(updateFGAlpha()));
00114     fg_alpha_property_->setMin(0.0);
00115     fg_alpha_property_->setMax(1.0);
00116     bg_color_property_ = new rviz::ColorProperty(
00117       "Background Color", QColor(0, 0, 0),
00118       "Background Color",
00119       this, SLOT(updateBGColor()));
00120     bg_alpha_property_ = new rviz::FloatProperty(
00121       "Background Alpha", 0.8, "Background Alpha",
00122       this, SLOT(updateBGAlpha()));
00123     bg_alpha_property_->setMin(0.0);
00124     bg_alpha_property_->setMax(1.0);
00125 
00126     QFontDatabase database;
00127     font_families_ = database.families();
00128     font_property_ = new rviz::EnumProperty(
00129       "font", "DejaVu Sans Mono",
00130       "font", this,
00131       SLOT(updateFont()));
00132     for (size_t i = 0; i < font_families_.size(); i++) {
00133       font_property_->addOption(font_families_[i], (int)i);
00134     }
00135   }
00136   
00137   OverlayTextDisplay::~OverlayTextDisplay()
00138   {
00139     onDisable();
00140     
00141     delete update_topic_property_;
00142     delete overtake_color_properties_property_;
00143     delete overtake_position_properties_property_;
00144     delete align_bottom_property_;
00145     delete top_property_;
00146     delete left_property_;
00147     delete width_property_;
00148     delete height_property_;
00149     delete text_size_property_;
00150     delete line_width_property_;
00151     delete bg_color_property_;
00152     delete bg_alpha_property_;
00153     delete fg_color_property_;
00154     delete fg_alpha_property_;
00155     delete font_property_;
00156   }
00157 
00158   void OverlayTextDisplay::onEnable()
00159   {
00160     if (overlay_) {
00161       overlay_->show();
00162     }
00163     subscribe();
00164   }
00165 
00166   void OverlayTextDisplay::onDisable()
00167   {
00168     if (overlay_) {
00169       overlay_->hide();
00170     }
00171     unsubscribe();
00172   }
00173   
00174   void OverlayTextDisplay::unsubscribe()
00175   {
00176     sub_.shutdown();
00177   }
00178 
00179   void OverlayTextDisplay::subscribe()
00180   {
00181     std::string topic_name = update_topic_property_->getTopicStd();
00182     if (topic_name.length() > 0 && topic_name != "/") {
00183       sub_ = ros::NodeHandle().subscribe(topic_name, 1, &OverlayTextDisplay::processMessage, this);
00184     }
00185   }
00186   
00187   void OverlayTextDisplay::updateTopic()
00188   {
00189     unsubscribe();
00190     subscribe();
00191   }
00192     
00193   
00194   void OverlayTextDisplay::onInitialize()
00195   {
00196     onEnable();
00197     updateTopic();
00198     updateOvertakePositionProperties();
00199     updateOvertakeColorProperties();
00200     updateAlignBottom();
00201     updateTop();
00202     updateLeft();
00203     updateWidth();
00204     updateHeight();
00205     updateTextSize();
00206     updateFGColor();
00207     updateFGAlpha();
00208     updateBGColor();
00209     updateBGAlpha();
00210     updateFont();
00211     updateLineWidth();
00212     require_update_texture_ = true;
00213   }
00214   
00215   void OverlayTextDisplay::update(float wall_dt, float ros_dt)
00216   {
00217     if (!require_update_texture_) {
00218       return;
00219     }
00220     if (!isEnabled()) {
00221       return;
00222     }
00223     if (!overlay_) {
00224       return;
00225     }
00226     overlay_->updateTextureSize(texture_width_, texture_height_);
00227     {
00228       ScopedPixelBuffer buffer = overlay_->getBuffer();
00229       QImage Hud = buffer.getQImage(*overlay_, bg_color_);
00230       QPainter painter( &Hud );
00231       painter.setRenderHint(QPainter::Antialiasing, true);
00232       painter.setPen(QPen(fg_color_, line_width_ || 1, Qt::SolidLine));
00233       uint16_t w = overlay_->getTextureWidth();
00234       uint16_t h = overlay_->getTextureHeight();
00235 
00236       
00237       if (text_size_ != 0) {
00238         
00239         QFont font(font_.length() > 0 ? font_.c_str(): "Liberation Sans");
00240         font.setPointSize(text_size_);
00241         font.setBold(true);
00242         painter.setFont(font);
00243       }
00244       if (text_.length() > 0) {
00245         
00246         
00247         
00248         std::string color_wrapped_text
00249           = (boost::format("<span style=\"color: rgba(%2%, %3%, %4%, %5%)\">%1%</span>")
00250              % text_ % fg_color_.red() % fg_color_.green() % fg_color_.blue() %
00251              fg_color_.alpha()).str();
00252         QStaticText static_text(
00253           boost::algorithm::replace_all_copy(color_wrapped_text, "\n", "<br >").c_str());
00254         static_text.setTextWidth(w);
00255         if (!align_bottom_) {
00256           painter.drawStaticText(0, 0, static_text);
00257         } else {
00258           QStaticText only_wrapped_text(color_wrapped_text.c_str());
00259           QFontMetrics fm(painter.fontMetrics());
00260           QRect text_rect = fm.boundingRect(0, 0, w, h,
00261                                             Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
00262                                             only_wrapped_text.text().remove(QRegExp("<[^>]*>")));
00263           painter.drawStaticText(0, h - text_rect.height(), static_text);
00264         }
00265       }
00266       painter.end();
00267     }
00268     overlay_->setDimensions(overlay_->getTextureWidth(), overlay_->getTextureHeight());
00269     require_update_texture_ = false;
00270   }
00271   
00272   void OverlayTextDisplay::processMessage
00273   (const jsk_rviz_plugins::OverlayText::ConstPtr& msg)
00274   {
00275     if (!isEnabled()) {
00276       return;
00277     }
00278     if (!overlay_) {
00279       static int count = 0;
00280       rviz::UniformStringStream ss;
00281       ss << "OverlayTextDisplayObject" << count++;
00282       overlay_.reset(new OverlayObject(ss.str()));
00283       overlay_->show();
00284     }
00285     if (overlay_) {
00286       if (msg->action == jsk_rviz_plugins::OverlayText::DELETE) {
00287         overlay_->hide();
00288       }
00289       else if (msg->action == jsk_rviz_plugins::OverlayText::ADD) {
00290         overlay_->show();
00291       }
00292     }
00293     
00294     
00295     text_ = msg->text;
00296     if (!overtake_position_properties_) {
00297       texture_width_ = msg->width;
00298       texture_height_ = msg->height;
00299       text_size_ = msg->text_size;
00300       left_ = msg->left;
00301       top_ = msg->top;
00302     }
00303     if (!overtake_color_properties_) {
00304       bg_color_ = QColor(msg->bg_color.r * 255.0,
00305                          msg->bg_color.g * 255.0,
00306                          msg->bg_color.b * 255.0,
00307                          msg->bg_color.a * 255.0);
00308       fg_color_ = QColor(msg->fg_color.r * 255.0,
00309                          msg->fg_color.g * 255.0,
00310                          msg->fg_color.b * 255.0,
00311                          msg->fg_color.a * 255.0);
00312       font_ = msg->font;
00313       line_width_ = msg->line_width;
00314     }
00315     if (overlay_) {
00316       overlay_->setPosition(left_, top_);
00317     }
00318     require_update_texture_ = true;
00319   }
00320 
00321   void OverlayTextDisplay::updateOvertakePositionProperties()
00322   {
00323     
00324     if (!overtake_position_properties_ &&
00325         overtake_position_properties_property_->getBool()) {
00326       updateTop();
00327       updateLeft();
00328       updateWidth();
00329       updateHeight();
00330       updateTextSize();
00331       require_update_texture_ = true;
00332     }
00333     overtake_position_properties_
00334       = overtake_position_properties_property_->getBool();
00335     if (overtake_position_properties_) {
00336       top_property_->show();
00337       left_property_->show();
00338       width_property_->show();
00339       height_property_->show();
00340       text_size_property_->show();
00341     }
00342     else {
00343       top_property_->hide();
00344       left_property_->hide();
00345       width_property_->hide();
00346       height_property_->hide();
00347       text_size_property_->hide();
00348     }
00349   }
00350   
00351   void OverlayTextDisplay::updateOvertakeColorProperties()
00352   {
00353     if (!overtake_color_properties_ &&
00354         overtake_color_properties_property_->getBool()) {
00355       
00356       updateFGColor();
00357       updateFGAlpha();
00358       updateBGColor();
00359       updateBGAlpha();
00360       updateFont();
00361       updateLineWidth();
00362       require_update_texture_ = true;
00363     }
00364     overtake_color_properties_ = overtake_color_properties_property_->getBool();
00365     if (overtake_color_properties_) {
00366       fg_color_property_->show();
00367       fg_alpha_property_->show();
00368       bg_color_property_->show();
00369       bg_alpha_property_->show();
00370       line_width_property_->show();
00371       font_property_->show();
00372     }
00373     else {
00374       fg_color_property_->hide();
00375       fg_alpha_property_->hide();
00376       bg_color_property_->hide();
00377       bg_alpha_property_->hide();
00378       line_width_property_->hide();
00379       font_property_->hide();
00380     }
00381   }
00382 
00383   void OverlayTextDisplay::updateAlignBottom()
00384   {
00385     if (align_bottom_ != align_bottom_property_->getBool()) {
00386       require_update_texture_ = true;
00387     }
00388     align_bottom_ = align_bottom_property_->getBool();
00389   }
00390 
00391   void OverlayTextDisplay::updateTop()
00392   {
00393     top_ = top_property_->getInt();
00394     if (overtake_position_properties_) {
00395       require_update_texture_ = true;
00396     }
00397   }
00398   
00399   void OverlayTextDisplay::updateLeft()
00400   {
00401     left_ = left_property_->getInt();
00402     if (overtake_position_properties_) {
00403       require_update_texture_ = true;
00404     }
00405   }
00406   
00407   void OverlayTextDisplay::updateWidth()
00408   {
00409     texture_width_ = width_property_->getInt();
00410     if (overtake_position_properties_) {
00411       require_update_texture_ = true;
00412     }
00413   }
00414   
00415   void OverlayTextDisplay::updateHeight()
00416   {
00417     texture_height_ = height_property_->getInt();
00418     if (overtake_position_properties_) {
00419       require_update_texture_ = true;
00420     }
00421   }
00422 
00423   void OverlayTextDisplay::updateTextSize()
00424   {
00425     text_size_ = text_size_property_->getInt();
00426     if (overtake_position_properties_) {
00427       require_update_texture_ = true;
00428     }
00429   }
00430 
00431   void OverlayTextDisplay::updateBGColor()
00432   {
00433     QColor c = bg_color_property_->getColor();
00434     bg_color_.setRed(c.red());
00435     bg_color_.setGreen(c.green());
00436     bg_color_.setBlue(c.blue());
00437     if (overtake_color_properties_) {
00438       require_update_texture_ = true;
00439     }
00440   }
00441 
00442   void OverlayTextDisplay::updateBGAlpha()
00443   {
00444     bg_color_.setAlpha(bg_alpha_property_->getFloat() * 255.0);
00445     if (overtake_color_properties_) {
00446       require_update_texture_ = true;
00447     }
00448   }
00449 
00450   void OverlayTextDisplay::updateFGColor()
00451   {
00452     QColor c = fg_color_property_->getColor();
00453     fg_color_.setRed(c.red());
00454     fg_color_.setGreen(c.green());
00455     fg_color_.setBlue(c.blue());
00456     if (overtake_color_properties_) {
00457       require_update_texture_ = true;
00458     }
00459   }
00460 
00461   void OverlayTextDisplay::updateFGAlpha()
00462   {
00463     fg_color_.setAlpha(fg_alpha_property_->getFloat() * 255.0);
00464     if (overtake_color_properties_) {
00465       require_update_texture_ = true;
00466     }
00467   }
00468 
00469   void OverlayTextDisplay::updateFont()
00470   {
00471     int font_index = font_property_->getOptionInt();
00472     if (font_index < font_families_.size()) {
00473       font_ = font_families_[font_index].toStdString();
00474     } else {
00475       ROS_FATAL("Unexpected error at selecting font index %d.", font_index);
00476       return;
00477     }
00478     if (overtake_color_properties_) {
00479       require_update_texture_ = true;
00480     }
00481   }
00482 
00483   void OverlayTextDisplay::updateLineWidth()
00484   {
00485     line_width_ = line_width_property_->getInt();
00486     if (overtake_color_properties_) {
00487       require_update_texture_ = true;
00488     }
00489   }
00490 
00491   bool OverlayTextDisplay::isInRegion(int x, int y)
00492   {
00493     return (top_ < y && top_ + texture_height_ > y &&
00494             left_ < x && left_ + texture_width_ > x);
00495   }
00496 
00497   void OverlayTextDisplay::movePosition(int x, int y)
00498   {
00499     top_ = y;
00500     left_ = x;
00501   }
00502 
00503   void OverlayTextDisplay::setPosition(int x, int y)
00504   {
00505     top_property_->setValue(y);
00506     left_property_->setValue(x);
00507   }
00508   
00509 }
00510 
00511 #include <pluginlib/class_list_macros.h>
00512 PLUGINLIB_EXPORT_CLASS( jsk_rviz_plugins::OverlayTextDisplay, rviz::Display )