Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CEGUIMenuItem.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUIMenuItem.cpp
00003         created:        2/4/2005
00004         author:         Tomas Lindquist Olsen (based on code by Paul D Turner)
00005         
00006         purpose:        Implementation of MenuItem widget base class
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "elements/CEGUIMenuItem.h"
00027 #include "elements/CEGUIMenubar.h"
00028 #include "elements/CEGUIPopupMenu.h"
00029 
00030 #include "CEGUILogger.h"
00031 
00032 // Start of CEGUI namespace section
00033 namespace CEGUI
00034 {
00035 
00036 /*************************************************************************
00037 Definition of Properties for this class
00038 *************************************************************************/
00039 MenuItemProperties::HoverColour                 MenuItem::d_hoverColourProperty;
00040 MenuItemProperties::PushedColour                MenuItem::d_pushedColourProperty;
00041 MenuItemProperties::OpenedColour                MenuItem::d_openedColourProperty;
00042 MenuItemProperties::NormalTextColour    MenuItem::d_normalTextColourProperty;
00043 MenuItemProperties::DisabledTextColour  MenuItem::d_disabledTextColourProperty;
00044 
00045 
00046 /*************************************************************************
00047         Constants
00048 *************************************************************************/
00049 // default colours for rendering
00050 const colour    MenuItem::DefaultHoverColour            = 0xFFFFFFFF;
00051 const colour    MenuItem::DefaultPushedColour           = 0xFFFFFFFF;
00052 const colour    MenuItem::DefaultOpenedColour           = 0xFFEFEFEF;
00053 const colour    MenuItem::DefaultNormalTextColour       = 0xFFFFFFFF;
00054 const colour    MenuItem::DefaultDisabledTextColour     = 0xFF7F7F7F;
00055 
00056 // event strings
00057 const String MenuItem::EventNamespace("MenuItem");
00058 const String MenuItem::EventClicked( (utf8*)"Clicked" );
00059 
00060 
00061 /*************************************************************************
00062         Constructor for MenuItem base class.
00063 *************************************************************************/
00064 MenuItem::MenuItem(const String& type, const String& name)
00065         : TextItem(type, name),
00066         d_pushed(false),
00067         d_hovering(false),
00068         d_opened(false),
00069         d_hoverColour(DefaultHoverColour),
00070         d_pushedColour(DefaultPushedColour),
00071         d_openedColour(DefaultOpenedColour),
00072         d_normalTextColour(DefaultNormalTextColour),
00073         d_disabledTextColour(DefaultDisabledTextColour),
00074         d_popup(NULL)
00075 {
00076         // menuitems dont want multi-click events
00077         setWantsMultiClickEvents(false);
00078         
00079         // add the additional events generated by this derived class
00080         addMenuItemEvents();
00081 
00082         addMenuItemProperties();
00083 }
00084 
00085 
00086 /*************************************************************************
00087         Destructor for MenuItem base class.
00088 *************************************************************************/
00089 MenuItem::~MenuItem(void)
00090 {
00091 }
00092 
00093 
00094 /*************************************************************************
00095         Update the internal state of the Widget
00096 *************************************************************************/
00097 void MenuItem::updateInternalState(const Point& mouse_pos)
00098 {
00099         bool oldstate = d_hovering;
00100 
00101         // assume not hovering 
00102         d_hovering = false;
00103 
00104         // if input is captured, but not by 'this', then we never hover highlight
00105         const Window* capture_wnd = getCaptureWindow();
00106 
00107         if ((capture_wnd == NULL) || (capture_wnd == this))
00108         {
00109                 Window* sheet = System::getSingleton().getGUISheet();
00110 
00111                 if (sheet != NULL)
00112                 {
00113                         // check if hovering highlight is required, which is basically ("mouse over widget" XOR "widget pushed").
00114                         if ((this == sheet->getChildAtPosition(mouse_pos)) != d_pushed)
00115                         {
00116                                 d_hovering = true;
00117 
00118                                 // are we attached to a menu ?
00119                                 if (getParent()->testClassName("MenuBase"))
00120                                 {
00121                                         MenuBase* menu = (MenuBase*)getParent();
00122 
00123                                         // is item really in list ?
00124                                         if (menu->isItemInList(this))
00125                                         {
00126                                                 // does this menubar only allow one popup open? and is there a popup open?
00127                                                 if ( !menu->isMultiplePopupsAllowed() && menu->getPopupMenuItem()!=NULL )
00128                                                 {
00129                                                         // open this popup instead
00130                                                         openPopupMenu();
00131                                                 }
00132 
00133                                         }
00134 
00135                                 }
00136 
00137                         }
00138 
00139                 }
00140 
00141         }
00142 
00143         // if state has changed, trigger a re-draw
00144         if (oldstate != d_hovering)
00145         {
00146                 requestRedraw();
00147         }
00148 
00149 }
00150 
00151 
00152 /*************************************************************************
00153         Set the popup menu for this item.
00154 *************************************************************************/
00155 void MenuItem::setPopupMenu(PopupMenu* popup)
00156 {
00157         // already attached?
00158         if (isChild(popup))
00159         {
00160                 d_popup = popup;
00161                 return;
00162         }
00163 
00164         // attach as child
00165         addChildWindow(popup);
00166         d_popup = popup;
00167 }
00168 
00169 /*************************************************************************
00170         Open the PopupMenu attached to this item.
00171 *************************************************************************/
00172 void MenuItem::openPopupMenu()
00173 {
00174         // no popup? or already open...
00175         if ( d_popup == NULL || d_opened )
00176                 return;
00177 
00178         // if we are attached to a menubar, we let it handle the "activation"
00179         MenuBase* menu = (Menubar*)getParent();
00180         if (getParent()->testClassName("Menubar") && menu->isItemInList(this))
00181         {
00182                 // align the popup to the bottom-left of the menuitem
00183                 Point pos(0,getAbsoluteRect().getHeight());
00184                 d_popup->setPosition(Absolute,pos);
00185 
00186                 menu->changePopupMenuItem(this);
00187         }
00188         // or maybe a popup menu?
00189         else if (getParent()->testClassName("PopupMenu") && menu->isItemInList(this))
00190         {
00191                 // align the popup to the top-right of the menuitem
00192                 const Rect absrect = getAbsoluteRect();
00193                 Point pos(absrect.getWidth(),0);
00194                 d_popup->setPosition(Absolute,pos);
00195 
00196                 menu->changePopupMenuItem(this);
00197         }
00198         // otherwise we do ourselves
00199         else
00200         {
00201                 // match up with Menubar::changePopupMenu
00202                 d_popup->openPopupMenu();
00203         }
00204 
00205         d_opened = true;
00206         requestRedraw();
00207 }
00208 
00209 
00210 /*************************************************************************
00211         Close the PopupMenu attached to this item.
00212 *************************************************************************/
00213 void MenuItem::closePopupMenu(bool notify)
00214 {
00215         // no popup? or not open...
00216         if ( d_popup == NULL || !d_opened )
00217                 return;
00218 
00219         // should we notify the parent menubar? otherwise...
00220         // if we are attached to a menubar, we let it handle the "deactivation"
00221         // only if the menubar does not allow multiple popups
00222         MenuBase* menu = (MenuBase*)getParent();
00223         if (notify && getParent()->testClassName("MenuBase") && menu->isItemInList(this) && !menu->isMultiplePopupsAllowed())
00224         {
00225                 menu->changePopupMenuItem(NULL);
00226         }
00227         // otherwise we do ourselves
00228         else
00229         {
00230                 // match up with Menubar::changePopupMenu
00231                 //d_popup->hide();
00232                 d_popup->closePopupMenu();
00233         }
00234 
00235         d_opened = false;
00236         requestRedraw();
00237 }
00238 
00239 
00240 /*************************************************************************
00241         Toggles the PopupMenu.
00242 *************************************************************************/
00243 bool MenuItem::togglePopupMenu(void)
00244 {
00245         if (d_opened)
00246         {
00247                 closePopupMenu();
00248                 return false;
00249         }
00250 
00251         openPopupMenu();
00252         return true;
00253 }
00254 
00255 /*************************************************************************
00256         Set the colour to use for the label text when rendering in the
00257         hover / highlighted states.     
00258 *************************************************************************/
00259 void MenuItem::setHoverColour(const colour& col)
00260 {
00261         if (d_hoverColour != col)
00262         {
00263                 d_hoverColour = col;
00264                 requestRedraw();
00265         }
00266 
00267 }
00268 
00269 
00270 /*************************************************************************
00271         Set the colour to use for the label text when rendering in the
00272         pushed state.
00273 *************************************************************************/
00274 void MenuItem::setPushedColour(const colour& col)
00275 {
00276         if (d_pushedColour != col)
00277         {
00278                 d_pushedColour = col;
00279                 requestRedraw();
00280         }
00281 
00282 }
00283 
00284 
00285 /*************************************************************************
00286         Set the colour to use for the label text when rendering in the
00287         opened state.
00288 *************************************************************************/
00289 void MenuItem::setOpenedColour(const colour& col)
00290 {
00291         if (d_openedColour != col)
00292         {
00293                 d_openedColour = col;
00294                 requestRedraw();
00295         }
00296 
00297 }
00298 
00299 
00300 /*************************************************************************
00301         Set the colour to use for the label text when rendering in the
00302         normal state.   
00303 *************************************************************************/
00304 void MenuItem::setNormalTextColour(const colour& col)
00305 {
00306         if (d_normalTextColour != col)
00307         {
00308                 d_normalTextColour = col;
00309                 requestRedraw();
00310         }
00311 
00312 }
00313 
00314 
00315 /*************************************************************************
00316         Set the colour to use for the label text when rendering in the
00317         disabled state. 
00318 *************************************************************************/
00319 void MenuItem::setDisabledTextColour(const colour& col)
00320 {
00321         if (d_disabledTextColour != col)
00322         {
00323                 d_disabledTextColour = col;
00324                 requestRedraw();
00325         }
00326 
00327 }
00328 
00329 
00330 /*************************************************************************
00331         Recursive function that closes all popups down the hierarcy starting
00332         with this one.
00333 *************************************************************************/
00334 void MenuItem::closeAllMenuItemPopups()
00335 {
00336         // are we attached to a PopupMenu?
00337         PopupMenu* pop = (PopupMenu*)getParent();
00338         if (getParent()->testClassName("PopupMenu") && pop->isItemInList(this))
00339         {
00340                 // is this parent popup attached to a menu item?
00341                 MenuItem* item = (MenuItem*)pop->getParent();
00342                 if (item!=NULL && item->testClassName("MenuItem"))
00343                 {
00344                         // close popup
00345                         item->closePopupMenu();
00346                         // recurse
00347                         item->closeAllMenuItemPopups();
00348                 }
00349                 // otherwise we just hide ourselves
00350                 else
00351                 {
00352                         //pop->closePopupMenu();
00353                         item->closePopupMenu();
00354                 }
00355         }
00356 }
00357 
00358 
00359 /*************************************************************************
00360         Add menuitem specific events    
00361 *************************************************************************/
00362 void MenuItem::addMenuItemEvents(void)
00363 {
00364         addEvent(EventClicked);
00365 }
00366 
00367 
00368 /*************************************************************************
00369         handler invoked internally when the menuitem is clicked.        
00370 *************************************************************************/
00371 void MenuItem::onClicked(WindowEventArgs& e)
00372 {
00373         // close the popup if we did'nt spawn a child
00374         if (!d_opened && !d_popupWasClosed)
00375         {
00376                 closeAllMenuItemPopups();
00377         }
00378         d_popupWasClosed=false;
00379         fireEvent(EventClicked, e, EventNamespace);
00380 }
00381 
00382 
00383 /*************************************************************************
00384         Handler for when the mouse moves
00385 *************************************************************************/
00386 void MenuItem::onMouseMove(MouseEventArgs& e)
00387 {
00388         // this is needed to discover whether mouse is in the widget area or not.
00389         // The same thing used to be done each frame in the rendering method,
00390         // but in this version the rendering method may not be called every frame
00391         // so we must discover the internal widget state here - which is actually
00392         // more efficient anyway.
00393 
00394         // base class processing
00395         Window::onMouseMove(e);
00396 
00397         updateInternalState(e.position);
00398         e.handled = true;
00399 }
00400 
00401 
00402 /*************************************************************************
00403         Handler for mouse button pressed events
00404 *************************************************************************/
00405 void MenuItem::onMouseButtonDown(MouseEventArgs& e)
00406 {
00407         // default processing
00408         Window::onMouseButtonDown(e);
00409 
00410         if (e.button == LeftButton)
00411         {
00412                 d_popupWasClosed = false;
00413                 if (captureInput())
00414                 {
00415                         d_pushed = true;
00416                         updateInternalState(e.position);
00417                         d_popupWasClosed = !togglePopupMenu();
00418                         requestRedraw();
00419                 }
00420 
00421                 // event was handled by us.
00422                 e.handled = true;
00423         }
00424 
00425 }
00426 
00427 
00428 /*************************************************************************
00429         Handler for mouse button release events
00430 *************************************************************************/
00431 void MenuItem::onMouseButtonUp(MouseEventArgs& e)
00432 {
00433         // default processing
00434         Window::onMouseButtonUp(e);
00435 
00436         if (e.button == LeftButton)
00437         {
00438                 releaseInput();
00439                 
00440                 // was the button released over this window?
00441                 if ( !d_popupWasClosed && System::getSingleton().getGUISheet()->getChildAtPosition(e.position) == this )
00442                 {
00443                         WindowEventArgs we(this);
00444                         onClicked(we);
00445                 }
00446 
00447                 // event was handled by us.
00448                 e.handled = true;
00449         }
00450 
00451 }
00452 
00453 /*************************************************************************
00454         Handler for when mouse capture is lost
00455 *************************************************************************/
00456 void MenuItem::onCaptureLost(WindowEventArgs& e)
00457 {
00458         // Default processing
00459         Window::onCaptureLost(e);
00460 
00461         d_pushed = false;
00462         updateInternalState(MouseCursor::getSingleton().getPosition());
00463         requestRedraw();
00464 
00465         // event was handled by us.
00466         e.handled = true;
00467 }
00468 
00469 
00470 /*************************************************************************
00471         Handler for when mouse leaves the widget
00472 *************************************************************************/
00473 void MenuItem::onMouseLeaves(MouseEventArgs& e)
00474 {
00475         // deafult processing
00476         Window::onMouseLeaves(e);
00477 
00478         d_hovering = false;
00479         requestRedraw();
00480 
00481         e.handled = true;
00482 }
00483 
00484 
00485 /*************************************************************************
00486         Internal version of adding a child window.
00487 *************************************************************************/
00488 void MenuItem::addChild_impl(Window* wnd)
00489 {
00490         TextItem::addChild_impl(wnd);
00491 
00492         // if this is a PopupMenu we add it like one. only if there is not already a popup attached.
00493         if (wnd->testClassName("PopupMenu") && d_popup==NULL)
00494         {
00495                 setPopupMenu((PopupMenu*)wnd);
00496         }
00497 
00498 }
00499 
00500 
00501 /*************************************************************************
00502         Add MenuItem specific properties
00503 *************************************************************************/
00504 void MenuItem::addMenuItemProperties(void)
00505 {
00506         addProperty(&d_hoverColourProperty);
00507         addProperty(&d_pushedColourProperty);
00508         addProperty(&d_openedColourProperty);
00509         addProperty(&d_normalTextColourProperty);
00510         addProperty(&d_disabledTextColourProperty);
00511 }
00512 
00513 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:32 2005 for Crazy Eddies GUI System by  doxygen 1.4.3