menu_handler.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
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 the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       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 THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  * 
00029  * Author: David Gossow
00030  */
00031 
00032 #include "interactive_markers/menu_handler.h"
00033 
00034 #include <boost/bind.hpp>
00035 #include <boost/make_shared.hpp>
00036 
00037 namespace interactive_markers
00038 {
00039 
00040 MenuHandler::MenuHandler() :
00041     current_handle_(1)
00042 {
00043 
00044 }
00045 
00046 MenuHandler::EntryHandle MenuHandler::insert( const std::string &title,
00047     const FeedbackCallback &feedback_cb )
00048 {
00049   EntryHandle handle = doInsert( title, visualization_msgs::MenuEntry::FEEDBACK, "", feedback_cb );
00050   top_level_handles_.push_back( handle );
00051   return handle;
00052 }
00053 
00054 MenuHandler::EntryHandle MenuHandler::insert( const std::string &title,
00055                                               const uint8_t command_type,
00056                                               const std::string &command )
00057 {
00058   EntryHandle handle = doInsert( title, command_type, command, FeedbackCallback() );
00059   top_level_handles_.push_back( handle );
00060   return handle;
00061 }
00062 
00063 
00064 MenuHandler::EntryHandle MenuHandler::insert( EntryHandle parent, const std::string &title,
00065     const FeedbackCallback &feedback_cb )
00066 {
00067   boost::unordered_map<EntryHandle, EntryContext>::iterator parent_context =
00068       entry_contexts_.find( parent );
00069 
00070   ROS_ASSERT_MSG ( parent_context != entry_contexts_.end(), "Parent menu entry %u not found.", parent );
00071 
00072   EntryHandle handle = doInsert( title, visualization_msgs::MenuEntry::FEEDBACK, "", feedback_cb );
00073   parent_context->second.sub_entries.push_back( handle );
00074   return handle;
00075 }
00076 
00077 
00078 MenuHandler::EntryHandle MenuHandler::insert( EntryHandle parent, const std::string &title,
00079                                               const uint8_t command_type,
00080                                               const std::string &command )
00081 {
00082   boost::unordered_map<EntryHandle, EntryContext>::iterator parent_context =
00083       entry_contexts_.find( parent );
00084 
00085   ROS_ASSERT_MSG ( parent_context != entry_contexts_.end(), "Parent menu entry %u not found.", parent );
00086 
00087   EntryHandle handle = doInsert( title, command_type, command, FeedbackCallback() );
00088   parent_context->second.sub_entries.push_back( handle );
00089   return handle;
00090 }
00091 
00092 
00093 bool MenuHandler::setVisible( EntryHandle handle, bool visible )
00094 {
00095   boost::unordered_map<EntryHandle, EntryContext>::iterator context =
00096       entry_contexts_.find( handle );
00097 
00098   if ( context == entry_contexts_.end() )
00099   {
00100     return false;
00101   }
00102 
00103   context->second.visible = visible;
00104   return true;
00105 }
00106 
00107 
00108 bool MenuHandler::setCheckState( EntryHandle handle, CheckState check_state )
00109 {
00110   boost::unordered_map<EntryHandle, EntryContext>::iterator context =
00111       entry_contexts_.find( handle );
00112 
00113   if ( context == entry_contexts_.end() )
00114   {
00115     return false;
00116   }
00117 
00118   context->second.check_state = check_state;
00119   return true;
00120 }
00121 
00122 
00123 bool MenuHandler::getCheckState( EntryHandle handle, CheckState &check_state ) const
00124 {
00125   boost::unordered_map<EntryHandle, EntryContext>::const_iterator context =
00126       entry_contexts_.find( handle );
00127 
00128   if ( context == entry_contexts_.end() )
00129   {
00130     check_state = NO_CHECKBOX;
00131     return false;
00132   }
00133 
00134   check_state = context->second.check_state;
00135   return true;
00136 }
00137 
00138 
00139 bool MenuHandler::apply( InteractiveMarkerServer &server, const std::string &marker_name )
00140 {
00141   visualization_msgs::InteractiveMarker int_marker;
00142 
00143   if ( !server.get( marker_name, int_marker ) )
00144   {
00145     // This marker has been deleted on the server, so forget it.
00146     managed_markers_.erase( marker_name );
00147     return false;
00148   }
00149 
00150   int_marker.menu_entries.clear();
00151 
00152   pushMenuEntries( top_level_handles_, int_marker.menu_entries, 0 );
00153 
00154   server.insert( int_marker );
00155   server.setCallback( marker_name, boost::bind( &MenuHandler::processFeedback, this, _1 ), visualization_msgs::InteractiveMarkerFeedback::MENU_SELECT );
00156   managed_markers_.insert( marker_name );
00157   return true;
00158 }
00159 
00160 bool MenuHandler::pushMenuEntries( std::vector<EntryHandle>& handles_in,
00161                                    std::vector<visualization_msgs::MenuEntry>& entries_out,
00162                                    EntryHandle parent_handle )
00163 {
00164   for ( unsigned t = 0; t < handles_in.size(); t++ )
00165   {
00166     EntryHandle handle = handles_in[t];
00167     boost::unordered_map<EntryHandle, EntryContext>::iterator context_it =
00168         entry_contexts_.find( handle );
00169 
00170     if ( context_it == entry_contexts_.end() )
00171     {
00172       ROS_ERROR( "Internal error: context handle not found! This is a bug in MenuHandler." );
00173       return false;
00174     }
00175 
00176     EntryContext& context = context_it->second;
00177 
00178     if ( !context.visible )
00179     {
00180       continue;
00181     }
00182 
00183     entries_out.push_back( makeEntry( context, handle, parent_handle ));
00184     if( false == pushMenuEntries( context.sub_entries, entries_out, handle ))
00185     {
00186       return false;
00187     }
00188   }
00189   return true;
00190 }
00191 
00192 bool MenuHandler::reApply( InteractiveMarkerServer &server )
00193 {
00194   bool success = true;
00195   std::set<std::string>::iterator it = managed_markers_.begin();
00196   while ( it != managed_markers_.end() )
00197   {
00198     // apply() may delete the entry "it" is pointing to, so
00199     // pre-compute the next iterator.
00200     std::set<std::string>::iterator next_it = it;
00201     next_it++;
00202     success = apply( server, *it ) && success;
00203     it = next_it;
00204   }
00205   return success;
00206 }
00207 
00208 MenuHandler::EntryHandle MenuHandler::doInsert( const std::string &title,
00209                                                 const uint8_t command_type,
00210                                                 const std::string &command,
00211                                                 const FeedbackCallback &feedback_cb )
00212 {
00213   EntryHandle handle = current_handle_;
00214   current_handle_++;
00215 
00216   EntryContext context;
00217   context.title = title;
00218   context.command = command;
00219   context.command_type = command_type;
00220   context.visible = true;
00221   context.check_state = NO_CHECKBOX;
00222   context.feedback_cb = feedback_cb;
00223 
00224   entry_contexts_[handle] = context;
00225   return handle;
00226 }
00227 
00228 visualization_msgs::MenuEntry MenuHandler::makeEntry( EntryContext& context, EntryHandle handle, EntryHandle parent_handle )
00229 {
00230   visualization_msgs::MenuEntry menu_entry;
00231 
00232   switch ( context.check_state )
00233   {
00234     case NO_CHECKBOX:
00235       menu_entry.title = context.title;
00236       break;
00237     case CHECKED:
00238       menu_entry.title = "[x] "+context.title;
00239       break;
00240     case UNCHECKED:
00241       menu_entry.title = "[ ] "+context.title;
00242       break;
00243   }
00244 
00245   menu_entry.command = context.command;
00246   menu_entry.command_type = context.command_type;
00247   menu_entry.id = handle;
00248   menu_entry.parent_id = parent_handle;
00249 
00250   return menu_entry;
00251 }
00252 
00253 
00254 void MenuHandler::processFeedback( const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback )
00255 {
00256   boost::unordered_map<EntryHandle, EntryContext>::iterator context =
00257     entry_contexts_.find( (EntryHandle) feedback->menu_entry_id );
00258 
00259   if ( context != entry_contexts_.end() && context->second.feedback_cb )
00260   {
00261     context->second.feedback_cb( feedback );
00262   }
00263 }
00264 
00265 bool MenuHandler::getTitle( EntryHandle handle, std::string &title ) const
00266 {
00267   boost::unordered_map<EntryHandle, EntryContext>::const_iterator context =
00268       entry_contexts_.find( handle );
00269 
00270   if ( context == entry_contexts_.end() )
00271   {
00272     return false;
00273   }
00274 
00275   title = context->second.title;
00276   return true;
00277 }
00278 
00279 
00280 
00281 }


interactive_markers
Author(s): David Gossow (C++), Michael Ferguson (Python)
autogenerated on Mon Jan 6 2014 11:54:25