Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

ControlBase.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_ControlBase_h
00003 #define INCLUDED_ControlBase_h
00004 
00005 #include "Motion/MotionManagerMsg.h"
00006 #include <string>
00007 #include <vector>
00008 #include <map>
00009 class Socket;
00010 
00011 //! Creates name token for the auto registration variable, have to do a layer of indirection to get line number into token so that a behavior can be registered in multiple menus
00012 #define AUTO_REGISTER_NAME_INDIRECT(className, line) autoRegister ## className ## line
00013 //! Creates name token for the auto registration variable, have to do a layer of indirection to get line number into token so that a behavior can be registered in multiple menus
00014 #define AUTO_REGISTER_NAME(className, line) AUTO_REGISTER_NAME_INDIRECT(className, line)
00015 
00016 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a control in the controller menu system.  See also #REGISTER_CONTROL and #REGISTER_BEHAVIOR for behaviors
00017 /*! Specify the menu name (use '/' to demark submenus) and allows you to pass optional flags */
00018 #define REGISTER_CONTROL_INSTANCE_OPT(className, controlInstance, menu, flags) \
00019 const ControlBase* AUTO_REGISTER_NAME(className,__LINE__) = ControlBase::registerControllerEntry(controlInstance,menu,flags)
00020 
00021 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a control in the controller menu system.  See also #REGISTER_CONTROL and #REGISTER_BEHAVIOR for behaviors
00022 /*! Specify the menu name (use '/' to demark submenus) */
00023 #define REGISTER_CONTROL_INSTANCE(className, controlInstance, menu) REGISTER_CONTROL_INSTANCE_OPT(className, controlInstance, menu, ControlBase::DEFAULTS)
00024 
00025 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a control in the controller menu system.  See also #REGISTER_CONTROL_INSTANCE and #REGISTER_BEHAVIOR for behaviors
00026 /*! Specify the menu name (use '/' to demark submenus) and allows you to pass optional flags. */
00027 #define REGISTER_CONTROL_OPT(className, menu, flags) REGISTER_CONTROL_INSTANCE_OPT(className, new className, menu, flags)
00028 
00029 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a control in the controller menu system.  See also #REGISTER_CONTROL_INSTANCE and #REGISTER_BEHAVIOR for behaviors
00030 /*! Specify the menu name (use '/' to demark submenus). */
00031 #define REGISTER_CONTROL(className, menu) REGISTER_CONTROL_INSTANCE(className, new className, menu)
00032 
00033 
00034 //! Base class for all items in the Controller hierarchy.
00035 /*! These are similar to behaviors in that they can do processing and
00036  *  are told when to start and stop.
00037  *
00038  *  However, the important difference is that these have to follow a
00039  *  much tighter set of guidelines for a more refined purpose - user
00040  *  interface.  Controls do not directly receive events - the
00041  *  Controller will process events for them and call the appropriate
00042  *  functions at the appropriate times.  Controls are expected to fit
00043  *  into a heirarchical scheme, where each control (except the root)
00044  *  has a parent which created it, and may return its own children
00045  *  where appropriate.
00046  *
00047  *  Controls can be very powerful, and a class can be both a behavior
00048  *  and a control.  This allows integrated user interface to
00049  *  controlling a complex behavior.  Some controls may simply need
00050  *  EventListener access instead to perform a few tricks.  Mix and
00051  *  match as you see fit.  (multiple inheritance can be nice if it's
00052  *  planned for, as these have been)
00053  *
00054  *  This base class will do most of the work of maintaining submenus
00055  *  for you, and will call appropriate virtual functions which you are
00056  *  expected to override.  Controls generally live in
00057  *  <tt>Behaviors/Controls/</tt> as the Controller itself is a
00058  *  behavior, and these controls merely its tools.
00059  *
00060  *  The ControlBase pointers which are returned at various points are the
00061  *  responsibility of the creator.  Controller will not delete them upon
00062  *  deactivation.
00063  *
00064  *  GUI Theory: \n
00065  *  There are 3 levels to the user interface.
00066  *  -# Robot/Local: Uses the buttons for input, and LEDs and sounds for immediate feedback.  No external resources needed
00067  *  -# Text: Uses a console to display/request information.
00068  *  -# GUI: Uses a graphical interface on a desktop machine
00069  *
00070  *  Obviously, higher levels require more technological resources, which also
00071  *  means there's more to go wrong and debug.  However, another important
00072  *  distinction between the first level and the others is that the first level
00073  *  does not require the user to lose direct contact with the robot.  Requiring
00074  *  the user to move back and forth from robot to computer can be much more
00075  *  frustrating than decoding LED signals or press head buttons.  There are also
00076  *  safety issues when triggering behaviors remotely if the robot is out of
00077  *  immediate reach.  But of course, having a GUI and text output is extremely
00078  *  valuable in terms of ease of use and efficiency.
00079  *
00080  *  So, the lesson is to try to support all 3 levels so that your interfaces
00081  *  will be robust and efficient in a variety of environments.  You'll thank
00082  *  yourself when you're demoing on the road and you can't get wavelan up, or
00083  *  the guest machine you're supposed to use doesn't have Java, or whatever.
00084  *
00085  * @todo ControlBase's should use ReferenceCounter so memory management is not an issue
00086  * @see Controller, NullControl */
00087 class ControlBase {
00088 public:
00089   //! Typically would use MotionManager::MC_ID, but re-specified here for convenience and to avoid dependence on MotionManager.h
00090   typedef MotionManagerMsg::MC_ID MC_ID;
00091   //! Typically would use MotionManager::invalid_MC_ID, but re-specified here for convenience and to avoid dependence on MotionManager.h
00092   static const MC_ID invalid_MC_ID=MotionManagerMsg::invalid_MC_ID;
00093   
00094   //! @name Constructors/Destructors
00095 
00096   ControlBase() : name("(null name)"), description(), hilights(), options(), doRewrite(false), display_id(invalid_MC_ID), gui_comm(NULL) {} //!< Contructor
00097   ControlBase(const std::string& n) : name(n), description((n.size()>16)?n:std::string()), hilights(), options(), doRewrite(false), display_id(invalid_MC_ID), gui_comm(NULL) {} //!< Contructor, initializes with a name
00098   ControlBase(const std::string& n, const std::string& d) : name(n), description(d), hilights(), options(), doRewrite(false), display_id(invalid_MC_ID), gui_comm(NULL) {} //!< Contructor, initializes with a name
00099 
00100   //! Destructor
00101   virtual ~ControlBase() {
00102     //    deactivate();
00103     //cout << "~ControlBase(): " << name << endl;
00104     clearSlots();
00105   }
00106 
00107   //@}
00108 
00109   //! You probably want to override some of these, call the ControlBase functions from your code if you want default sound effects (or look in Config::controller_config).
00110   //! @name Controller Functions
00111 
00112   //! Called when the control is activated (or the control system is reactivating)
00113   /*! Takes the id number of a LedMC which the control should use, maintained by Controller.
00114    *  Controls share the display which is passed, and may use the socket @a gui to communicate with the GUI controller, if it is connected.
00115    *  @return a ControlBase pointer.  Return: @li @a this if the control should stay active (if it's not a one-shot command) @li @c NULL to return to parent @li other address to spawn a child control*/
00116   virtual ControlBase * activate(MC_ID disp_id, Socket * gui);
00117   virtual void pause();      //!< called when a control is being overriden by a child, or the control system is deactivating (e-stop being turned off)
00118   virtual void refresh();    //!< called when the child has deactivated and this control should refresh its display, or some other event (such as the user pressing the refresh button) has happened to cause a refresh to be needed
00119   virtual void deactivate(); //!< called when this control is being popped from the control stack
00120 
00121   //! when the user has trigger an "open selection" - default is to return the hilighted control*/
00122   /*! The value which is returned is then activate()ed and pushed on the Controller's stack*/
00123   virtual ControlBase * doSelect();
00124   //! when the user wants to increment the control - default is to hilight the first non-null slot after the last hilight, and return @c this
00125   /*! The value which is returned is then activate()ed and pushed on the Controller's stack, so you probably want to return @c this */
00126   virtual ControlBase * doNextItem();
00127   //! when the user wants to decrement the control - default is to hilight the last non-null slot before the first hilight, and return @c this
00128   /*! The value which is returned is then activate()ed and pushed on the Controller's stack, so you probably want to return @c this */
00129   virtual ControlBase * doPrevItem();
00130   //! when the user wants to cancel - you should almost always return NULL now unless you need to override the cancel in order to confirm something (e.g. "Save changes?")
00131   /*! The value which is returned is then activate()ed and pushed on the Controller's stack, you probably want to return @c NULL */
00132   virtual ControlBase * doCancel();
00133   //! prompt the user for text input on the current input device (cin, tekkotsu console (sout), or GUI)
00134   /*! The value which is returned is then activate()ed and pushed on the Controller's stack, so you probably want to return @c this */
00135   virtual ControlBase * doReadStdIn(const std::string& prompt=std::string());
00136   //! called when the user has supplied a text string (may or may not have been prompted by doReadStdIn()!  May not even be active yet - the user can direct the same input to a set of hilighted menus)
00137   /*! The value which is returned is then activate()ed and pushed on the Controller's stack*/
00138   virtual ControlBase * takeInput(const std::string& msg); 
00139   //! may be called before takeInput to verify this Control can make sense of msg
00140   virtual bool validInput(const std::string& msg); 
00141   //! Called when the control is picked up from the control registry (implies it is now safe to access global resources, such as erouter)
00142   virtual void registered() {}
00143   //@}
00144   
00145   //! @name Accessors
00146 
00147   virtual ControlBase& setName(const std::string& n) { name=n; return *this; } //!< sets the name of the control
00148   virtual std::string getName() const { return name; } //!< returns the name of the control
00149 
00150   virtual ControlBase& setDescription(const std::string d) { description=d; return *this; } //!< sets the description of the control
00151   virtual std::string getDescription() const { return description; } //!< returns a short description of what the control does
00152 
00153   virtual const std::vector<ControlBase*>& getSlots() const { return options; } //!< returns the vector of sub-controls
00154   virtual ControlBase* findSlot(const std::string& name) const;
00155   virtual std::string getSlotName(unsigned int i) const; //!< returns the string that will appear in slot @a i
00156   virtual unsigned int slotsSize() const { return options.size(); } //!< returns the number of options available
00157   virtual void setSlot(unsigned int i,ControlBase* o); //!< sets @a i'th element of #options to @a o
00158   virtual void pushSlot(ControlBase* o); //!< sets next unused element of #options to @a o
00159   virtual void clearSlots(); //!< deletes each slot item and clears the slots
00160 
00161   virtual const std::vector<unsigned int>& getHilights() const { return hilights; } //!< returns a vector of the indicies of hilighted slots
00162   virtual void setHilights(const std::vector<unsigned int>& hi); //!< sets the hilighted slots
00163   virtual void hilightFirst(); //!< sets the hilight to the first non-null slot
00164 
00165   virtual MC_ID getDisplay() { return display_id; } //!< returns display being used
00166   virtual ControlBase& setDisplay(MC_ID d) { display_id=d; return *this; } //!< sets display to use
00167 
00168   //@}
00169   
00170   
00171   //! provides options for registerControllerEntry() and by extension #REGISTER_CONTROLLER_OPT and #REGISTER_CONTROLLER_MENU
00172   enum RegisterControllerFlags_t {
00173     DEFAULTS=0, //!< indicates default options (behavior will not be started automatically), see also #BEH_DEFAULTS macro
00174     BEH_START=1, //!< indicates the behavior should be activated at launch instead of waiting for the user to do it manually, see also #BEH_START macro
00175     BEH_RETAIN=2, //!< the behavior's memory allocation will *not* be freed between activations, so state will be maintained, see also #BEH_RETAIN macro
00176     BEH_NONEXCLUSIVE=4 //!< the behavior be able to run in parallel with other behaviors, see also #BEH_NONEXCLUSIVE macro
00177   };
00178   
00179   //! Registers a ControlBase to be added to the specified Controller menu, use '/' to specify sub-menus, see REGISTER_CONTROLLER macro.
00180   /*! This only works when called as an initializer to a static variable.  Once the menus have been initialized, later calls to this function won't update the menus. */
00181   static ControlBase* registerControllerEntry(ControlBase* c, const std::string& menu, int flags=ControlBase::DEFAULTS);
00182   
00183   typedef std::map<std::string,std::pair<ControlBase*,int> > ControlRegistryEntry_t; // !< shorthand for the map between original control names and their instances with flags, see getControllerEntries()
00184   typedef std::map<std::string, ControlRegistryEntry_t > ControlRegistry_t; //!< shorthand for the map between menu names and associated map of entries, see getControllerEntries()
00185   
00186   //! Provides static/global storage of behaviors requesting to be added to controller menus.
00187   /*! This collection is processed by the startup behavior to build the menu structure. */
00188   static ControlRegistry_t& getControllerEntries() {
00189     static ControlRegistry_t entries;
00190     return entries;
00191   }
00192   
00193   
00194 
00195 protected:
00196     
00197   //! clears the display (if use_VT100 is on)
00198   virtual void clearMenu();
00199   
00200   //! called by takeInput if the input doesn't match any slots or matches multiple slots -- the ControlBase implementation displays an error and returns itself
00201   /*! @param msg the input originally sent to takeInput()
00202    *  @param ambiguous true if the input matched more than one item, false if it didn't match any */
00203   virtual ControlBase* invalidInput(const std::string& msg, bool ambiguous);
00204 
00205   //! returns the average of the hilighted indicies - used to know to play the "next" sound, or the "prev" sound when the hilight changes
00206   float hilightsAvg() const;
00207 
00208   std::string name; //!< the name of this control
00209   std::string description; //!< the description of this control
00210   std::vector<unsigned int> hilights; //!< keep sorted - index(es) of current selection - can have multiple if using GUI
00211   std::vector<ControlBase*> options; //!< vector of controls to select from
00212   bool doRewrite; //!< toggles using VT100 codes to reposition the cursor at the beginning of the menu
00213                   /*!< we don't always want to do this, any time someone else might have written to
00214                    *   the display we set this to false so we don't overwrite it. */
00215 
00216   MC_ID display_id; //!< LedMC to use for displaying selection
00217   Socket * gui_comm; //!< socket to communicate with the GUI, if it is connected
00218   
00219 private:
00220   ControlBase(const ControlBase&); //!< you can override, but don't call this...
00221   ControlBase& operator=(const ControlBase&); //!< you can override, but don't call this...
00222 };
00223 
00224 /*! @file
00225  * @brief Defines ControlBase from which all items in the control system should inherit
00226  * @author ejt (Creator)
00227  */
00228 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:37 2016 by Doxygen 1.6.3