overlay_menu_display.cpp
Go to the documentation of this file.
1 // -*- mode: c++; -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2014, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 #include "overlay_menu_display.h"
37 
38 #include <OGRE/OgreMaterialManager.h>
39 #include <OGRE/OgreTextureManager.h>
40 #include <OGRE/OgreTexture.h>
41 #include <OGRE/OgreHardwarePixelBuffer.h>
42 #include <OGRE/OgreTechnique.h>
43 
45 #include <rviz/display_context.h>
46 #include <rviz/view_manager.h>
47 #include <rviz/render_panel.h>
48 
49 namespace jsk_rviz_plugins
50 {
51 
52  const int menu_padding_x = 100;
53  const int menu_padding_y = 5;
54  const int menu_last_padding_y = 30;
55  const double animate_duration = 0.2;
57  {
59  "Topic", "",
60  ros::message_traits::datatype<jsk_rviz_plugins::OverlayMenu>(),
61  "jsk_rviz_plugins::OverlayMenu topic to subscribe to.",
62  this, SLOT( updateTopic() ));
63  left_property_ = new rviz::IntProperty("left", 128,
64  "left of the image window",
65  this, SLOT(updateLeft()));
67  top_property_ = new rviz::IntProperty("top", 128,
68  "top of the image window",
69  this, SLOT(updateTop()));
71  keep_centered_property_ = new rviz::BoolProperty("keep centered", true,
72  "enable automatic center adjustment",
73  this, SLOT(updateKeepCentered()));
74 
75  // NOTE: Overtaking FG/BG Color Properties defaults to TRUE for backward compatibility.
77  "Overtake FG Color Properties", true,
78  "overtake color properties specified by message such as foreground color and alpha",
79  this, SLOT(updateOvertakeFGColorProperties()));
81  "Overtake BG Color Properties", true,
82  "overtake color properties specified by message such as background color and alpha",
83  this, SLOT(updateOvertakeBGColorProperties()));
84 
86  "Foreground Color", QColor(25, 255, 240),
87  "Foreground Color",
88  this, SLOT(updateFGColor()));
90  "Foreground Alpha", 1.0, "Foreground Alpha",
91  this, SLOT(updateFGAlpha()));
94 
96  "Background Color", QColor(0, 0, 0),
97  "Background Color",
98  this, SLOT(updateBGColor()));
100  "Background Alpha", 0.5, "Background Alpha",
101  this, SLOT(updateBGAlpha()));
104  }
105 
107  {
108  onDisable();
109  delete update_topic_property_;
110  delete left_property_;
111  delete top_property_;
115  delete bg_color_property_;
116  delete bg_alpha_property_;
117  delete fg_color_property_;
118  delete fg_alpha_property_;
119  }
120 
122  {
124  updateLeft();
125  updateTop();
128  updateFGColor();
129  updateFGAlpha();
130  updateBGColor();
131  updateBGAlpha();
132  require_update_texture_ = false;
134  }
135 
137  {
138  if (overlay_) {
139  overlay_->show();
140  }
141  subscribe();
142  }
143 
145  {
146  if (overlay_) {
147  overlay_->hide();
148  }
149  unsubscribe();
150  }
151 
153  {
154  sub_.shutdown();
155  }
156 
158  {
159  std::string topic_name = update_topic_property_->getTopicStd();
160  if (topic_name.length() > 0 && topic_name != "/") {
161  sub_ = ros::NodeHandle().subscribe(topic_name, 1,
163  this);
164  }
165  }
166 
168  (const jsk_rviz_plugins::OverlayMenu::ConstPtr& msg)
169  {
170  next_menu_ = msg;
172  bg_color_ = QColor(msg->bg_color.r * 255.0,
173  msg->bg_color.g * 255.0,
174  msg->bg_color.b * 255.0,
175  msg->bg_color.a * 255.0);
177  fg_color_ = QColor(msg->fg_color.r * 255.0,
178  msg->fg_color.g * 255.0,
179  msg->fg_color.b * 255.0,
180  msg->fg_color.a * 255.0);
181  }
182 
184  {
185  if (!current_menu_ && next_menu_) { // first time
186  ROS_DEBUG("need to resize because this is the first time to draw");
187  return true;
188  }
189  else if (!current_menu_ && !next_menu_) {
190  // both are null, it means that ...
191  // the plugin tries to draw without message reception
192  ROS_DEBUG("no need to resize because the plugin tries to draw without message reception");
193  return false;
194  }
195  else if (current_menu_ && !next_menu_) {
196  // this is unexpected case
197  ROS_DEBUG("no need to resize, this is unexpected case. please debug");
198  return false;
199  }
200  else {
201  if (current_menu_->menus.size() != next_menu_->menus.size()) {
202  ROS_DEBUG("need to resize because the length of menu is different");
203  return true;
204  }
205  else if (current_menu_->title != next_menu_->title) {
206  return true;
207  }
208  else {
209  // check all the menu is same or not
210  for (size_t i = 0; i < current_menu_->menus.size(); i++) {
211  if (current_menu_->menus[i] != next_menu_->menus[i]) {
212  ROS_DEBUG("need to resize because the content of menu is different");
213  return true;
214  }
215  }
216  ROS_DEBUG("no need to resize because the content of menu is same");
217  return false;
218  }
219  }
220  }
221 
223  {
224  QFont font;
225  font.setPointSize(20);
226  return font;
227  }
228 
230  {
231  QFontMetrics fm(font());
232  return fm;
233  }
234 
236  const jsk_rviz_plugins::OverlayMenu::ConstPtr& msg)
237  {
238  QFontMetrics fm = fontMetrics();
239  int max_width = 0;
240  for (size_t i = 0; i < msg->menus.size(); i++) {
241  int w = fm.width(getMenuString(msg, i).c_str());
242  if (max_width < w) {
243  max_width = w;
244  }
245  }
246  int w = fm.width(msg->title.c_str());
247 
248  if (max_width < w) {
249  max_width = w;
250  }
251  return max_width + menu_padding_x * 2;
252  }
253 
255  const jsk_rviz_plugins::OverlayMenu::ConstPtr& msg)
256  {
257  QFontMetrics fm = fontMetrics();
258  return fm.height() * (msg->menus.size() + 1)
259  + menu_padding_y * (msg->menus.size() + 1 - 1)
260  + menu_last_padding_y * 2;
261  }
262 
263  void OverlayMenuDisplay::update(float wall_dt, float ros_dt)
264  {
265  if (!next_menu_) {
266  ROS_DEBUG("next_menu_ is null, no need to update");
267  return;
268  }
269  if (next_menu_->action == jsk_rviz_plugins::OverlayMenu::ACTION_CLOSE &&
271  ROS_DEBUG("request is close and state is closed, we ignore it completely");
272  return;
273  }
274 
275  if (next_menu_->action == jsk_rviz_plugins::OverlayMenu::ACTION_CLOSE) {
276  // need to close...
277  if (animation_state_ == CLOSED) {
278  // do nothing, it should be ignored above if sentence
279  ROS_WARN("request is CLOSE and state is CLOSED, it should be ignored before...");
280  }
281  else if (animation_state_ == OPENED) { // OPENED -> CLOSING
284  }
285  else if (animation_state_ == CLOSING) {
286  animation_t_ -= wall_dt;
287  if (animation_t_ > 0) { // CLOSING -> CLOSING
289  }
290  else { // CLOSING -> CLOSED
291  animation_t_ = 0;
294  }
295  }
296  else if (animation_state_ == OPENING) { // if the status is OPENING, we open it anyway...??
297  animation_t_ += wall_dt;
298  if (animation_t_ < animate_duration) { // OPENING -> OPENING
300  }
301  else { // OPENING -> OPENED
302  redraw();
304  }
305  }
306  }
307  else { // OPEN request
308  if (animation_state_ == CLOSED) { // CLOSED -> OPENING, do nothing just change the state
309  animation_t_ = 0.0;
311  }
312  else if (animation_state_ == OPENING) {
313  animation_t_ += wall_dt;
314  ROS_DEBUG("animation_t: %f", animation_t_);
315  if (animation_t_ < animate_duration) { // OPENING -> OPENING
317  }
318  else { // OPENING -> OPENED
319  redraw();
321  }
322  }
323  else if (animation_state_ == OPENED) { // OPENED -> OPENED
324  if (isNeedToRedraw()) {
325  redraw();
326  }
327  }
328  else if (animation_state_ == CLOSING) { // CLOSING, we close it anyway...
329  animation_t_ -= wall_dt;
330  if (animation_t_ > 0) {
332  }
333  else {
334  animation_t_ = 0;
337  }
338  }
339  }
340  //redraw();
341  //current_menu_ = next_menu_;
342  }
343 
345  return true;
346  }
347 
349  const jsk_rviz_plugins::OverlayMenu::ConstPtr& msg,
350  size_t index)
351  {
352  if (index >= msg->menus.size()) {
353  return "";
354  }
355  else {
356  return msg->menus[index];
357  }
358  }
359 
361  {
362  if (!overlay_) {
363  static int count = 0;
365  ss << "OverlayMenuDisplayObject" << count++;
366  overlay_.reset(new OverlayObject(ss.str()));
367  overlay_->show();
368  }
369  if (!overlay_->isTextureReady() || isNeedToResize()) {
371  }
372  else {
373  ROS_DEBUG("no need to update texture size");
374  }
375  }
376 
378  {
379  ROS_DEBUG("openningAnimation");
380  prepareOverlay();
381  int current_width = animation_t_ / animate_duration * overlay_->getTextureWidth();
382  int current_height = animation_t_ / animate_duration * overlay_->getTextureHeight();
383  {
384  ScopedPixelBuffer buffer = overlay_->getBuffer();
385  QColor transparent(0, 0, 0, 0.0);
386  QImage Hud = buffer.getQImage(*overlay_);
387  for (int i = 0; i < overlay_->getTextureWidth(); i++) {
388  for (int j = 0; j < overlay_->getTextureHeight(); j++) {
389  if (i > (overlay_->getTextureWidth() - current_width) / 2.0 &&
390  i < overlay_->getTextureWidth() - (overlay_->getTextureWidth() - current_width) / 2.0 &&
391  j > (overlay_->getTextureHeight() - current_height) / 2.0 &&
392  j < overlay_->getTextureHeight() - (overlay_->getTextureHeight() - current_height) / 2.0) {
393  Hud.setPixel(i, j, bg_color_.rgba());
394  }
395  else {
396  Hud.setPixel(i, j, transparent.rgba());
397  }
398  }
399  }
400  }
401  setMenuLocation();
403  }
404 
406  {
407  ROS_DEBUG("redraw");
408  prepareOverlay();
409  {
410  ScopedPixelBuffer buffer = overlay_->getBuffer();
411  QImage Hud = buffer.getQImage(*overlay_, bg_color_);
412  QPainter painter( &Hud );
413  painter.setRenderHint(QPainter::Antialiasing, true);
414  painter.setPen(QPen(fg_color_, 1, Qt::SolidLine));
415  painter.setFont(font());
416  int line_height = fontMetrics().height();
417  int w = drawAreaWidth(next_menu_);
418  painter.drawText(menu_padding_x, menu_padding_y,
419  w, line_height,
420  Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
421  next_menu_->title.c_str());
422  for (size_t i = 0; i < next_menu_->menus.size(); i++) {
423  std::string menu = getMenuString(next_menu_, i);
424  painter.drawText(menu_padding_x, line_height * ( 1 + i ) + menu_padding_y + menu_last_padding_y,
425  w, line_height,
426  Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
427  menu.c_str());
428  }
429  if (next_menu_->current_index <= next_menu_->menus.size()) {
430  // draw '>'
431  painter.drawText(menu_padding_x - fontMetrics().width(">") * 2,
432  line_height * ( 1 + next_menu_->current_index ) + menu_padding_y + menu_last_padding_y,
433  w, line_height,
434  Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
435  ">");
436  }
437  // draw line
438  int texture_width = overlay_->getTextureWidth();
439  int texture_height = overlay_->getTextureHeight();
440  painter.drawLine(menu_padding_x / 2, menu_last_padding_y / 2 + line_height,
441  menu_padding_x / 2, texture_height - menu_last_padding_y / 2);
442  painter.drawLine(texture_width - menu_padding_x / 2, menu_last_padding_y / 2 + line_height,
443  texture_width - menu_padding_x / 2, texture_height - menu_last_padding_y / 2);
444  painter.drawLine(menu_padding_x / 2, menu_last_padding_y / 2 + line_height,
445  texture_width - menu_padding_x / 2, menu_last_padding_y / 2 + line_height);
446  painter.drawLine(menu_padding_x / 2, texture_height - menu_last_padding_y / 2,
447  texture_width - menu_padding_x / 2, texture_height - menu_last_padding_y / 2);
448 
449  painter.end();
451  }
452  setMenuLocation();
453  }
454 
456  {
457  overlay_->setDimensions(overlay_->getTextureWidth(), overlay_->getTextureHeight());
458  int window_width = context_->getViewManager()->getRenderPanel()->width();
459  int window_height = context_->getViewManager()->getRenderPanel()->height();
460  if (keep_centered_)
461  {
462  left_ = (window_width - (int)overlay_->getTextureWidth()) / 2.0;
463  top_ = (window_height - (int)overlay_->getTextureHeight()) / 2.0;
464  }
465  left_ = std::max(0, std::min(window_width - (int)overlay_->getTextureWidth(), left_));
466  top_ = std::max(0, std::min(window_height - (int)overlay_->getTextureHeight(), top_));
467  overlay_->setPosition(left_, top_);
468  }
469 
471  {
472  boost::mutex::scoped_lock lock(mutex_);
473  unsubscribe();
474  subscribe();
475  }
476 
478  {
479  boost::mutex::scoped_lock lock(mutex_);
481  }
482 
484  {
485  boost::mutex::scoped_lock lock(mutex_);
487  }
488 
490  {
491  if (keep_centered_ &&
493  updateLeft();
494  updateTop();
495  }
496  boost::mutex::scoped_lock lock(mutex_);
498  }
499 
501  {
504  // read all the parameters from properties
505  updateFGColor();
506  updateFGAlpha();
508  }
513  }
514  else {
517  }
518  }
519 
521  {
524  // read all the parameters from properties
525  updateBGColor();
526  updateBGAlpha();
528  }
533  }
534  else {
537  }
538  }
539 
541  {
542  QColor c = fg_color_property_->getColor();
543  fg_color_.setRed(c.red());
544  fg_color_.setGreen(c.green());
545  fg_color_.setBlue(c.blue());
548  }
549  }
550 
552  {
553  fg_color_.setAlpha(fg_alpha_property_->getFloat() * 255.0);
556  }
557  }
558 
560  {
561  QColor c = bg_color_property_->getColor();
562  bg_color_.setRed(c.red());
563  bg_color_.setGreen(c.green());
564  bg_color_.setBlue(c.blue());
567  }
568  }
569 
571  {
572  bg_color_.setAlpha(bg_alpha_property_->getFloat() * 255.0);
575  }
576  }
577 
579  {
580  return (overlay_ && overlay_->isTextureReady() &&
581  top_ < y && top_ + overlay_->getTextureHeight() > y &&
582  left_ < x && left_ + overlay_->getTextureWidth() > x);
583  }
584 
586  {
587  if (!keep_centered_)
588  {
589  top_ = y;
590  left_ = x;
591  }
592  }
593 
595  {
596  if (!keep_centered_)
597  {
600  }
601  }
602 }
603 
virtual int drawAreaWidth(const jsk_rviz_plugins::OverlayMenu::ConstPtr &msg)
void setMin(float min)
void setMax(float max)
jsk_rviz_plugins::OverlayMenu::ConstPtr current_menu_
virtual QImage getQImage(unsigned int width, unsigned int height)
PLUGINLIB_EXPORT_CLASS(jsk_rviz_plugins::PictogramArrayDisplay, rviz::Display)
DisplayContext * context_
virtual QColor getColor() const
virtual ViewManager * getViewManager() const=0
rviz::RosTopicProperty * update_topic_property_
rviz::BoolProperty * overtake_bg_color_properties_property_
void setMin(int min)
width
#define ROS_WARN(...)
std::string getTopicStd() const
virtual int drawAreaHeight(const jsk_rviz_plugins::OverlayMenu::ConstPtr &msg)
jsk_rviz_plugins::OverlayMenu::ConstPtr next_menu_
virtual void update(float wall_dt, float ros_dt)
rviz::BoolProperty * overtake_fg_color_properties_property_
RenderPanel * getRenderPanel() const
virtual void processMessage(const jsk_rviz_plugins::OverlayMenu::ConstPtr &msg)
virtual std::string getMenuString(const jsk_rviz_plugins::OverlayMenu::ConstPtr &msg, size_t index)
virtual int getInt() const
bool setValue(const QVariant &new_value) override
w
virtual float getFloat() const
const double animate_duration
virtual bool getBool() const
#define ROS_DEBUG(...)


jsk_rviz_plugins
Author(s): Kei Okada , Yohei Kakiuchi , Shohei Fujii , Ryohei Ueda
autogenerated on Thu Jun 1 2023 02:45:58