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 )