llmenugl.cpp

Go to the documentation of this file.
00001 
00032 //*****************************************************************************
00033 //
00034 // This file contains the opengl based menu implementation.
00035 //
00036 // NOTES: A menu label is split into 4 columns. The left column, the
00037 // label colum, the accelerator column, and the right column. The left
00038 // column is used for displaying boolean values for toggle and check
00039 // controls. The right column is used for submenus.
00040 //
00041 //*****************************************************************************
00042 
00043 //#include "llviewerprecompiledheaders.h"
00044 #include "linden_common.h"
00045 
00046 #include "llmenugl.h"
00047 
00048 #include "llmath.h"
00049 #include "llgl.h"
00050 #include "llfocusmgr.h"
00051 #include "llfont.h"
00052 #include "llcoord.h"
00053 #include "llwindow.h"
00054 #include "llcriticaldamp.h"
00055 #include "lluictrlfactory.h"
00056 
00057 #include "llfontgl.h"
00058 #include "llresmgr.h"
00059 #include "llui.h"
00060 
00061 #include "llglheaders.h"
00062 #include "llstl.h"
00063 
00064 #include "v2math.h"
00065 #include <set>
00066 #include <boost/tokenizer.hpp>
00067 
00068 // static
00069 LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
00070 
00071 S32 MENU_BAR_HEIGHT = 0;
00072 S32 MENU_BAR_WIDTH = 0;
00073 
00077 
00078 const LLString SEPARATOR_NAME("separator");
00079 const LLString TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
00080 const LLString SEPARATOR_LABEL( "-----------" );
00081 const LLString VERTICAL_SEPARATOR_LABEL( "|" );
00082 
00083 const S32 LABEL_BOTTOM_PAD_PIXELS = 2;
00084 
00085 const U32 LEFT_PAD_PIXELS = 3;
00086 const U32 LEFT_WIDTH_PIXELS = 15;
00087 const U32 LEFT_PLAIN_PIXELS = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS;
00088 
00089 const U32 RIGHT_PAD_PIXELS = 2;
00090 const U32 RIGHT_WIDTH_PIXELS = 15;
00091 const U32 RIGHT_PLAIN_PIXELS = RIGHT_PAD_PIXELS + RIGHT_WIDTH_PIXELS;
00092 
00093 const U32 ACCEL_PAD_PIXELS = 10;
00094 const U32 PLAIN_PAD_PIXELS = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS + RIGHT_PAD_PIXELS + RIGHT_WIDTH_PIXELS;
00095 
00096 const U32 BRIEF_PAD_PIXELS = 2;
00097 
00098 const U32 SEPARATOR_HEIGHT_PIXELS = 8;
00099 const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;
00100 const S32 MENU_ITEM_PADDING = 4;
00101 
00102 const LLString BOOLEAN_TRUE_PREFIX( "X" );
00103 const LLString BRANCH_SUFFIX( ">" );
00104 const LLString ARROW_UP  ("^^^^^^^");
00105 const LLString ARROW_DOWN("vvvvvvv");
00106 
00107 const F32 MAX_MOUSE_SLOPE_SUB_MENU = 0.9f;
00108 
00109 const S32 PIE_GESTURE_ACTIVATE_DISTANCE = 10;
00110 
00111 LLColor4 LLMenuItemGL::sEnabledColor( 0.0f, 0.0f, 0.0f, 1.0f );
00112 LLColor4 LLMenuItemGL::sDisabledColor( 0.5f, 0.5f, 0.5f, 1.0f );
00113 LLColor4 LLMenuItemGL::sHighlightBackground( 0.0f, 0.0f, 0.7f, 1.0f );
00114 LLColor4 LLMenuItemGL::sHighlightForeground( 1.0f, 1.0f, 1.0f, 1.0f );
00115 BOOL LLMenuItemGL::sDropShadowText = TRUE;
00116 
00117 LLColor4 LLMenuGL::sDefaultBackgroundColor( 0.25f, 0.25f, 0.25f, 0.75f );
00118 BOOL LLMenuGL::sKeyboardMode = FALSE;
00119 
00120 LLViewHandle LLMenuHolderGL::sItemLastSelectedHandle;
00121 LLFrameTimer LLMenuHolderGL::sItemActivationTimer;
00122 //LLColor4 LLMenuGL::sBackgroundColor( 0.8f, 0.8f, 0.0f, 1.0f );
00123 
00124 const S32 PIE_CENTER_SIZE = 20;         // pixels, radius of center hole
00125 const F32 PIE_SCALE_FACTOR = 1.7f; // scale factor for pie menu when mouse is initially down
00126 const F32 PIE_SHRINK_TIME = 0.2f; // time of transition between unbounded and bounded display of pie menu
00127 
00128 const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f;
00129 
00133 
00134 // Default constructor
00135 LLMenuItemGL::LLMenuItemGL( const LLString& name, const LLString& label, KEY key, MASK mask ) :
00136         LLView( name, TRUE ),
00137         mJumpKey(KEY_NONE),
00138         mAcceleratorKey( key ),
00139         mAcceleratorMask( mask ),
00140         mAllowKeyRepeat(FALSE),
00141         mHighlight( FALSE ),
00142         mGotHover( FALSE ),
00143         mBriefItem( FALSE ),
00144         mFont( LLFontGL::sSansSerif ),
00145         mStyle(LLFontGL::NORMAL),
00146         mDrawTextDisabled( FALSE )
00147 {
00148         setLabel( label );
00149 }
00150 
00151 // virtual
00152 LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const
00153 {
00154         LLXMLNodePtr node = LLView::getXML();
00155 
00156         node->createChild("type", TRUE)->setStringValue(getType());
00157 
00158         node->createChild("label", TRUE)->setStringValue(mLabel);
00159 
00160         if (mAcceleratorKey != KEY_NONE)
00161         {
00162                 std::stringstream out;
00163                 if (mAcceleratorMask & MASK_CONTROL)
00164                 {
00165                         out << "control|";
00166                 }
00167                 if (mAcceleratorMask & MASK_ALT)
00168                 {
00169                         out << "alt|";
00170                 }
00171                 if (mAcceleratorMask & MASK_SHIFT)
00172                 {
00173                         out << "shift|";
00174                 }
00175                 out << LLKeyboard::stringFromKey(mAcceleratorKey);
00176 
00177                 node->createChild("shortcut", TRUE)->setStringValue(out.str());
00178                 
00179 #ifdef LL_DARWIN
00180                 // Write in special tag if this key is really a ctrl combination on the Mac
00181                 if (mAcceleratorMask & MASK_MAC_CONTROL)
00182                 {
00183                         node->createChild("useMacCtrl", TRUE)->setBoolValue( TRUE );
00184                 }
00185 #endif // LL_DARWIN
00186         }
00187 
00188         return node;
00189 }
00190 
00191 BOOL LLMenuItemGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
00192 {
00193         // modified from LLView::handleKey
00194         // ignore visibility, as keyboard accelerators should still trigger menu items
00195         // even when they are not visible
00196         // also, ignore enabled flag for self, as that can change based on menu callbacks
00197         BOOL handled = FALSE;
00198 
00199         if( called_from_parent )  
00200         {
00201                 // Downward traversal
00202                 if (mEnabled)
00203                 {
00204                         handled = childrenHandleKey( key, mask ) != NULL;
00205                 }
00206         }
00207         
00208         if( !handled )
00209         {
00210                 handled = handleKeyHere( key, mask, called_from_parent );
00211         }
00212 
00213         return handled;
00214 }
00215 
00216 BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
00217 {
00218         if( mEnabled && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
00219         {
00220                 doIt();
00221                 return TRUE;
00222         }
00223         return FALSE;
00224 }
00225 
00226 BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask)
00227 {
00228         mGotHover = TRUE;
00229         getWindow()->setCursor(UI_CURSOR_ARROW);
00230         return TRUE;
00231 }
00232         
00233 void LLMenuItemGL::setBriefItem(BOOL b)
00234 {
00235         mBriefItem = b;
00236 }
00237 
00238 // This function checks to see if the accelerator key is already in use;
00239 // if not, it will be added to the list
00240 BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
00241 {
00242         LLKeyBinding *accelerator = NULL;
00243 
00244         if (mAcceleratorKey != KEY_NONE)
00245         {
00246                 std::list<LLKeyBinding*>::iterator list_it;
00247                 for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
00248                 {
00249                         accelerator = *list_it;
00250                         if ((accelerator->mKey == mAcceleratorKey) && (accelerator->mMask == (mAcceleratorMask & MASK_NORMALKEYS)))
00251                         {
00252 
00253                         // *NOTE: get calling code to throw up warning or route
00254                         // warning messages back to app-provided output
00255                         //      LLString warning;
00256                         //      warning.append("Duplicate key binding <");
00257                         //      appendAcceleratorString( warning );
00258                         //      warning.append("> for menu items:\n    ");
00259                         //      warning.append(accelerator->mName);
00260                         //      warning.append("\n    ");
00261                         //      warning.append(mLabel);
00262 
00263                         //      llwarns << warning << llendl;
00264                         //      LLAlertDialog::modalAlert(warning);
00265                                 return FALSE;
00266                         }
00267                 }
00268                 if (!accelerator)
00269                 {                               
00270                         accelerator = new LLKeyBinding;
00271                         if (accelerator)
00272                         {
00273                                 accelerator->mKey = mAcceleratorKey;
00274                                 accelerator->mMask = (mAcceleratorMask & MASK_NORMALKEYS);
00275 //                              accelerator->mName = mLabel;
00276                         }
00277                         listp->push_back(accelerator);//addData(accelerator);
00278                 }
00279         }
00280         return TRUE;
00281 }
00282 
00283 // This function appends the character string representation of
00284 // the current accelerator key and mask to the provided string.
00285 void LLMenuItemGL::appendAcceleratorString( LLString& st )
00286 {
00287         // break early if this is a silly thing to do.
00288         if( KEY_NONE == mAcceleratorKey )
00289         {
00290                 return;
00291         }
00292 
00293         // Append any masks
00294 #ifdef LL_DARWIN
00295         // Standard Mac names for modifier keys in menu equivalents
00296         // We could use the symbol characters, but they only exist in certain fonts.
00297         if( mAcceleratorMask & MASK_CONTROL )
00298         {
00299                 if ( mAcceleratorMask & MASK_MAC_CONTROL )
00300                 {
00301                         st.append( "Ctrl-" );
00302                 }
00303                 else
00304                 {
00305                         st.append( "Cmd-" );            // Symbol would be "\xE2\x8C\x98"
00306                 }
00307         }
00308         if( mAcceleratorMask & MASK_ALT )
00309                 st.append( "Opt-" );            // Symbol would be "\xE2\x8C\xA5"
00310         if( mAcceleratorMask & MASK_SHIFT )
00311                 st.append( "Shift-" );          // Symbol would be "\xE2\x8C\xA7"
00312 #else
00313         if( mAcceleratorMask & MASK_CONTROL )
00314                 st.append( "Ctrl-" );
00315         if( mAcceleratorMask & MASK_ALT )
00316                 st.append( "Alt-" );
00317         if( mAcceleratorMask & MASK_SHIFT )
00318                 st.append( "Shift-" );
00319 #endif
00320 
00321         LLString keystr = LLKeyboard::stringFromKey( mAcceleratorKey );
00322         if ((mAcceleratorMask & MASK_NORMALKEYS) &&
00323                 (keystr[0] == '-' || keystr[0] == '='))
00324         {
00325                 st.append( " " );
00326         }
00327         st.append( keystr );
00328 }
00329 
00330 void LLMenuItemGL::setJumpKey(KEY key)
00331 {
00332         mJumpKey = LLStringOps::toUpper((char)key);
00333 }
00334 
00335 KEY LLMenuItemGL::getJumpKey()
00336 {
00337         return mJumpKey;
00338 }
00339 
00340 
00341 // set the font used by all of the menu objects
00342 void LLMenuItemGL::setFont(LLFontGL* font)
00343 {
00344         mFont = font;
00345 }
00346 
00347 // returns the height in pixels for the current font.
00348 U32 LLMenuItemGL::getNominalHeight( void )
00349 {
00350         return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING;
00351 }
00352 
00353 // functions to control the color scheme
00354 void LLMenuItemGL::setEnabledColor( const LLColor4& color )
00355 {
00356         sEnabledColor = color;
00357 }
00358 
00359 void LLMenuItemGL::setDisabledColor( const LLColor4& color )
00360 {
00361         sDisabledColor = color;
00362 }
00363 
00364 void LLMenuItemGL::setHighlightBGColor( const LLColor4& color )
00365 {
00366         sHighlightBackground = color;
00367 }
00368 
00369 void LLMenuItemGL::setHighlightFGColor( const LLColor4& color )
00370 {
00371         sHighlightForeground = color;
00372 }
00373 
00374 
00375 // change the label
00376 void LLMenuItemGL::setLabel( const LLStringExplicit& label )
00377 {
00378         mLabel = label;
00379 }
00380 
00381 // Get the parent menu for this item
00382 LLMenuGL* LLMenuItemGL::getMenu()
00383 {
00384         return (LLMenuGL*) getParent();
00385 }
00386 
00387 
00388 // getNominalWidth() - returns the normal width of this control in
00389 // pixels - this is used for calculating the widest item, as well as
00390 // for horizontal arrangement.
00391 U32 LLMenuItemGL::getNominalWidth( void )
00392 {
00393         U32 width;
00394         
00395         if (mBriefItem)
00396         {
00397                 width = BRIEF_PAD_PIXELS;
00398         }
00399         else
00400         {
00401                 width = PLAIN_PAD_PIXELS;
00402         }
00403 
00404         if( KEY_NONE != mAcceleratorKey )
00405         {
00406                 width += ACCEL_PAD_PIXELS;
00407                 LLString temp;
00408                 appendAcceleratorString( temp );
00409                 width += mFont->getWidth( temp );
00410         }
00411         width += mFont->getWidth( mLabel.getWString().c_str() );
00412         return width;
00413 }
00414 
00415 // called to rebuild the draw label
00416 void LLMenuItemGL::buildDrawLabel( void )
00417 {
00418         mDrawAccelLabel.clear();
00419         LLString st = mDrawAccelLabel.getString();
00420         appendAcceleratorString( st );
00421         mDrawAccelLabel = st;
00422 }
00423 
00424 void LLMenuItemGL::doIt( void )
00425 {
00426         // close all open menus by default
00427         // if parent menu is actually visible (and we are not triggering menu item via accelerator)
00428         if (!getMenu()->getTornOff() 
00429                 && getMenu()->getVisible())
00430         {
00431                 LLMenuGL::sMenuContainer->hideMenus();
00432         }
00433 }
00434 
00435 // set the hover status (called by it's menu)
00436  void LLMenuItemGL::setHighlight( BOOL highlight )
00437 {
00438         if (highlight)
00439         {
00440                 getMenu()->clearHoverItem();
00441         }
00442         mHighlight = highlight;
00443 }
00444 
00445 // determine if this object represents an active sub-menu
00446 BOOL LLMenuItemGL::isActive( void ) const
00447 {
00448         return FALSE;
00449 }
00450 
00451 // determine if this object represents an open sub-menu
00452 BOOL LLMenuItemGL::isOpen( void ) const
00453 {
00454         return FALSE;
00455 }
00456 
00457 BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
00458 {
00459         if (getHighlight() && 
00460                 getMenu()->isOpen())
00461         {
00462                 if (key == KEY_UP)
00463                 {
00464                         // switch to keyboard navigation mode
00465                         LLMenuGL::setKeyboardMode(TRUE);
00466 
00467                         getMenu()->highlightPrevItem(this);
00468                         return TRUE;
00469                 }
00470                 else if (key == KEY_DOWN)
00471                 {
00472                         // switch to keyboard navigation mode
00473                         LLMenuGL::setKeyboardMode(TRUE);
00474 
00475                         getMenu()->highlightNextItem(this);
00476                         return TRUE;
00477                 }
00478                 else if (key == KEY_RETURN && mask == MASK_NONE)
00479                 {
00480                         // switch to keyboard navigation mode
00481                         LLMenuGL::setKeyboardMode(TRUE);
00482 
00483                         doIt();
00484                         return TRUE;
00485                 }
00486         }
00487 
00488         return FALSE;
00489 }
00490 
00491 BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK )
00492 {
00493         if (mEnabled)
00494         {
00495                 // switch to mouse navigation mode
00496                 LLMenuGL::setKeyboardMode(FALSE);
00497 
00498                 doIt();
00499                 make_ui_sound("UISndClickRelease");
00500                 return TRUE;
00501         }
00502         return FALSE;
00503 }
00504 
00505 BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK )
00506 {
00507         if (mEnabled)
00508         {
00509                 // switch to mouse navigation mode
00510                 LLMenuGL::setKeyboardMode(FALSE);
00511 
00512                 setHighlight(TRUE);
00513                 return TRUE;
00514         }
00515         else
00516         {
00517                 return FALSE;
00518         }
00519 }
00520 
00521 
00522 void LLMenuItemGL::draw( void )
00523 {
00524         // *FIX: This can be optimized by using switches. Want to avoid
00525         // that until the functionality is finalized.
00526 
00527         // HACK: Brief items don't highlight.  Pie menu takes care of it.  JC
00528         // let disabled items be highlighted, just don't draw them as such
00529         if( getEnabled() && getHighlight() && !mBriefItem)
00530         {
00531                 glColor4fv( sHighlightBackground.mV );
00532                 gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0 );
00533         }
00534 
00535         LLColor4 color;
00536 
00537         U8 font_style = mStyle;
00538         if (LLMenuItemGL::sDropShadowText && getEnabled() && !mDrawTextDisabled )
00539         {
00540                 font_style |= LLFontGL::DROP_SHADOW_SOFT;
00541         }
00542 
00543         if ( getEnabled() && getHighlight() )
00544         {
00545                 color = sHighlightForeground;
00546         }
00547         else if( getEnabled() && !mDrawTextDisabled )
00548         {
00549                 color = sEnabledColor;
00550         }
00551         else
00552         {
00553                 color = sDisabledColor;
00554         }
00555 
00556         // Draw the text on top.
00557         if (mBriefItem)
00558         {
00559                 mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color,
00560                                            LLFontGL::LEFT, LLFontGL::BOTTOM, font_style );
00561         }
00562         else
00563         {
00564                 if( !mDrawBoolLabel.empty() )
00565                 {
00566                         mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
00567                                                    LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
00568                 }
00569                 mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
00570                                            LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
00571                 if( !mDrawAccelLabel.empty() )
00572                 {
00573                         mFont->render( mDrawAccelLabel.getWString(), 0, (F32)mRect.mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
00574                                                    LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
00575                 }
00576                 if( !mDrawBranchLabel.empty() )
00577                 {
00578                         mFont->render( mDrawBranchLabel.getWString(), 0, (F32)mRect.mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
00579                                                    LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
00580                 }
00581         }
00582 
00583         // underline "jump" key only when keyboard navigation has been initiated
00584         if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode())
00585         {
00586                 LLString upper_case_label = mLabel.getString();
00587                 LLString::toUpper(upper_case_label);
00588                 std::string::size_type offset = upper_case_label.find(mJumpKey);
00589                 if (offset != std::string::npos)
00590                 {
00591                         S32 x_begin = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset);
00592                         S32 x_end = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset + 1);
00593                         gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1);
00594                 }
00595         }
00596 
00597         // clear got hover every frame
00598         mGotHover = FALSE;
00599 }
00600 
00601 BOOL LLMenuItemGL::setLabelArg( const LLString& key, const LLStringExplicit& text )
00602 {
00603         mLabel.setArg(key, text);
00604         return TRUE;
00605 }
00606 
00607 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00608 // Class LLMenuItemSeparatorGL
00609 //
00610 // This class represents a separator.
00611 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00612 
00613 class LLMenuItemSeparatorGL : public LLMenuItemGL
00614 {
00615 public:
00616         LLMenuItemSeparatorGL( const LLString &name = SEPARATOR_NAME );
00617 
00618         virtual LLString getType() const        { return "separator"; }
00619 
00620         virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_MENU_ITEM_SEPARATOR; }
00621         virtual LLString getWidgetTag() const { return LL_MENU_ITEM_SEPARATOR_GL_TAG; }
00622 
00623         // doIt() - do the primary funcationality of the menu item.
00624         virtual void doIt( void ) {}
00625 
00626         virtual void draw( void );
00627         virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
00628         virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
00629         virtual BOOL handleHover(S32 x, S32 y, MASK mask);
00630 
00631         virtual U32 getNominalHeight( void ) { return SEPARATOR_HEIGHT_PIXELS; }
00632 };
00633 
00634 LLMenuItemSeparatorGL::LLMenuItemSeparatorGL( const LLString &name ) :
00635         LLMenuItemGL( SEPARATOR_NAME, SEPARATOR_LABEL )
00636 {
00637 }
00638 
00639 void LLMenuItemSeparatorGL::draw( void )
00640 {
00641         glColor4fv( sDisabledColor.mV );
00642         const S32 y = mRect.getHeight() / 2;
00643         const S32 PAD = 6;
00644         gl_line_2d( PAD, y, mRect.getWidth() - PAD, y );
00645 }
00646 
00647 BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
00648 {
00649         LLMenuGL* parent_menu = getMenu();
00650         if (y > mRect.getHeight() / 2)
00651         {
00652                 return parent_menu->handleMouseDown(x + mRect.mLeft, mRect.mTop + 1, mask);
00653         }
00654         else
00655         {
00656                 return parent_menu->handleMouseDown(x + mRect.mLeft, mRect.mBottom - 1, mask);
00657         }
00658 }
00659 
00660 BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask) 
00661 {
00662         LLMenuGL* parent_menu = getMenu();
00663         if (y > mRect.getHeight() / 2)
00664         {
00665                 return parent_menu->handleMouseUp(x + mRect.mLeft, mRect.mTop + 1, mask);
00666         }
00667         else
00668         {
00669                 return parent_menu->handleMouseUp(x + mRect.mLeft, mRect.mBottom - 1, mask);
00670         }
00671 }
00672 
00673 BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) 
00674 {
00675         LLMenuGL* parent_menu = getMenu();
00676         if (y > mRect.getHeight() / 2)
00677         {
00678                 parent_menu->highlightPrevItem(this, FALSE);
00679                 return FALSE;
00680         }
00681         else
00682         {
00683                 parent_menu->highlightNextItem(this, FALSE);
00684                 return FALSE;
00685         }
00686 }
00687 
00688 
00689 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00690 // Class LLMenuItemVerticalSeparatorGL
00691 //
00692 // This class represents a vertical separator.
00693 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00694 
00695 class LLMenuItemVerticalSeparatorGL
00696 :       public LLMenuItemSeparatorGL
00697 {
00698 public:
00699         LLMenuItemVerticalSeparatorGL( void );
00700 
00701         virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_MENU_SEPARATOR_VERTICAL; }
00702         virtual LLString getWidgetTag() const { return LL_MENU_ITEM_VERTICAL_SEPARATOR_GL_TAG; }
00703 
00704         virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }
00705 };
00706 
00707 LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void )
00708 {
00709         setLabel( VERTICAL_SEPARATOR_LABEL );
00710 }
00711 
00712 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00713 // Class LLMenuItemTearOffGL
00714 //
00715 // This class represents a separator.
00716 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00717 LLMenuItemTearOffGL::LLMenuItemTearOffGL(LLViewHandle parent_floater_handle) : 
00718         LLMenuItemGL("tear off", TEAROFF_SEPARATOR_LABEL), 
00719         mParentHandle(parent_floater_handle)
00720 {
00721 }
00722 
00723 EWidgetType LLMenuItemTearOffGL::getWidgetType() const
00724 {
00725         return WIDGET_TYPE_TEAROFF_MENU;
00726 }
00727 
00728 LLString LLMenuItemTearOffGL::getWidgetTag() const
00729 {
00730         return LL_MENU_ITEM_TEAR_OFF_GL_TAG;
00731 }
00732 
00733 void LLMenuItemTearOffGL::doIt()
00734 {
00735         if (getMenu()->getTornOff())
00736         {
00737                 LLTearOffMenu* torn_off_menu = (LLTearOffMenu*)(getMenu()->getParent());
00738                 torn_off_menu->close();
00739         }
00740         else
00741         {
00742                 // transfer keyboard focus and highlight to first real item in list
00743                 if (getHighlight())
00744                 {
00745                         getMenu()->highlightNextItem(this);
00746                 }
00747 
00748                 getMenu()->arrange();
00749 
00750                 LLFloater* parent_floater = LLFloater::getFloaterByHandle(mParentHandle);
00751                 LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu());
00752 
00753                 if (tear_off_menu)
00754                 {
00755                         if (parent_floater)
00756                         {
00757                                 parent_floater->addDependentFloater(tear_off_menu, FALSE);
00758                         }
00759 
00760                         // give focus to torn off menu because it will have
00761                         // been taken away when parent menu closes
00762                         tear_off_menu->setFocus(TRUE);
00763                 }
00764         }
00765         LLMenuItemGL::doIt();
00766 }
00767 
00768 void LLMenuItemTearOffGL::draw()
00769 {
00770         // disabled items can be highlighted, but shouldn't render as such
00771         if( getEnabled() && getHighlight() && !mBriefItem)
00772         {
00773                 glColor4fv( sHighlightBackground.mV );
00774                 gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0 );
00775         }
00776 
00777         if (mEnabled)
00778         {
00779                 glColor4fv( sEnabledColor.mV );
00780         }
00781         else
00782         {
00783                 glColor4fv( sDisabledColor.mV );
00784         }
00785         const S32 y = mRect.getHeight() / 3;
00786         const S32 PAD = 6;
00787         gl_line_2d( PAD, y, mRect.getWidth() - PAD, y );
00788         gl_line_2d( PAD, y * 2, mRect.getWidth() - PAD, y * 2 );
00789 }
00790 
00791 U32 LLMenuItemTearOffGL::getNominalHeight( void ) { return TEAROFF_SEPARATOR_HEIGHT_PIXELS; }
00792 
00793 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00794 // Class LLMenuItemBlankGL
00795 //
00796 // This class represents a blank, non-functioning item.
00797 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00798 
00799 class LLMenuItemBlankGL : public LLMenuItemGL
00800 {
00801 public:
00802         LLMenuItemBlankGL( void );
00803 
00804         virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_MENU_ITEM_BLANK; }
00805         virtual LLString getWidgetTag() const { return LL_MENU_ITEM_BLANK_GL_TAG; }
00806 
00807         // doIt() - do the primary funcationality of the menu item.
00808         virtual void doIt( void ) {}
00809 
00810         virtual void draw( void ) {}
00811 };
00812 
00813 LLMenuItemBlankGL::LLMenuItemBlankGL( void )
00814 :       LLMenuItemGL( "", "" )
00815 {
00816         mEnabled = FALSE;
00817 }
00818 
00822 
00823 LLMenuItemCallGL::LLMenuItemCallGL( const LLString& name, 
00824                                                                         const LLString& label, 
00825                                                                         menu_callback clicked_cb, 
00826                                                                     enabled_callback enabled_cb,
00827                                                                         void* user_data,
00828                                                                         KEY key, MASK mask,
00829                                                                         BOOL enabled,
00830                                                                         on_disabled_callback on_disabled_cb) :
00831         LLMenuItemGL( name, label, key, mask ),
00832         mCallback( clicked_cb ),
00833         mEnabledCallback( enabled_cb ),
00834         mLabelCallback(NULL),
00835         mUserData( user_data ),
00836         mOnDisabledCallback(on_disabled_cb)
00837 {
00838         if(!enabled) setEnabled(FALSE);
00839 }
00840 
00841 LLMenuItemCallGL::LLMenuItemCallGL( const LLString& name, 
00842                                                                         menu_callback clicked_cb, 
00843                                                                     enabled_callback enabled_cb,
00844                                                                         void* user_data,
00845                                                                         KEY key, MASK mask,
00846                                                                         BOOL enabled,
00847                                                                         on_disabled_callback on_disabled_cb) :
00848         LLMenuItemGL( name, name, key, mask ),
00849         mCallback( clicked_cb ),
00850         mEnabledCallback( enabled_cb ),
00851         mLabelCallback(NULL),
00852         mUserData( user_data ),
00853         mOnDisabledCallback(on_disabled_cb)
00854 {
00855         if(!enabled) setEnabled(FALSE);
00856 }
00857 
00858 LLMenuItemCallGL::LLMenuItemCallGL(const LLString& name,
00859                                                                    const LLString& label,
00860                                                                    menu_callback clicked_cb,
00861                                                                    enabled_callback enabled_cb,
00862                                                                    label_callback label_cb,
00863                                                                    void* user_data,
00864                                                                    KEY key, MASK mask,
00865                                                                    BOOL enabled,
00866                                                                    on_disabled_callback on_disabled_cb) :
00867         LLMenuItemGL(name, label, key, mask),
00868         mCallback(clicked_cb),
00869         mEnabledCallback(enabled_cb),
00870         mLabelCallback(label_cb),
00871         mUserData(user_data),
00872         mOnDisabledCallback(on_disabled_cb)
00873 {
00874         if(!enabled) setEnabled(FALSE);
00875 }
00876 
00877 LLMenuItemCallGL::LLMenuItemCallGL(const LLString& name,
00878                                                                    menu_callback clicked_cb,
00879                                                                    enabled_callback enabled_cb,
00880                                                                    label_callback label_cb,
00881                                                                    void* user_data,
00882                                                                    KEY key, MASK mask,
00883                                                                    BOOL enabled,
00884                                                                    on_disabled_callback on_disabled_cb) :
00885         LLMenuItemGL(name, name, key, mask),
00886         mCallback(clicked_cb),
00887         mEnabledCallback(enabled_cb),
00888         mLabelCallback(label_cb),
00889         mUserData(user_data),
00890         mOnDisabledCallback(on_disabled_cb)
00891 {
00892         if(!enabled) setEnabled(FALSE);
00893 }
00894 
00895 void LLMenuItemCallGL::setEnabledControl(LLString enabled_control, LLView *context)
00896 {
00897         // Register new listener
00898         if (!enabled_control.empty())
00899         {
00900                 LLControlBase *control = context->findControl(enabled_control);
00901                 if (control)
00902                 {
00903                         LLSD state = control->registerListener(this, "ENABLED");
00904                         setEnabled(state);
00905                 }
00906                 else
00907                 {
00908                         context->addBoolControl(enabled_control, mEnabled);
00909                         control = context->findControl(enabled_control);
00910                         control->registerListener(this, "ENABLED");
00911                 }
00912         }
00913 }
00914 
00915 void LLMenuItemCallGL::setVisibleControl(LLString enabled_control, LLView *context)
00916 {
00917         // Register new listener
00918         if (!enabled_control.empty())
00919         {
00920                 LLControlBase *control = context->findControl(enabled_control);
00921                 if (control)
00922                 {
00923                         LLSD state = control->registerListener(this, "VISIBLE");
00924                         setVisible(state);
00925                 }
00926                 else
00927                 {
00928                         context->addBoolControl(enabled_control, mEnabled);
00929                         control = context->findControl(enabled_control);
00930                         control->registerListener(this, "VISIBLE");
00931                 }
00932         }
00933 }
00934 
00935 // virtual
00936 bool LLMenuItemCallGL::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00937 {
00938         if (userdata.asString() == "ENABLED" && event->desc() == "value_changed")
00939         {
00940                 LLSD state = event->getValue();
00941                 setEnabled(state);
00942                 return TRUE;
00943         }
00944         if (userdata.asString() == "VISIBLE" && event->desc() == "value_changed")
00945         {
00946                 LLSD state = event->getValue();
00947                 setVisible(state);
00948                 return TRUE;
00949         }
00950         return LLMenuItemGL::handleEvent(event, userdata);
00951 }
00952 
00953 // virtual
00954 LLXMLNodePtr LLMenuItemCallGL::getXML(bool save_children) const
00955 {
00956         LLXMLNodePtr node = LLMenuItemGL::getXML();
00957 
00958         // Contents
00959 
00960         std::vector<LLListenerEntry> listeners = mDispatcher->getListeners();
00961         std::vector<LLListenerEntry>::iterator itor;
00962         for (itor = listeners.begin(); itor != listeners.end(); ++itor)
00963         {
00964                 LLString listener_name = findEventListener((LLSimpleListener*)itor->listener);
00965                 if (!listener_name.empty())
00966                 {
00967                         LLXMLNodePtr child_node = node->createChild("on_click", FALSE);
00968                         child_node->createChild("function", TRUE)->setStringValue(listener_name);
00969                         child_node->createChild("filter", TRUE)->setStringValue(itor->filter.asString());
00970                         child_node->createChild("userdata", TRUE)->setStringValue(itor->userdata.asString());
00971                 }
00972         }
00973 
00974         return node;
00975 }
00976 
00977 // doIt() - Call the callback provided
00978 void LLMenuItemCallGL::doIt( void )
00979 {
00980         // RN: menu item can be deleted in callback, so beware
00981         getMenu()->setItemLastSelected( this );
00982 
00983         if( mCallback )
00984         {
00985                 mCallback( mUserData );
00986         }
00987         LLPointer<LLEvent> fired_event = new LLEvent(this);
00988         fireEvent(fired_event, "on_click");
00989         LLMenuItemGL::doIt();
00990 }
00991 
00992 EWidgetType LLMenuItemCallGL::getWidgetType() const 
00993 {
00994         return WIDGET_TYPE_MENU_ITEM_CALL;
00995 }
00996 
00997 LLString LLMenuItemCallGL::getWidgetTag() const
00998 {
00999         return LL_MENU_ITEM_CALL_GL_TAG;
01000 }
01001 
01002 void LLMenuItemCallGL::buildDrawLabel( void )
01003 {
01004         LLPointer<LLEvent> fired_event = new LLEvent(this);
01005         fireEvent(fired_event, "on_build");
01006         if( mEnabledCallback )
01007         {
01008                 setEnabled( mEnabledCallback( mUserData ) );
01009         }
01010         if(mLabelCallback)
01011         {
01012                 LLString label;
01013                 mLabelCallback(label, mUserData);
01014                 mLabel = label;
01015         }
01016         LLMenuItemGL::buildDrawLabel();
01017 }
01018 
01019 BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask )
01020 {
01021         if( (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
01022         {
01023                 LLPointer<LLEvent> fired_event = new LLEvent(this);
01024                 fireEvent(fired_event, "on_build");
01025                 if( mEnabledCallback )
01026                 {
01027                         setEnabled( mEnabledCallback( mUserData ) );
01028                 }
01029                 if( !mEnabled )
01030                 {
01031                         if( mOnDisabledCallback )
01032                         {
01033                                 mOnDisabledCallback( mUserData );
01034                         }
01035                 }
01036         }
01037         return LLMenuItemGL::handleAcceleratorKey(key, mask);
01038 }
01039 
01043 
01044 LLMenuItemCheckGL::LLMenuItemCheckGL ( const LLString& name, 
01045                                                                            const LLString& label,
01046                                                                            menu_callback clicked_cb,
01047                                                                            enabled_callback enabled_cb,
01048                                                                            check_callback check_cb,
01049                                                                            void* user_data,
01050                                                                            KEY key, MASK mask ) :
01051         LLMenuItemCallGL( name, label, clicked_cb, enabled_cb, user_data, key, mask ),
01052         mCheckCallback( check_cb ), 
01053         mChecked(FALSE)
01054 {
01055 }
01056 
01057 LLMenuItemCheckGL::LLMenuItemCheckGL ( const LLString& name, 
01058                                                                            menu_callback clicked_cb,
01059                                                                            enabled_callback enabled_cb,
01060                                                                            check_callback check_cb,
01061                                                                            void* user_data,
01062                                                                            KEY key, MASK mask ) :
01063         LLMenuItemCallGL( name, name, clicked_cb, enabled_cb, user_data, key, mask ),
01064         mCheckCallback( check_cb ), 
01065         mChecked(FALSE)
01066 {
01067 }
01068 
01069 LLMenuItemCheckGL::LLMenuItemCheckGL ( const LLString& name, 
01070                                                                            const LLString& label,
01071                                                                            menu_callback clicked_cb,
01072                                                                            enabled_callback enabled_cb,
01073                                                                            LLString control_name,
01074                                                                            LLView *context,
01075                                                                            void* user_data,
01076                                                                            KEY key, MASK mask ) :
01077         LLMenuItemCallGL( name, label, clicked_cb, enabled_cb, user_data, key, mask ),
01078         mCheckCallback( NULL )
01079 {
01080         setControlName(control_name, context);
01081 }
01082 
01083 void LLMenuItemCheckGL::setCheckedControl(LLString checked_control, LLView *context)
01084 {
01085         // Register new listener
01086         if (!checked_control.empty())
01087         {
01088                 LLControlBase *control = context->findControl(checked_control);
01089                 if (control)
01090                 {
01091                         LLSD state = control->registerListener(this, "CHECKED");
01092                         mChecked = state;
01093                 }
01094                 else
01095                 {
01096                         context->addBoolControl(checked_control, mChecked);
01097                         control = context->findControl(checked_control);
01098                         control->registerListener(this, "CHECKED");
01099                 }
01100         }
01101 }
01102 
01103 // virtual
01104 bool LLMenuItemCheckGL::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
01105 {
01106         if (userdata.asString() == "CHECKED" && event->desc() == "value_changed")
01107         {
01108                 LLSD state = event->getValue();
01109                 mChecked = state;
01110                 if(mChecked)
01111                 {
01112                         mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
01113                 }
01114                 else
01115                 {
01116                         mDrawBoolLabel.clear();
01117                 }
01118                 return TRUE;
01119         }
01120         return LLMenuItemCallGL::handleEvent(event, userdata);
01121 }
01122 
01123 // virtual
01124 LLXMLNodePtr LLMenuItemCheckGL::getXML(bool save_children) const
01125 {
01126         LLXMLNodePtr node = LLMenuItemCallGL::getXML();
01127         return node;
01128 }
01129 
01130 EWidgetType LLMenuItemCheckGL::getWidgetType() const 
01131 { 
01132         return WIDGET_TYPE_MENU_ITEM_CHECK;
01133 }
01134 
01135 LLString LLMenuItemCheckGL::getWidgetTag() const
01136 {
01137         return LL_MENU_ITEM_CHECK_GL_TAG;
01138 }
01139 
01140 // called to rebuild the draw label
01141 void LLMenuItemCheckGL::buildDrawLabel( void )
01142 {
01143         if(mChecked || (mCheckCallback && mCheckCallback( mUserData ) ) )
01144         {
01145                 mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
01146         }
01147         else
01148         {
01149                 mDrawBoolLabel.clear();
01150         }
01151         LLMenuItemCallGL::buildDrawLabel();
01152 }
01153 
01154 
01158 
01159 LLMenuItemToggleGL::LLMenuItemToggleGL( const LLString& name, const LLString& label, BOOL* toggle,
01160                                                                                 KEY key, MASK mask ) :
01161         LLMenuItemGL( name, label, key, mask ),
01162         mToggle( toggle )
01163 {
01164 }
01165 
01166 LLMenuItemToggleGL::LLMenuItemToggleGL( const LLString& name, BOOL* toggle,
01167                                                                                 KEY key, MASK mask ) :
01168         LLMenuItemGL( name, name, key, mask ),
01169         mToggle( toggle )
01170 {
01171 }
01172 
01173 
01174 // called to rebuild the draw label
01175 void LLMenuItemToggleGL::buildDrawLabel( void )
01176 {
01177         if( *mToggle )
01178         {
01179                 mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
01180         }
01181         else
01182         {
01183                 mDrawBoolLabel.clear();
01184         }
01185         mDrawAccelLabel.clear();
01186         LLString st = mDrawAccelLabel;
01187         appendAcceleratorString( st );
01188         mDrawAccelLabel = st;
01189 }
01190 
01191 // doIt() - do the primary funcationality of the menu item.
01192 void LLMenuItemToggleGL::doIt( void )
01193 {
01194         getMenu()->setItemLastSelected( this );
01195         //llinfos << "LLMenuItemToggleGL::doIt " << mLabel.c_str() << llendl;
01196         *mToggle = !(*mToggle);
01197         buildDrawLabel();
01198         LLMenuItemGL::doIt();
01199 }
01200 
01201 
01202 LLMenuItemBranchGL::LLMenuItemBranchGL( const LLString& name, const LLString& label, LLMenuGL* branch,
01203                                                                                 KEY key, MASK mask ) :
01204         LLMenuItemGL( name, label, key, mask ),
01205         mBranch( branch )
01206 {
01207         mBranch->setVisible( FALSE );
01208         mBranch->setParentMenuItem(this);
01209 }
01210 
01211 // virtual
01212 LLView* LLMenuItemBranchGL::getChildByName(const LLString& name, BOOL recurse) const
01213 {
01214         if (mBranch->getName() == name)
01215         {
01216                 return mBranch;
01217         }
01218         // Always recurse on branches
01219         return mBranch->getChildByName(name, recurse);
01220 }
01221 
01222 EWidgetType LLMenuItemBranchGL::getWidgetType() const
01223 {
01224         return WIDGET_TYPE_MENU_ITEM_BRANCH;
01225 }
01226 
01227 LLString LLMenuItemBranchGL::getWidgetTag() const
01228 {
01229         return LL_MENU_ITEM_BRANCH_GL_TAG;
01230 }
01231 
01232 // virtual
01233 BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
01234 {
01235         if (mEnabled)
01236         {
01237                 // switch to mouse navigation mode
01238                 LLMenuGL::setKeyboardMode(FALSE);
01239 
01240                 doIt();
01241                 make_ui_sound("UISndClickRelease");
01242                 return TRUE;
01243         }
01244         return FALSE;
01245 }
01246 
01247 BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
01248 {
01249         return mBranch->handleAcceleratorKey(key, mask);
01250 }
01251 
01252 // virtual
01253 LLXMLNodePtr LLMenuItemBranchGL::getXML(bool save_children) const
01254 {
01255         if (mBranch)
01256         {
01257                 return mBranch->getXML();
01258         }
01259 
01260         return LLMenuItemGL::getXML();
01261 }
01262 
01263 
01264 // This function checks to see if the accelerator key is already in use;
01265 // if not, it will be added to the list
01266 BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp)
01267 {
01268         U32 item_count = mBranch->getItemCount();
01269         LLMenuItemGL *item;
01270 
01271         while (item_count--)
01272         {
01273                 if ((item = mBranch->getItem(item_count)))
01274                 {
01275                         return item->addToAcceleratorList(listp);
01276                 }
01277         }
01278         return FALSE;
01279 }
01280 
01281 
01282 // called to rebuild the draw label
01283 void LLMenuItemBranchGL::buildDrawLabel( void )
01284 {
01285         mDrawAccelLabel.clear();
01286         LLString st = mDrawAccelLabel;
01287         appendAcceleratorString( st );
01288         mDrawAccelLabel = st;
01289         mDrawBranchLabel = BRANCH_SUFFIX;
01290 }
01291 
01292 // doIt() - do the primary functionality of the menu item.
01293 void LLMenuItemBranchGL::doIt( void )
01294 {
01295         openMenu();
01296 
01297         // keyboard navigation automatically propagates highlight to sub-menu
01298         // to facilitate fast menu control via jump keys
01299         if (LLMenuGL::getKeyboardMode() && !mBranch->getHighlightedItem())
01300         {
01301                 mBranch->highlightNextItem(NULL);
01302         }
01303 }
01304 
01305 BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
01306 {
01307         BOOL handled = FALSE;
01308         if (called_from_parent)
01309         {
01310                 handled = mBranch->handleKey(key, mask, called_from_parent);
01311         }
01312 
01313         if (!handled)
01314         {
01315                 handled = LLMenuItemGL::handleKey(key, mask, called_from_parent);
01316         }
01317 
01318         return handled;
01319 }
01320 
01321 BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
01322 {
01323         BOOL handled = FALSE;
01324         if (called_from_parent)
01325         {
01326                 handled = mBranch->handleUnicodeChar(uni_char, TRUE);
01327         }
01328 
01329         if (!handled)
01330         {
01331                 handled = LLMenuItemGL::handleUnicodeChar(uni_char, called_from_parent);
01332         }
01333 
01334         return handled;
01335 }
01336 
01337 
01338 // set the hover status (called by it's menu)
01339 void LLMenuItemBranchGL::setHighlight( BOOL highlight )
01340 {
01341         if (highlight == getHighlight()) return;
01342 
01343         // make sure only yourself is highlighted
01344         if (highlight)
01345         {
01346                 getMenu()->clearHoverItem();
01347         }
01348 
01349         BOOL auto_open = mEnabled && (!mBranch->getVisible() || mBranch->getTornOff());
01350         // torn off menus don't open sub menus on hover unless they have focus
01351         if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus())
01352         {
01353                 auto_open = FALSE;
01354         }
01355         // don't auto open torn off sub-menus (need to explicitly active menu item to give them focus)
01356         if (mBranch->getTornOff())
01357         {
01358                 auto_open = FALSE;
01359         }
01360 
01361         mHighlight = highlight;
01362         if( highlight )
01363         {
01364                 if(auto_open)
01365                 {
01366                         openMenu();
01367                 }
01368         }
01369         else
01370         {
01371                 if (mBranch->getTornOff())
01372                 {
01373                         ((LLFloater*)mBranch->getParent())->setFocus(FALSE);
01374                         mBranch->clearHoverItem();
01375                 }
01376                 else
01377                 {
01378                         mBranch->setVisible( FALSE );
01379                 }
01380         }
01381 }
01382 
01383 void LLMenuItemBranchGL::setEnabledSubMenus(BOOL enabled)
01384 {
01385         mBranch->setEnabledSubMenus(enabled);
01386 }
01387 
01388 void LLMenuItemBranchGL::draw()
01389 {
01390         LLMenuItemGL::draw();
01391         if (mBranch->getVisible() && !mBranch->getTornOff())
01392         {
01393                 setHighlight(TRUE);
01394         }
01395 }
01396 
01397 // determine if this object is active
01398 // which, for branching menus, means the branch is open and has "focus"
01399 BOOL LLMenuItemBranchGL::isActive( void ) const
01400 {
01401         return isOpen() && mBranch->getHighlightedItem();
01402 }
01403 
01404 BOOL LLMenuItemBranchGL::isOpen( void ) const
01405 {
01406         return mBranch->isOpen();
01407 }
01408 
01409 void LLMenuItemBranchGL::updateBranchParent(LLView* parentp)
01410 {
01411         if (mBranch->getParent() == NULL)
01412         {
01413                 // make the branch menu a sibling of my parent menu
01414                 mBranch->updateParent(parentp);
01415         }
01416 }
01417 
01418 void LLMenuItemBranchGL::onVisibilityChange( BOOL new_visibility )
01419 {
01420         if (new_visibility == FALSE && !mBranch->getTornOff())
01421         {
01422                 mBranch->setVisible(FALSE);
01423         }
01424         LLMenuItemGL::onVisibilityChange(new_visibility);
01425 }
01426 
01427 BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
01428 {
01429         if (getMenu()->getVisible() && mBranch->getVisible() && key == KEY_LEFT)
01430         {
01431                 // switch to keyboard navigation mode
01432                 LLMenuGL::setKeyboardMode(TRUE);
01433 
01434                 BOOL handled = mBranch->clearHoverItem();
01435                 if (mBranch->getTornOff())
01436                 {
01437                         ((LLFloater*)mBranch->getParent())->setFocus(FALSE);
01438                 }
01439                 if (handled && getMenu()->getTornOff())
01440                 {
01441                         ((LLFloater*)getMenu()->getParent())->setFocus(TRUE);
01442                 }
01443                 return handled;
01444         }
01445 
01446         if (getEnabled() &&
01447                 getHighlight() && 
01448                 getMenu()->isOpen() && 
01449                 key == KEY_RIGHT && !mBranch->getHighlightedItem())
01450         {
01451                 // switch to keyboard navigation mode
01452                 LLMenuGL::setKeyboardMode(TRUE);
01453 
01454                 LLMenuItemGL* itemp = mBranch->highlightNextItem(NULL);
01455                 if (itemp)
01456                 {
01457                         return TRUE;
01458                 }
01459         }
01460 
01461         return LLMenuItemGL::handleKeyHere(key, mask, called_from_parent);
01462 }
01463 
01464 void LLMenuItemBranchGL::openMenu()
01465 {
01466         if (mBranch->getTornOff())
01467         {
01468                 gFloaterView->bringToFront((LLFloater*)mBranch->getParent());
01469                 // this might not be necessary, as torn off branches don't get focus and hence no highligth
01470                 mBranch->highlightNextItem(NULL);
01471         }
01472         else if( !mBranch->getVisible() )
01473         {
01474                 // get valid rectangle for menus
01475                 const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
01476 
01477                 mBranch->arrange();
01478 
01479                 LLRect rect = mBranch->getRect();
01480                 // calculate root-view relative position for branch menu
01481                 S32 left = mRect.mRight;
01482                 S32 top = mRect.mTop - mRect.mBottom;
01483 
01484                 localPointToOtherView(left, top, &left, &top, mBranch->getParent());
01485 
01486                 rect.setLeftTopAndSize( left, top,
01487                                                                 rect.getWidth(), rect.getHeight() );
01488 
01489                 if (mBranch->getCanTearOff())
01490                 {
01491                         rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
01492                 }
01493                 mBranch->setRect( rect );
01494                 S32 x = 0;
01495                 S32 y = 0;
01496                 mBranch->localPointToOtherView( 0, 0, &x, &y, mBranch->getParent() ); 
01497                 S32 delta_x = 0;
01498                 S32 delta_y = 0;
01499                 if( y < menu_region_rect.mBottom )
01500                 {
01501                         delta_y = menu_region_rect.mBottom - y;
01502                 }
01503 
01504                 S32 menu_region_width = menu_region_rect.getWidth();
01505                 if( x - menu_region_rect.mLeft > menu_region_width - rect.getWidth() )
01506                 {
01507                         // move sub-menu over to left side
01508                         delta_x = llmax(-x, (-1 * (rect.getWidth() + mRect.getWidth())));
01509                 }
01510                 mBranch->translate( delta_x, delta_y );
01511                 mBranch->setVisible( TRUE );
01512         }
01513 }
01514 
01515 
01516 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01517 // Class LLMenuItemBranchDownGL
01518 //
01519 // The LLMenuItemBranchDownGL represents a menu item that has a
01520 // sub-menu. This is used to make menu bar menus.
01521 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01522 
01523 class LLMenuItemBranchDownGL : public LLMenuItemBranchGL
01524 {
01525 protected:
01526 
01527 public:
01528         LLMenuItemBranchDownGL( const LLString& name, const LLString& label, LLMenuGL* branch,
01529                                                         KEY key = KEY_NONE, MASK mask = MASK_NONE );
01530 
01531         virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_MENU_ITEM_BRANCH_DOWN; }
01532         virtual LLString getWidgetTag() const { return LL_MENU_ITEM_BRANCH_DOWN_GL_TAG; }
01533 
01534         virtual LLString getType() const        { return "menu"; }
01535 
01536         // returns the normal width of this control in pixels - this is
01537         // used for calculating the widest item, as well as for horizontal
01538         // arrangement.
01539         virtual U32 getNominalWidth( void );
01540 
01541         // called to rebuild the draw label
01542         virtual void buildDrawLabel( void );
01543 
01544         // handles opening, positioning, and arranging the menu branch associated with this item
01545         virtual void openMenu( void );
01546 
01547         // set the hover status (called by it's menu) and if the object is
01548         // active. This is used for behavior transfer.
01549         virtual void setHighlight( BOOL highlight );
01550 
01551         virtual BOOL isActive( void ) const;
01552 
01553         // LLView functionality
01554         virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
01555         virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); 
01556         virtual void draw( void );
01557         virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
01558         
01559         virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
01560 };
01561 
01562 LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const LLString& name,
01563                                                                                                 const LLString& label,
01564                                                                                                 LLMenuGL* branch, 
01565                                                                                                 KEY key, MASK mask ) :
01566         LLMenuItemBranchGL( name, label, branch, key, mask )
01567 {
01568 }
01569 
01570 // returns the normal width of this control in pixels - this is used
01571 // for calculating the widest item, as well as for horizontal
01572 // arrangement.
01573 U32 LLMenuItemBranchDownGL::getNominalWidth( void )
01574 {
01575         U32 width = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS + RIGHT_PAD_PIXELS;
01576         width += mFont->getWidth( mLabel.getWString().c_str() ); 
01577         return width;
01578 }
01579 
01580 // called to rebuild the draw label
01581 void LLMenuItemBranchDownGL::buildDrawLabel( void )
01582 {
01583         mDrawAccelLabel.clear();
01584         LLString st = mDrawAccelLabel;
01585         appendAcceleratorString( st );
01586         mDrawAccelLabel = st;
01587 }
01588 
01589 void LLMenuItemBranchDownGL::openMenu( void )
01590 {
01591         if( mBranch->getVisible() && !mBranch->getTornOff() )
01592         {
01593                 mBranch->setVisible( FALSE );
01594         }
01595         else
01596         {
01597                 if (mBranch->getTornOff())
01598                 {
01599                         gFloaterView->bringToFront((LLFloater*)mBranch->getParent());
01600                 }
01601                 else
01602                 {
01603                         // We're showing the drop-down menu, so patch up its labels/rects
01604                         mBranch->arrange();
01605 
01606                         LLRect rect = mBranch->getRect();
01607                         S32 left = 0;
01608                         S32 top = mRect.mBottom;
01609                         localPointToOtherView(left, top, &left, &top, mBranch->getParent());
01610 
01611                         rect.setLeftTopAndSize( left, top,
01612                                                                         rect.getWidth(), rect.getHeight() );
01613                         mBranch->setRect( rect );
01614                         S32 x = 0;
01615                         S32 y = 0;
01616                         mBranch->localPointToScreen( 0, 0, &x, &y ); 
01617                         S32 delta_x = 0;
01618 
01619                         LLCoordScreen window_size;
01620                         LLWindow* windowp = getWindow();
01621                         windowp->getSize(&window_size);
01622 
01623                         S32 window_width = window_size.mX;
01624                         if( x > window_width - rect.getWidth() )
01625                         {
01626                                 delta_x = (window_width - rect.getWidth()) - x;
01627                         }
01628                         mBranch->translate( delta_x, 0 );
01629 
01630                         setHighlight(TRUE);
01631                         mBranch->setVisible( TRUE );
01632                 }
01633 
01634 
01635         }
01636 }
01637 
01638 // set the hover status (called by it's menu)
01639 void LLMenuItemBranchDownGL::setHighlight( BOOL highlight )
01640 {
01641         if (highlight == getHighlight()) return;
01642 
01643         if (highlight)
01644         {
01645                 getMenu()->clearHoverItem();
01646         }
01647         mHighlight = highlight;
01648         if( !highlight)
01649         {
01650                 if (mBranch->getTornOff())
01651                 {
01652                         ((LLFloater*)mBranch->getParent())->setFocus(FALSE);
01653                         mBranch->clearHoverItem();
01654                 }
01655                 else
01656                 {
01657                         mBranch->setVisible( FALSE );
01658                 }
01659         }
01660 }
01661 
01662 BOOL LLMenuItemBranchDownGL::isActive() const
01663 {
01664         // for top level menus, being open is sufficient to be considered 
01665         // active, because clicking on them with the mouse will open
01666         // them, without moving keyboard focus to them
01667         return isOpen();
01668 }
01669 
01670 BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
01671 {
01672         // switch to mouse control mode
01673         LLMenuGL::setKeyboardMode(FALSE);
01674         doIt();
01675         make_ui_sound("UISndClick");
01676         return TRUE;
01677 }
01678 
01679 BOOL LLMenuItemBranchDownGL::handleMouseUp( S32 x, S32 y, MASK mask )
01680 {
01681         return TRUE;
01682 }
01683 
01684 
01685 BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask)
01686 {
01687         BOOL branch_visible = mBranch->getVisible();
01688         BOOL handled = mBranch->handleAcceleratorKey(key, mask);
01689         if (handled && !branch_visible && getVisible())
01690         {
01691                 // flash this menu entry because we triggered an invisible menu item
01692                 LLMenuHolderGL::setActivatedItem(this);
01693         }
01694 
01695         return handled;
01696 }
01697 
01698 BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
01699 {
01700         BOOL menu_open = mBranch->getVisible();
01701         // don't do keyboard navigation of top-level menus unless in keyboard mode, or menu expanded
01702         if (getHighlight() && getMenu()->getVisible() && (isActive() || LLMenuGL::getKeyboardMode()))
01703         {
01704                 if (key == KEY_LEFT)
01705                 {
01706                         // switch to keyboard navigation mode
01707                         LLMenuGL::setKeyboardMode(TRUE);
01708 
01709                         LLMenuItemGL* itemp = getMenu()->highlightPrevItem(this);
01710                         // open new menu only if previous menu was open
01711                         if (itemp && itemp->getEnabled() && menu_open)
01712                         {
01713                                 itemp->doIt();
01714                         }
01715 
01716                         return TRUE;
01717                 }
01718                 else if (key == KEY_RIGHT)
01719                 {
01720                         // switch to keyboard navigation mode
01721                         LLMenuGL::setKeyboardMode(TRUE);
01722 
01723                         LLMenuItemGL* itemp = getMenu()->highlightNextItem(this);
01724                         // open new menu only if previous menu was open
01725                         if (itemp && itemp->getEnabled() && menu_open)
01726                         {
01727                                 itemp->doIt();
01728                         }
01729 
01730                         return TRUE;
01731                 }
01732                 else if (key == KEY_DOWN)
01733                 {
01734                         // switch to keyboard navigation mode
01735                         LLMenuGL::setKeyboardMode(TRUE);
01736 
01737                         if (getEnabled() && !isActive())
01738                         {
01739                                 doIt();
01740                         }
01741                         mBranch->highlightNextItem(NULL);
01742                         return TRUE;
01743                 }
01744                 else if (key == KEY_UP)
01745                 {
01746                         // switch to keyboard navigation mode
01747                         LLMenuGL::setKeyboardMode(TRUE);
01748 
01749                         if (getEnabled() && !isActive())
01750                         {
01751                                 doIt();
01752                         }
01753                         mBranch->highlightPrevItem(NULL);
01754                         return TRUE;
01755                 }
01756         }
01757 
01758         return FALSE;
01759 }
01760 
01761 void LLMenuItemBranchDownGL::draw( void )
01762 {
01763         //FIXME: try removing this
01764         if (mBranch->getVisible() && !mBranch->getTornOff())
01765         {
01766                 setHighlight(TRUE);
01767         }
01768 
01769         if( getHighlight() )
01770         {
01771                 glColor4fv( sHighlightBackground.mV );
01772                 gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0 );
01773         }
01774 
01775         U8 font_style = mStyle;
01776         if (LLMenuItemGL::sDropShadowText && getEnabled() && !mDrawTextDisabled )
01777         {
01778                 font_style |= LLFontGL::DROP_SHADOW_SOFT;
01779         }
01780 
01781         LLColor4 color;
01782         if (getHighlight())
01783         {
01784                 color = sHighlightForeground;
01785         }
01786         else if( mEnabled )
01787         {
01788                 color = sEnabledColor;
01789         }
01790         else
01791         {
01792                 color = sDisabledColor;
01793         }
01794         mFont->render( mLabel.getWString(), 0, (F32)mRect.getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
01795                                    LLFontGL::HCENTER, LLFontGL::BOTTOM, font_style );
01796 
01797 
01798         // underline navigation key only when keyboard navigation has been initiated
01799         if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode())
01800         {
01801                 LLString upper_case_label = mLabel.getString();
01802                 LLString::toUpper(upper_case_label);
01803                 std::string::size_type offset = upper_case_label.find(mJumpKey);
01804                 if (offset != std::string::npos)
01805                 {
01806                         S32 x_offset = llround((F32)mRect.getWidth() / 2.f - mFont->getWidthF32(mLabel.getString(), 0, S32_MAX) / 2.f);
01807                         S32 x_begin = x_offset + mFont->getWidth(mLabel, 0, offset);
01808                         S32 x_end = x_offset + mFont->getWidth(mLabel, 0, offset + 1);
01809                         gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS);
01810                 }
01811         }
01812 
01813         // reset every frame so that we only show highlight 
01814         // when we get hover events on that frame
01815         mGotHover = FALSE;
01816 }
01817 
01821 
01822 // Default constructor
01823 LLMenuGL::LLMenuGL( const LLString& name, const LLString& label, LLViewHandle parent_floater_handle )
01824 :       LLUICtrl( name, LLRect(), FALSE, NULL, NULL ),
01825         mBackgroundColor( sDefaultBackgroundColor ),
01826         mBgVisible( TRUE ),
01827         mParentMenuItem( NULL ),
01828         mLabel( label ),
01829         mDropShadowed( TRUE ),
01830         mHorizontalLayout( FALSE ),
01831         mKeepFixedSize( FALSE ),
01832         mLastMouseX(0),
01833         mLastMouseY(0),
01834         mMouseVelX(0),
01835         mMouseVelY(0),
01836         mTornOff(FALSE),
01837         mTearOffItem(NULL),
01838         mSpilloverBranch(NULL),
01839         mSpilloverMenu(NULL),
01840         mParentFloaterHandle(parent_floater_handle),
01841         mJumpKey(KEY_NONE)
01842 {
01843         mFadeTimer.stop();
01844         setCanTearOff(TRUE, parent_floater_handle);
01845         setTabStop(FALSE);
01846 }
01847 
01848 LLMenuGL::LLMenuGL( const LLString& label, LLViewHandle parent_floater_handle )
01849 :       LLUICtrl( label, LLRect(), FALSE, NULL, NULL ),
01850         mBackgroundColor( sDefaultBackgroundColor ),
01851         mBgVisible( TRUE ),
01852         mParentMenuItem( NULL ),
01853         mLabel( label ),
01854         mDropShadowed( TRUE ),
01855         mHorizontalLayout( FALSE ),
01856         mKeepFixedSize( FALSE ),
01857         mLastMouseX(0),
01858         mLastMouseY(0),
01859         mMouseVelX(0),
01860         mMouseVelY(0),
01861         mTornOff(FALSE),
01862         mTearOffItem(NULL),
01863         mSpilloverBranch(NULL),
01864         mSpilloverMenu(NULL),
01865         mParentFloaterHandle(parent_floater_handle),
01866         mJumpKey(KEY_NONE)
01867 {
01868         mFadeTimer.stop();
01869         setCanTearOff(TRUE, parent_floater_handle);
01870         setTabStop(FALSE);
01871 }
01872 
01873 // Destroys the object
01874 LLMenuGL::~LLMenuGL( void )
01875 {
01876         // delete the branch, as it might not be in view hierarchy
01877         // leave the menu, because it is always in view hierarchy
01878         delete mSpilloverBranch;
01879         mJumpKeys.clear();
01880 }
01881 
01882 void LLMenuGL::setCanTearOff(BOOL tear_off, LLViewHandle parent_floater_handle )
01883 {
01884         if (tear_off && mTearOffItem == NULL)
01885         {
01886                 mTearOffItem = new LLMenuItemTearOffGL(parent_floater_handle);
01887                 mItems.insert(mItems.begin(), mTearOffItem);
01888                 addChildAtEnd(mTearOffItem);
01889                 arrange();
01890         }
01891         else if (!tear_off && mTearOffItem != NULL)
01892         {
01893                 mItems.remove(mTearOffItem);
01894                 removeChild(mTearOffItem);
01895                 delete mTearOffItem;
01896                 mTearOffItem = NULL;
01897                 arrange();
01898         }
01899 }
01900 
01901 // virtual
01902 LLXMLNodePtr LLMenuGL::getXML(bool save_children) const
01903 {
01904         LLXMLNodePtr node = LLView::getXML();
01905 
01906         // Attributes
01907 
01908         node->createChild("opaque", TRUE)->setBoolValue(mBgVisible);
01909 
01910         node->createChild("drop_shadow", TRUE)->setBoolValue(mDropShadowed);
01911 
01912         node->createChild("tear_off", TRUE)->setBoolValue((mTearOffItem != NULL));
01913 
01914         if (mBgVisible)
01915         {
01916                 // TomY TODO: this should save out the color control name
01917                 node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
01918         }
01919 
01920         // Contents
01921         item_list_t::const_iterator item_iter;
01922         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
01923         {
01924                 LLView* child = (*item_iter);
01925                 LLMenuItemGL* item = (LLMenuItemGL*)child;
01926 
01927                 LLXMLNodePtr child_node = item->getXML();
01928 
01929                 node->addChild(child_node);
01930         }
01931 
01932         return node;
01933 }
01934 
01935 void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory)
01936 {
01937         if (child->hasName(LL_MENU_GL_TAG))
01938         {
01939                 // SUBMENU
01940                 LLMenuGL *submenu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory);
01941                 appendMenu(submenu);
01942                 if (LLMenuGL::sMenuContainer != NULL)
01943                 {
01944                         submenu->updateParent(LLMenuGL::sMenuContainer);
01945                 }
01946                 else
01947                 {
01948                         submenu->updateParent(parent);
01949                 }
01950         }
01951         else if (child->hasName(LL_MENU_ITEM_CALL_GL_TAG) || 
01952                         child->hasName(LL_MENU_ITEM_CHECK_GL_TAG) || 
01953                         child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG))
01954         {
01955                 LLMenuItemGL *item = NULL;
01956 
01957                 LLString type;
01958                 LLString item_name;
01959                 LLString source_label;
01960                 LLString item_label;
01961                 KEY              jump_key = KEY_NONE;
01962 
01963                 child->getAttributeString("type", type);
01964                 child->getAttributeString("name", item_name);
01965                 child->getAttributeString("label", source_label);
01966 
01967                 // parse jump key out of label
01968                 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
01969                 boost::char_separator<char> sep("_");
01970                 tokenizer tokens(source_label, sep);
01971                 tokenizer::iterator token_iter;
01972                 S32 token_count = 0;
01973                 for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
01974                 {
01975                         item_label += (*token_iter);
01976                         if (token_count > 0)
01977                         {
01978                                 jump_key = (*token_iter).c_str()[0];
01979                         }
01980                         ++token_count;
01981                 }
01982 
01983 
01984                 if (child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG))
01985                 {
01986                         appendSeparator(item_name);
01987                 }
01988                 else
01989                 {
01990                         // ITEM
01991                         if (child->hasName(LL_MENU_ITEM_CALL_GL_TAG) || 
01992                                 child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
01993                         {
01994                                 MASK mask = 0;
01995                                                         
01996 #ifdef LL_DARWIN
01997                                 // See if this Mac accelerator should really use the ctrl key and not get mapped to cmd
01998                                 BOOL useMacCtrl = FALSE;
01999                                 child->getAttributeBOOL("useMacCtrl", useMacCtrl);
02000 #endif // LL_DARWIN
02001                                 
02002                                 LLString shortcut;
02003                                 child->getAttributeString("shortcut", shortcut);
02004                                 if (shortcut.find("control") != shortcut.npos)
02005                                 {
02006 #ifdef LL_DARWIN
02007                                         if ( useMacCtrl )
02008                                         {
02009                                                 mask |= MASK_MAC_CONTROL;
02010                                         }
02011 #endif // LL_DARWIN
02012                                         mask |= MASK_CONTROL;
02013                                 }
02014                                 if (shortcut.find("alt") != shortcut.npos)
02015                                 {
02016                                         mask |= MASK_ALT;
02017                                 }
02018                                 if (shortcut.find("shift") != shortcut.npos)
02019                                 {
02020                                         mask |= MASK_SHIFT;
02021                                 }
02022                                 S32 pipe_pos = shortcut.rfind("|");
02023                                 LLString key_str = shortcut.substr(pipe_pos+1);
02024 
02025                                 KEY key = KEY_NONE;
02026                                 LLKeyboard::keyFromString(key_str, &key);
02027 
02028                                 LLMenuItemCallGL *new_item;
02029                                 LLXMLNodePtr call_child;
02030 
02031                                 if (child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
02032                                 {
02033                                         LLString control_name;
02034                                         child->getAttributeString("control_name", control_name);
02035 
02036                                         new_item = new LLMenuItemCheckGL(item_name, item_label, 0, 0, control_name, parent, 0, key, mask);
02037 
02038                                         for (call_child = child->getFirstChild(); call_child.notNull(); call_child = call_child->getNextSibling())
02039                                         {
02040                                                 if (call_child->hasName("on_check"))
02041                                                 {
02042                                                         LLString callback_name;
02043                                                         LLString control_name = "";
02044                                                         if (call_child->hasAttribute("function"))
02045                                                         {
02046                                                                 call_child->getAttributeString("function", callback_name);
02047 
02048                                                                 control_name = callback_name;
02049 
02050                                                                 LLString callback_data = item_name;
02051                                                                 if (call_child->hasAttribute("userdata"))
02052                                                                 {
02053                                                                         call_child->getAttributeString("userdata", callback_data);
02054                                                                         if (!callback_data.empty())
02055                                                                         {
02056                                                                                 control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
02057                                                                         }
02058                                                                 }
02059 
02060                                                                 LLSD userdata;
02061                                                                 userdata["control"] = control_name;
02062                                                                 userdata["data"] = callback_data;
02063 
02064                                                                 LLSimpleListener* callback = parent->getListenerByName(callback_name);
02065 
02066                                                                 if (!callback) continue;
02067 
02068                                                                 new_item->addListener(callback, "on_build", userdata);
02069                                                         }
02070                                                         else if (call_child->hasAttribute("control"))
02071                                                         {
02072                                                                 call_child->getAttributeString("control", control_name);
02073                                                         }
02074                                                         else
02075                                                         {
02076                                                                 continue;
02077                                                         }
02078                                                         LLControlBase *control = parent->findControl(control_name);
02079                                                         if (!control)
02080                                                         {
02081                                                                 parent->addBoolControl(control_name, FALSE);
02082                                                         }
02083                                                         ((LLMenuItemCheckGL*)new_item)->setCheckedControl(control_name, parent);
02084                                                 }
02085                                         }
02086                                 }
02087                                 else
02088                                 {
02089                                         new_item = new LLMenuItemCallGL(item_name, item_label, 0, 0, 0, 0, key, mask);
02090                                 }
02091 
02092                                 for (call_child = child->getFirstChild(); call_child.notNull(); call_child = call_child->getNextSibling())
02093                                 {
02094                                         if (call_child->hasName("on_click"))
02095                                         {
02096                                                 LLString callback_name;
02097                                                 call_child->getAttributeString("function", callback_name);
02098 
02099                                                 LLString callback_data = item_name;
02100                                                 if (call_child->hasAttribute("userdata"))
02101                                                 {
02102                                                         call_child->getAttributeString("userdata", callback_data);
02103                                                 }
02104 
02105                                                 LLSimpleListener* callback = parent->getListenerByName(callback_name);
02106 
02107                                                 if (!callback) continue;
02108 
02109                                                 new_item->addListener(callback, "on_click", callback_data);
02110                                         }
02111                                         if (call_child->hasName("on_enable"))
02112                                         {
02113                                                 LLString callback_name;
02114                                                 LLString control_name = "";
02115                                                 if (call_child->hasAttribute("function"))
02116                                                 {
02117                                                         call_child->getAttributeString("function", callback_name);
02118 
02119                                                         control_name = callback_name;
02120 
02121                                                         LLString callback_data = "";
02122                                                         if (call_child->hasAttribute("userdata"))
02123                                                         {
02124                                                                 call_child->getAttributeString("userdata", callback_data);
02125                                                                 if (!callback_data.empty())
02126                                                                 {
02127                                                                         control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
02128                                                                 }
02129                                                         }
02130 
02131                                                         LLSD userdata;
02132                                                         userdata["control"] = control_name;
02133                                                         userdata["data"] = callback_data;
02134 
02135                                                         LLSimpleListener* callback = parent->getListenerByName(callback_name);
02136 
02137                                                         if (!callback) continue;
02138 
02139                                                         new_item->addListener(callback, "on_build", userdata);
02140                                                 }
02141                                                 else if (call_child->hasAttribute("control"))
02142                                                 {
02143                                                         call_child->getAttributeString("control", control_name);
02144                                                 }
02145                                                 else
02146                                                 {
02147                                                         continue;
02148                                                 }
02149                                                 new_item->setEnabledControl(control_name, parent);
02150                                         }
02151                                         if (call_child->hasName("on_visible"))
02152                                         {
02153                                                 LLString callback_name;
02154                                                 LLString control_name = "";
02155                                                 if (call_child->hasAttribute("function"))
02156                                                 {
02157                                                         call_child->getAttributeString("function", callback_name);
02158 
02159                                                         control_name = callback_name;
02160 
02161                                                         LLString callback_data = "";
02162                                                         if (call_child->hasAttribute("userdata"))
02163                                                         {
02164                                                                 call_child->getAttributeString("userdata", callback_data);
02165                                                                 if (!callback_data.empty())
02166                                                                 {
02167                                                                         control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
02168                                                                 }
02169                                                         }
02170 
02171                                                         LLSD userdata;
02172                                                         userdata["control"] = control_name;
02173                                                         userdata["data"] = callback_data;
02174 
02175                                                         LLSimpleListener* callback = parent->getListenerByName(callback_name);
02176 
02177                                                         if (!callback) continue;
02178 
02179                                                         new_item->addListener(callback, "on_build", userdata);
02180                                                 }
02181                                                 else if (call_child->hasAttribute("control"))
02182                                                 {
02183                                                         call_child->getAttributeString("control", control_name);
02184                                                 }
02185                                                 else
02186                                                 {
02187                                                         continue;
02188                                                 }
02189                                                 new_item->setVisibleControl(control_name, parent);
02190                                         }
02191                                 }
02192                                 item = new_item;
02193                                 item->setLabel(item_label);
02194                                 if (jump_key != KEY_NONE)
02195                                         item->setJumpKey(jump_key);
02196                         }
02197 
02198                         if (item != NULL)
02199                         {
02200                                 append(item);
02201                         }
02202                 }
02203         }
02204 }
02205 
02206 // are we the childmost active menu and hence our jump keys should be enabled?
02207 // or are we a free-standing torn-off menu (which uses jump keys too)
02208 BOOL LLMenuGL::jumpKeysActive()
02209 {
02210         LLMenuItemGL* highlighted_item = getHighlightedItem();
02211         BOOL active = getVisible() && getEnabled();
02212         if (getTornOff())
02213         {
02214                 // activation of jump keys on torn off menus controlled by keyboard focus
02215                 active = active && ((LLFloater*)getParent())->hasFocus();
02216 
02217         }
02218         else
02219         {
02220                 // Are we the terminal active menu?
02221                 // Yes, if parent menu item deems us to be active (just being visible is sufficient for top-level menus)
02222                 // and we don't have a highlighted menu item pointing to an active sub-menu
02223                 active = active && (!getParentMenuItem() || getParentMenuItem()->isActive()) // I have a parent that is active...
02224                                 && (!highlighted_item || !highlighted_item->isActive()); //... but no child that is active
02225         }
02226         return active;
02227 }
02228 
02229 BOOL LLMenuGL::isOpen()
02230 {
02231         if (getTornOff())
02232         {
02233                 LLMenuItemGL* itemp = getHighlightedItem();
02234                 // if we have an open sub-menu, then we are considered part of 
02235                 // the open menu chain even if we don't have focus
02236                 if (itemp && itemp->isOpen())
02237                 {
02238                         return TRUE;
02239                 }
02240                 // otherwise we are only active if we have keyboard focus
02241                 return ((LLFloater*)getParent())->hasFocus();
02242         }
02243         else
02244         {
02245                 // normally, menus are hidden as soon as the user focuses
02246                 // on another menu, so just use the visibility criterion
02247                 return getVisible();
02248         }
02249 }
02250 // static
02251 LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
02252 {
02253         LLString name("menu");
02254         node->getAttributeString("name", name);
02255 
02256         LLString label = name;
02257         node->getAttributeString("label", label);
02258 
02259         // parse jump key out of label
02260         LLString new_menu_label;
02261 
02262         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
02263         boost::char_separator<char> sep("_");
02264         tokenizer tokens(label, sep);
02265         tokenizer::iterator token_iter;
02266 
02267         KEY jump_key = KEY_NONE;
02268         S32 token_count = 0;
02269         for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
02270         {
02271                 new_menu_label += (*token_iter);
02272                 if (token_count > 0)
02273                 {
02274                         jump_key = (*token_iter).c_str()[0];
02275                 }
02276                 ++token_count;
02277         }
02278 
02279         BOOL opaque = FALSE;
02280         node->getAttributeBOOL("opaque", opaque);
02281 
02282         LLMenuGL *menu = new LLMenuGL(name, new_menu_label);
02283 
02284         menu->setJumpKey(jump_key);
02285 
02286         BOOL tear_off = FALSE;
02287         node->getAttributeBOOL("tear_off", tear_off);
02288         menu->setCanTearOff(tear_off);
02289 
02290         if (node->hasAttribute("drop_shadow"))
02291         {
02292                 BOOL drop_shadow = FALSE;
02293                 node->getAttributeBOOL("drop_shadow", drop_shadow);
02294                 menu->setDropShadowed(drop_shadow);
02295         }
02296 
02297         menu->setBackgroundVisible(opaque);
02298         LLColor4 color(0,0,0,1);
02299         if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
02300         {
02301                 menu->setBackgroundColor(color);
02302         }
02303 
02304         BOOL create_jump_keys = FALSE;
02305         node->getAttributeBOOL("create_jump_keys", create_jump_keys);
02306 
02307         LLXMLNodePtr child;
02308         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
02309         {
02310                 menu->parseChildXML(child, parent, factory);
02311         }
02312 
02313         if (create_jump_keys)
02314         {
02315                 menu->createJumpKeys();
02316         }
02317         return menu;
02318 }
02319 
02320 // control the color scheme
02321 void LLMenuGL::setDefaultBackgroundColor( const LLColor4& color )
02322 {
02323         sDefaultBackgroundColor = color;
02324 }
02325 
02326 void LLMenuGL::setBackgroundColor( const LLColor4& color )
02327 {
02328         mBackgroundColor = color;
02329 }
02330 
02331 LLColor4 LLMenuGL::getBackgroundColor()
02332 {
02333         return mBackgroundColor;
02334 }
02335 
02336 
02337 // rearrange the child rects so they fit the shape of the menu.
02338 void LLMenuGL::arrange( void )
02339 {
02340         // calculate the height & width, and set our rect based on that
02341         // information.
02342         LLRect initial_rect = mRect;
02343 
02344         U32 width = 0, height = MENU_ITEM_PADDING;
02345 
02346         cleanupSpilloverBranch();
02347 
02348         if( mItems.size() ) 
02349         {
02350                 const LLRect menu_region_rect = LLMenuGL::sMenuContainer ? LLMenuGL::sMenuContainer->getMenuRect() : LLRect(0, S32_MAX, S32_MAX, 0);
02351 
02352                 U32 max_width = menu_region_rect.getWidth();
02353                 U32 max_height = menu_region_rect.getHeight();
02354                 // *FIX: create the item first and then ask for its dimensions?
02355                 S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::sSansSerif->getWidth( "More" );
02356                 S32 spillover_item_height = llround(LLFontGL::sSansSerif->getLineHeight()) + MENU_ITEM_PADDING;
02357 
02358                 if (mHorizontalLayout)
02359                 {
02360                         item_list_t::iterator item_iter;
02361                         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02362                         {
02363                                 if ((*item_iter)->getVisible())
02364                                 {
02365                                         if (!getTornOff() && width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width)
02366                                         {
02367                                                 // no room for any more items
02368                                                 createSpilloverBranch();
02369 
02370                                                 item_list_t::iterator spillover_iter;
02371                                                 for (spillover_iter = item_iter; spillover_iter != mItems.end(); ++spillover_iter)
02372                                                 {
02373                                                         LLMenuItemGL* itemp = (*spillover_iter);
02374                                                         removeChild(itemp);
02375                                                         mSpilloverMenu->append(itemp);
02376                                                 }
02377                                                 mItems.erase(item_iter, mItems.end());
02378                                                 
02379                                                 mItems.push_back(mSpilloverBranch);
02380                                                 addChild(mSpilloverBranch);
02381                                                 height = llmax(height, mSpilloverBranch->getNominalHeight());
02382                                                 width += mSpilloverBranch->getNominalWidth();
02383 
02384                                                 break;
02385                                         }
02386                                         else
02387                                         {
02388                                                 // track our rect
02389                                                 height = llmax(height, (*item_iter)->getNominalHeight());
02390                                                 width += (*item_iter)->getNominalWidth();
02391                                         }
02392                                 }
02393                         }
02394                 }
02395                 else
02396                 {
02397                         item_list_t::iterator item_iter;
02398                         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02399                         {
02400                                 if ((*item_iter)->getVisible())
02401                                 {
02402                                         if (!getTornOff() && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height)
02403                                         {
02404                                                 // no room for any more items
02405                                                 createSpilloverBranch();
02406 
02407                                                 item_list_t::iterator spillover_iter;
02408                                                 for (spillover_iter= item_iter; spillover_iter != mItems.end(); ++spillover_iter)
02409                                                 {
02410                                                         LLMenuItemGL* itemp = (*spillover_iter);
02411                                                         removeChild(itemp);
02412                                                         mSpilloverMenu->append(itemp);
02413                                                 }
02414                                                 mItems.erase(item_iter, mItems.end());
02415                                                 mItems.push_back(mSpilloverBranch);
02416                                                 addChild(mSpilloverBranch);
02417                                                 height += mSpilloverBranch->getNominalHeight();
02418                                                 width = llmax( width, mSpilloverBranch->getNominalWidth() );
02419 
02420                                                 break;
02421                                         }
02422                                         else
02423                                         {
02424                                                 // track our rect
02425                                                 height += (*item_iter)->getNominalHeight();
02426                                                 width = llmax( width, (*item_iter)->getNominalWidth() );
02427                                         }
02428                                 }
02429                         }
02430                 }
02431 
02432                 mRect.mRight = mRect.mLeft + width;
02433                 mRect.mTop = mRect.mBottom + height;
02434 
02435                 S32 cur_height = (S32)llmin(max_height, height);
02436                 S32 cur_width = 0;
02437                 item_list_t::iterator item_iter;
02438                 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02439                 {
02440                         if ((*item_iter)->getVisible())
02441                         {
02442                                 // setup item rect to hold label
02443                                 LLRect rect;
02444                                 if (mHorizontalLayout)
02445                                 {
02446                                         rect.setLeftTopAndSize( cur_width, height, (*item_iter)->getNominalWidth(), height);
02447                                         cur_width += (*item_iter)->getNominalWidth();
02448                                 }
02449                                 else
02450                                 {
02451                                         rect.setLeftTopAndSize( 0, cur_height, width, (*item_iter)->getNominalHeight());
02452                                         cur_height -= (*item_iter)->getNominalHeight();
02453                                 }
02454                                 (*item_iter)->setRect( rect );
02455                                 (*item_iter)->buildDrawLabel();
02456                         }
02457                 }
02458         }
02459         if (mKeepFixedSize)
02460         {
02461                 reshape(initial_rect.getWidth(), initial_rect.getHeight());
02462         }
02463 }
02464 
02465 void LLMenuGL::createSpilloverBranch()
02466 {
02467         if (!mSpilloverBranch)
02468         {
02469                 // should be NULL but delete anyway
02470                 delete mSpilloverMenu;
02471                 // technically, you can't tear off spillover menus, but we're passing the handle
02472                 // along just to be safe
02473                 mSpilloverMenu = new LLMenuGL("More", "More", mParentFloaterHandle);
02474                 mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer);
02475                 // Inherit colors
02476                 mSpilloverMenu->setBackgroundColor( mBackgroundColor );
02477                 mSpilloverMenu->setCanTearOff(FALSE);
02478 
02479                 mSpilloverBranch = new LLMenuItemBranchGL("More", "More", mSpilloverMenu);
02480                 mSpilloverBranch->setFontStyle(LLFontGL::ITALIC);
02481         }
02482 }
02483 
02484 void LLMenuGL::cleanupSpilloverBranch()
02485 {
02486         if (mSpilloverBranch && mSpilloverBranch->getParent() == this)
02487         {
02488                 // head-recursion to propagate items back up to root menu
02489                 mSpilloverMenu->cleanupSpilloverBranch();
02490 
02491                 removeChild(mSpilloverBranch);
02492 
02493                 item_list_t::iterator found_iter = std::find(mItems.begin(), mItems.end(), mSpilloverBranch);
02494                 if (found_iter != mItems.end())
02495                 {
02496                         mItems.erase(found_iter);
02497                 }
02498 
02499                 delete mSpilloverBranch;
02500                 mSpilloverBranch = NULL;
02501 
02502                 // pop off spillover items
02503                 while (mSpilloverMenu->getItemCount())
02504                 {
02505                         LLMenuItemGL* itemp = mSpilloverMenu->getItem(0);
02506                         mSpilloverMenu->removeChild(itemp);
02507                         mSpilloverMenu->mItems.erase(mSpilloverMenu->mItems.begin());
02508                         // put them at the end of our own list
02509                         mItems.push_back(itemp);
02510                         addChild(itemp);
02511                 }
02512         }
02513 }
02514 
02515 void LLMenuGL::createJumpKeys()
02516 {
02517         mJumpKeys.clear();
02518 
02519         std::set<LLString> unique_words;
02520         std::set<LLString> shared_words;
02521 
02522         item_list_t::iterator item_it;
02523         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
02524         boost::char_separator<char> sep(" ");
02525 
02526         for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it)
02527         {
02528                 LLString uppercase_label = (*item_it)->getLabel();
02529                 LLString::toUpper(uppercase_label);
02530 
02531                 tokenizer tokens(uppercase_label, sep);
02532                 tokenizer::iterator token_iter;
02533                 for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
02534                 {
02535                         if (unique_words.find(*token_iter) != unique_words.end())
02536                         {
02537                                 // this word exists in more than one menu instance
02538                                 shared_words.insert(*token_iter);
02539                         }
02540                         else
02541                         {
02542                                 // we have a new word, keep track of it
02543                                 unique_words.insert(*token_iter);
02544                         }
02545                 }
02546         }
02547 
02548         // pre-assign specified jump keys
02549         for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it)
02550         {
02551                 KEY jump_key = (*item_it)->getJumpKey();
02552                 if(jump_key != KEY_NONE)
02553                 {
02554                         if (mJumpKeys.find(jump_key) == mJumpKeys.end())
02555                         {
02556                                 mJumpKeys.insert(std::pair<KEY, LLMenuItemGL*>(jump_key, (*item_it)));
02557                         }
02558                         else
02559                         {
02560                                 // this key is already spoken for, 
02561                                 // so we need to reassign it below
02562                                 (*item_it)->setJumpKey(KEY_NONE);
02563                         }
02564                 }
02565         }
02566 
02567         for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it)
02568         {
02569                 // skip over items that already have assigned jump keys
02570                 if ((*item_it)->getJumpKey() != KEY_NONE)
02571                 {
02572                         continue;
02573                 }
02574                 LLString uppercase_label = (*item_it)->getLabel();
02575                 LLString::toUpper(uppercase_label);
02576 
02577                 tokenizer tokens(uppercase_label, sep);
02578                 tokenizer::iterator token_iter;
02579 
02580                 BOOL found_key = FALSE;
02581                 for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
02582                 {
02583                         LLString uppercase_word = *token_iter;
02584 
02585                         // this word is not shared with other menu entries...
02586                         if (shared_words.find(*token_iter) == shared_words.end())
02587                         {
02588                                 S32 i;
02589                                 for(i = 0; i < (S32)uppercase_word.size(); i++)
02590                                 {
02591                                         char jump_key = uppercase_word[i];
02592                                         
02593                                         if (LLStringOps::isDigit(jump_key) || LLStringOps::isUpper(jump_key) &&
02594                                                 mJumpKeys.find(jump_key) == mJumpKeys.end())
02595                                         {
02596                                                 mJumpKeys.insert(std::pair<KEY, LLMenuItemGL*>(jump_key, (*item_it)));
02597                                                 (*item_it)->setJumpKey(jump_key);
02598                                                 found_key = TRUE;
02599                                                 break;
02600                                         }
02601                                 }
02602                         }
02603                         if (found_key)
02604                         {
02605                                 break;
02606                         }
02607                 }
02608         }
02609 }
02610 
02611 // remove all items on the menu
02612 void LLMenuGL::empty( void )
02613 {
02614         cleanupSpilloverBranch();
02615 
02616         mItems.clear();
02617 
02618         deleteAllChildren();
02619         
02620 }
02621 
02622 // Adjust rectangle of the menu
02623 void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom)
02624 {
02625         mRect.mLeft = left;
02626         mRect.mBottom = bottom;
02627         arrange();
02628 }
02629 
02630 BOOL LLMenuGL::handleJumpKey(KEY key)
02631 {
02632         // must perform case-insensitive comparison, so just switch to uppercase input key
02633         key = toupper(key);
02634         navigation_key_map_t::iterator found_it = mJumpKeys.find(key);
02635         if(found_it != mJumpKeys.end() && found_it->second->getEnabled())
02636         {
02637                 // switch to keyboard navigation mode
02638                 LLMenuGL::setKeyboardMode(TRUE);
02639 
02640                 // force highlight to close old menus and any open sub-menus
02641 
02642                 //clearHoverItem();
02643                 // force highlight to close old menus and open and sub-menus
02644                 found_it->second->setHighlight(TRUE);
02645                 found_it->second->doIt();
02646 
02647         }
02648         // if we are navigating the menus, we need to eat the keystroke
02649         // so rest of UI doesn't handle it
02650         return TRUE;
02651 }
02652 
02653 
02654 // Add the menu item to this menu.
02655 BOOL LLMenuGL::append( LLMenuItemGL* item )
02656 {
02657         mItems.push_back( item );
02658         addChild( item );
02659         arrange();
02660         return TRUE;
02661 }
02662 
02663 // add a separator to this menu
02664 BOOL LLMenuGL::appendSeparator( const LLString &separator_name )
02665 {
02666         LLMenuItemGL* separator = new LLMenuItemSeparatorGL(separator_name);
02667         return append( separator );
02668 }
02669 
02670 // add a menu - this will create a cascading menu
02671 BOOL LLMenuGL::appendMenu( LLMenuGL* menu )
02672 {
02673         if( menu == this )
02674         {
02675                 llerrs << "** Attempt to attach menu to itself. This is certainly "
02676                            << "a logic error." << llendl;
02677         }
02678         BOOL success = TRUE;
02679 
02680         LLMenuItemBranchGL* branch = NULL;
02681         branch = new LLMenuItemBranchGL( menu->getName(), menu->getLabel(), menu );
02682         branch->setJumpKey(menu->getJumpKey());
02683         success &= append( branch );
02684 
02685         // Inherit colors
02686         menu->setBackgroundColor( mBackgroundColor );
02687 
02688         return success;
02689 }
02690 
02691 void LLMenuGL::setEnabledSubMenus(BOOL enable)
02692 {
02693         setEnabled(enable);
02694         item_list_t::iterator item_iter;
02695         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02696         {
02697                 (*item_iter)->setEnabledSubMenus( enable );
02698         }
02699 }
02700 
02701 // setItemEnabled() - pass the label and the enable flag for a menu
02702 // item. TRUE will make sure it's enabled, FALSE will disable it.
02703 void LLMenuGL::setItemEnabled( const LLString& name, BOOL enable )
02704 {
02705         item_list_t::iterator item_iter;
02706         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02707         {
02708                 if( (*item_iter)->getName() == name )
02709                 {
02710                         (*item_iter)->setEnabled( enable );
02711                         (*item_iter)->setEnabledSubMenus( enable );
02712                         break;
02713                 }
02714         }
02715 }
02716 
02717 void LLMenuGL::setItemVisible( const LLString& name, BOOL visible )
02718 {
02719         item_list_t::iterator item_iter;
02720         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02721         {
02722                 if( (*item_iter)->getName() == name )
02723                 {
02724                         (*item_iter)->setVisible( visible );
02725                         break;
02726                 }
02727         }
02728 }
02729 
02730 void LLMenuGL::setItemLastSelected(LLMenuItemGL* item)
02731 {
02732         if (getVisible())
02733         {
02734                 LLMenuHolderGL::setActivatedItem(item);
02735         }
02736 
02737         // fix the checkmarks
02738         item->buildDrawLabel();
02739 }
02740 
02741 //  Set whether drop shadowed 
02742 void LLMenuGL::setDropShadowed( const BOOL shadowed )
02743 {
02744         mDropShadowed = shadowed;
02745 }
02746 
02747 void LLMenuGL::setTornOff(BOOL torn_off)
02748 { 
02749         mTornOff = torn_off;
02750 }
02751 
02752 U32 LLMenuGL::getItemCount()
02753 {
02754         return mItems.size();
02755 }
02756 
02757 LLMenuItemGL* LLMenuGL::getItem(S32 number)
02758 {
02759         if (number >= 0 && number < (S32)mItems.size())
02760         {
02761                 item_list_t::iterator item_iter;
02762                 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02763                 {
02764                         if (number == 0)
02765                         {
02766                                 return (*item_iter);
02767                         }
02768                         number--;
02769                 }
02770         }
02771         return NULL;
02772 }
02773 
02774 LLMenuItemGL* LLMenuGL::getHighlightedItem()
02775 {
02776         item_list_t::iterator item_iter;
02777         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02778         {
02779                 if ((*item_iter)->getHighlight())
02780                 {
02781                         return (*item_iter);
02782                 }
02783         }
02784         return NULL;
02785 }
02786 
02787 LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled)
02788 {
02789         // highlighting first item on a torn off menu is the
02790         // same as giving focus to it
02791         if (!cur_item && getTornOff())
02792         {
02793                 ((LLFloater*)getParent())->setFocus(TRUE);
02794         }
02795 
02796         item_list_t::iterator cur_item_iter;
02797         for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); ++cur_item_iter)
02798         {
02799                 if( (*cur_item_iter) == cur_item)
02800                 {
02801                         break;
02802                 }
02803         }
02804 
02805         item_list_t::iterator next_item_iter;
02806         if (cur_item_iter == mItems.end())
02807         {
02808                 next_item_iter = mItems.begin();
02809         }
02810         else
02811         {
02812                 next_item_iter = cur_item_iter;
02813                 next_item_iter++;
02814                 if (next_item_iter == mItems.end())
02815                 {
02816                         next_item_iter = mItems.begin();
02817                 }
02818         }
02819 
02820         // when first highlighting a menu, skip over tear off menu item
02821         if (mTearOffItem && !cur_item)
02822         {
02823                 // we know the first item is the tear off menu item
02824                 cur_item_iter = mItems.begin();
02825                 next_item_iter++;
02826                 if (next_item_iter == mItems.end())
02827                 {
02828                         next_item_iter = mItems.begin();
02829                 }
02830         }
02831 
02832         while(1)
02833         {
02834                 // skip separators and disabled items
02835                 if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getName() != SEPARATOR_NAME)
02836                 {
02837                         if (cur_item)
02838                         {
02839                                 cur_item->setHighlight(FALSE);
02840                         }
02841                         (*next_item_iter)->setHighlight(TRUE);
02842                         return (*next_item_iter);
02843                 }
02844 
02845 
02846                 if (!skip_disabled || next_item_iter == cur_item_iter)
02847                 {
02848                         break;
02849                 }
02850 
02851                 next_item_iter++;
02852                 if (next_item_iter == mItems.end())
02853                 {
02854                         if (cur_item_iter == mItems.end())
02855                         {
02856                                 break;
02857                         }
02858                         next_item_iter = mItems.begin();
02859                 }
02860         }
02861 
02862         return NULL;
02863 }
02864 
02865 LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled)
02866 {
02867         // highlighting first item on a torn off menu is the
02868         // same as giving focus to it
02869         if (!cur_item && getTornOff())
02870         {
02871                 ((LLFloater*)getParent())->setFocus(TRUE);
02872         }
02873 
02874         item_list_t::reverse_iterator cur_item_iter;
02875         for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter)
02876         {
02877                 if( (*cur_item_iter) == cur_item)
02878                 {
02879                         break;
02880                 }
02881         }
02882 
02883         item_list_t::reverse_iterator prev_item_iter;
02884         if (cur_item_iter == mItems.rend())
02885         {
02886                 prev_item_iter = mItems.rbegin();
02887         }
02888         else
02889         {
02890                 prev_item_iter = cur_item_iter;
02891                 prev_item_iter++;
02892                 if (prev_item_iter == mItems.rend())
02893                 {
02894                         prev_item_iter = mItems.rbegin();
02895                 }
02896         }
02897 
02898         while(1)
02899         {
02900                 // skip separators and disabled items
02901                 if ((*prev_item_iter)->getEnabled() && (*prev_item_iter)->getName() != SEPARATOR_NAME)
02902                 {
02903                         (*prev_item_iter)->setHighlight(TRUE);
02904                         return (*prev_item_iter);
02905                 }
02906 
02907                 if (!skip_disabled || prev_item_iter == cur_item_iter)
02908                 {
02909                         break;
02910                 }
02911 
02912                 prev_item_iter++;
02913                 if (prev_item_iter == mItems.rend())
02914                 {
02915                         if (cur_item_iter == mItems.rend())
02916                         {
02917                                 break;
02918                         }
02919 
02920                         prev_item_iter = mItems.rbegin();
02921                 }
02922         }
02923 
02924         return NULL;
02925 }
02926 
02927 void LLMenuGL::buildDrawLabels()
02928 {
02929         item_list_t::iterator item_iter;
02930         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02931         {
02932                 (*item_iter)->buildDrawLabel();
02933         }
02934 }
02935 
02936 void LLMenuGL::updateParent(LLView* parentp)
02937 {
02938         if (getParent())
02939         {
02940                 getParent()->removeChild(this);
02941         }
02942         parentp->addChild(this);
02943         item_list_t::iterator item_iter;
02944         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02945         {
02946                 (*item_iter)->updateBranchParent(parentp);
02947         }
02948 }
02949 
02950 // LLView functionality
02951 BOOL LLMenuGL::handleKey( KEY key, MASK mask, BOOL called_from_parent )
02952 {
02953         BOOL handled = FALSE;
02954 
02955         // Pass down even if not visible
02956         if( mEnabled && called_from_parent )
02957         {
02958                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02959                 {
02960                         LLView* viewp = *child_it;
02961                         if (viewp->handleKey(key, mask, TRUE))
02962                         {
02963                                 handled = TRUE;
02964                                 break;
02965                         }
02966                 }
02967         }
02968 
02969         if( !handled )
02970         {
02971                 handled = handleKeyHere( key, mask, called_from_parent );
02972                 if (handled && LLView::sDebugKeys)
02973                 {
02974                         llinfos << "Key handled by " << getName() << llendl;
02975                 }
02976         }
02977 
02978         return handled;
02979 }
02980 
02981 BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
02982 {
02983         // don't handle if not enabled
02984         if(!mEnabled)
02985         {
02986                 return FALSE;
02987         }
02988 
02989         // Pass down even if not visible
02990         item_list_t::iterator item_iter;
02991         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
02992         {
02993                 LLMenuItemGL* itemp = *item_iter;
02994                 if (itemp->handleAcceleratorKey(key, mask))
02995                 {
02996                         return TRUE;
02997                 }
02998         }
02999 
03000         return FALSE;
03001 }
03002 
03003 BOOL LLMenuGL::handleUnicodeCharHere( llwchar uni_char, BOOL called_from_parent )
03004 {
03005         if (jumpKeysActive())
03006         {
03007                 return handleJumpKey((KEY)uni_char);
03008         }
03009         return FALSE;
03010 }
03011 
03012 BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
03013 {
03014         // leave submenu in place if slope of mouse < MAX_MOUSE_SLOPE_SUB_MENU
03015         BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0;
03016         S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX;
03017         S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY;
03018         LLVector2 mouse_dir((F32)mouse_delta_x, (F32)mouse_delta_y);
03019         mouse_dir.normVec();
03020         LLVector2 mouse_avg_dir((F32)mMouseVelX, (F32)mMouseVelY);
03021         mouse_avg_dir.normVec();
03022         F32 interp = 0.5f * (llclamp(mouse_dir * mouse_avg_dir, 0.f, 1.f));
03023         mMouseVelX = llround(lerp((F32)mouse_delta_x, (F32)mMouseVelX, interp));
03024         mMouseVelY = llround(lerp((F32)mouse_delta_y, (F32)mMouseVelY, interp));
03025         mLastMouseX = x;
03026         mLastMouseY = y;
03027 
03028         // don't change menu focus unless mouse is moving or alt key is not held down
03029         if ((llabs(mMouseVelX) > 0 || 
03030                         llabs(mMouseVelY) > 0) &&
03031                 (!mHasSelection ||
03032                 //(mouse_delta_x == 0 && mouse_delta_y == 0) ||
03033                 (mMouseVelX < 0) ||
03034                 llabs((F32)mMouseVelY) / llabs((F32)mMouseVelX) > MAX_MOUSE_SLOPE_SUB_MENU))
03035         {
03036                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
03037                 {
03038                         LLView* viewp = *child_it;
03039                         S32 local_x = x - viewp->getRect().mLeft;
03040                         S32 local_y = y - viewp->getRect().mBottom;
03041                         if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight())
03042                         {
03043                                 // moving mouse always highlights new item
03044                                 if (mouse_delta_x != 0 || mouse_delta_y != 0)
03045                                 {
03046                                         ((LLMenuItemGL*)viewp)->setHighlight(FALSE);
03047                                 }
03048                         }
03049                 }
03050 
03051                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
03052                 {
03053                         LLView* viewp = *child_it;
03054                         S32 local_x = x - viewp->getRect().mLeft;
03055                         S32 local_y = y - viewp->getRect().mBottom;
03056                         //RN: always call handleHover to track mGotHover status
03057                         // but only set highlight when mouse is moving
03058                         if( viewp->getVisible() && 
03059                                 //RN: allow disabled items to be highlighted to preserve "active" menus when
03060                                 // moving mouse through them
03061                                 //viewp->getEnabled() && 
03062                                 viewp->pointInView(local_x, local_y) && 
03063                                 viewp->handleHover(local_x, local_y, mask))
03064                         {
03065                                 // moving mouse always highlights new item
03066                                 if (mouse_delta_x != 0 || mouse_delta_y != 0)
03067                                 {
03068                                         ((LLMenuItemGL*)viewp)->setHighlight(TRUE);
03069                                         LLMenuGL::setKeyboardMode(FALSE);
03070                                 }
03071                                 mHasSelection = TRUE;
03072                         }
03073                 }
03074         }
03075         getWindow()->setCursor(UI_CURSOR_ARROW);
03076         return TRUE;
03077 }
03078 
03079 void LLMenuGL::draw( void )
03080 {
03081         if (mDropShadowed && !mTornOff)
03082         {
03083                 gl_drop_shadow(0, mRect.getHeight(), mRect.getWidth(), 0, 
03084                         LLUI::sColorsGroup->getColor("ColorDropShadow"), 
03085                         LLUI::sConfigGroup->getS32("DropShadowFloater") );
03086         }
03087 
03088         LLColor4 bg_color = mBackgroundColor;
03089 
03090         if( mBgVisible )
03091         {
03092                 gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0, mBackgroundColor );
03093         }
03094         LLView::draw();
03095 }
03096 
03097 void LLMenuGL::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
03098 {
03099         glColor4fv( color.mV );
03100         LLRect item_rect = itemp->getRect();
03101         gl_rect_2d( 0, item_rect.getHeight(), item_rect.getWidth(), 0);
03102 }
03103 
03104 void LLMenuGL::setVisible(BOOL visible)
03105 {
03106         if (visible != getVisible())
03107         {
03108                 if (!visible)
03109                 {
03110                         mFadeTimer.start();
03111                         clearHoverItem();
03112                         // reset last known mouse coordinates so
03113                         // we don't spoof a mouse move next time we're opened
03114                         mLastMouseX = 0;
03115                         mLastMouseY = 0;
03116                 }
03117                 else
03118                 {
03119                         mHasSelection = FALSE;
03120                         mFadeTimer.stop();
03121                 }
03122 
03123                 LLView::setVisible(visible);
03124         }
03125 }
03126 
03127 LLMenuGL* LLMenuGL::getChildMenuByName(const LLString& name, BOOL recurse) const
03128 {
03129         LLView* view = getChildByName(name, recurse);
03130         if (view)
03131         {
03132                 if (view->getWidgetType() == WIDGET_TYPE_MENU_ITEM_BRANCH)
03133                 {
03134                         LLMenuItemBranchGL *branch = (LLMenuItemBranchGL *)view;
03135                         return branch->getBranch();
03136                 }
03137                 if (view->getWidgetType() == WIDGET_TYPE_MENU || view->getWidgetType() == WIDGET_TYPE_PIE_MENU)
03138                 {
03139                         return (LLMenuGL*)view;
03140                 }
03141         }
03142         llwarns << "Child Menu " << name << " not found in menu " << mName << llendl;
03143         return NULL;
03144 }
03145 
03146 BOOL LLMenuGL::clearHoverItem()
03147 {
03148         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
03149         {
03150                 LLMenuItemGL* itemp = (LLMenuItemGL*)*child_it;
03151                 if (itemp->getHighlight())
03152                 {
03153                         itemp->setHighlight(FALSE);
03154                         return TRUE;
03155                 }
03156         }               
03157         return FALSE;
03158 }
03159 
03160 void hide_top_view( LLView* view )
03161 {
03162         if( view ) view->setVisible( FALSE );
03163 }
03164 
03165 
03166 // static
03167 void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
03168 {
03169         const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
03170 
03171         const S32 HPAD = 2;
03172         LLRect rect = menu->getRect();
03173         //LLView* cur_view = spawning_view;
03174         S32 left = x + HPAD;
03175         S32 top = y;
03176         spawning_view->localPointToOtherView(left, top, &left, &top, menu->getParent());
03177         rect.setLeftTopAndSize( left, top,
03178                                                         rect.getWidth(), rect.getHeight() );
03179 
03180 
03181         //rect.setLeftTopAndSize(x + HPAD, y, rect.getWidth(), rect.getHeight());
03182         menu->setRect( rect );
03183 
03184         S32 bottom;
03185         left = rect.mLeft;
03186         bottom = rect.mBottom;
03187         //menu->getParent()->localPointToScreen( rect.mLeft, rect.mBottom, 
03188         //                                                                      &left, &bottom ); 
03189         S32 delta_x = 0;
03190         S32 delta_y = 0;
03191         if( bottom < menu_region_rect.mBottom )
03192         {
03193                 // At this point, we need to move the context menu to the
03194                 // other side of the mouse.
03195                 //delta_y = menu_region_rect.mBottom - bottom;
03196                 delta_y = (rect.getHeight() + 2 * HPAD);
03197         }
03198 
03199         if( left > menu_region_rect.mRight - rect.getWidth() )
03200         {
03201                 // At this point, we need to move the context menu to the
03202                 // other side of the mouse.
03203                 //delta_x = (window_width - rect.getWidth()) - x;
03204                 delta_x = -(rect.getWidth() + 2 * HPAD);
03205         }
03206         menu->translate( delta_x, delta_y );
03207         menu->setVisible( TRUE );
03208 }
03209 
03210 //-----------------------------------------------------------------------------
03211 // class LLPieMenuBranch
03212 // A branch to another pie menu
03213 //-----------------------------------------------------------------------------
03214 class LLPieMenuBranch : public LLMenuItemGL
03215 {
03216 public:
03217         LLPieMenuBranch(const LLString& name, const LLString& label, LLPieMenu* branch,
03218                                         enabled_callback ecb, void* user_data);
03219 
03220         virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_PIE_MENU_BRANCH; }
03221         virtual LLString getWidgetTag() const { return LL_PIE_MENU_BRANCH_TAG; }
03222 
03223         // called to rebuild the draw label
03224         virtual void buildDrawLabel( void );
03225 
03226         // doIt() - do the primary funcationality of the menu item.
03227         virtual void doIt( void );
03228 
03229         LLPieMenu* getBranch() { return mBranch; }
03230 
03231 protected:
03232         LLPieMenu* mBranch;
03233         enabled_callback mEnabledCallback;
03234         void* mUserData;
03235 };
03236 
03237 LLPieMenuBranch::LLPieMenuBranch(const LLString& name,
03238                                                                  const LLString& label,
03239                                                                  LLPieMenu* branch,
03240                                                                  enabled_callback ecb,
03241                                                                  void* user_data) 
03242 :       LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ),
03243         mBranch( branch ),
03244         mEnabledCallback( ecb ),
03245         mUserData(user_data)
03246 {
03247         mBranch->hide(FALSE);
03248         mBranch->setParentMenuItem(this);
03249 }
03250 
03251 // called to rebuild the draw label
03252 void LLPieMenuBranch::buildDrawLabel( void )
03253 {
03254         if(mEnabledCallback)
03255         {
03256                 setEnabled(mEnabledCallback(mUserData));
03257                 mDrawTextDisabled = FALSE;
03258         }
03259         else
03260         {
03261                 // default enablement is this -- if any of the subitems are
03262                 // enabled, this item is enabled. JC
03263                 U32 sub_count = mBranch->getItemCount();
03264                 U32 i;
03265                 BOOL any_enabled = FALSE;
03266                 for (i = 0; i < sub_count; i++)
03267                 {
03268                         LLMenuItemGL* item = mBranch->getItem(i);
03269                         item->buildDrawLabel();
03270                         if (item->getEnabled() && !item->getDrawTextDisabled() )
03271                         {
03272                                 any_enabled = TRUE;
03273                                 break;
03274                         }
03275                 }
03276                 mDrawTextDisabled = !any_enabled;
03277                 setEnabled(TRUE);
03278         }
03279 
03280         mDrawAccelLabel.clear();
03281         LLString st = mDrawAccelLabel;
03282         appendAcceleratorString( st );
03283         mDrawAccelLabel = st;
03284         
03285         // No special branch suffix
03286         mDrawBranchLabel.clear();
03287 }
03288 
03289 // doIt() - do the primary funcationality of the menu item.
03290 void LLPieMenuBranch::doIt( void )
03291 {
03292         LLPieMenu *parent = (LLPieMenu *)getParent();
03293 
03294         LLRect rect = parent->getRect();
03295         S32 center_x;
03296         S32 center_y;
03297         parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, &center_x, &center_y);
03298 
03299         parent->hide(FALSE);
03300         mBranch->show(  center_x, center_y, FALSE );
03301 }
03302 
03303 //-----------------------------------------------------------------------------
03304 // class LLPieMenu
03305 // A circular menu of items, icons, etc.
03306 //-----------------------------------------------------------------------------
03307 LLPieMenu::LLPieMenu(const LLString& name, const LLString& label)
03308 :       LLMenuGL(name, label),
03309         mFirstMouseDown(FALSE),
03310         mUseInfiniteRadius(FALSE),
03311         mHoverItem(NULL),
03312         mHoverThisFrame(FALSE),
03313         mHoveredAnyItem(FALSE),
03314         mOuterRingAlpha(1.f),
03315         mCurRadius(0.f),
03316         mRightMouseDown(FALSE)
03317 { 
03318         LLMenuGL::setVisible(FALSE);
03319         setCanTearOff(FALSE);
03320 }
03321 
03322 LLPieMenu::LLPieMenu(const LLString& name)
03323 :       LLMenuGL(name, name),
03324         mFirstMouseDown(FALSE),
03325         mUseInfiniteRadius(FALSE),
03326         mHoverItem(NULL),
03327         mHoverThisFrame(FALSE),
03328         mHoveredAnyItem(FALSE),
03329         mOuterRingAlpha(1.f),
03330         mCurRadius(0.f),
03331         mRightMouseDown(FALSE)
03332 { 
03333         LLMenuGL::setVisible(FALSE);
03334         setCanTearOff(FALSE);
03335 }
03336 
03337 // virtual
03338 LLPieMenu::~LLPieMenu()
03339 { }
03340 
03341 
03342 EWidgetType LLPieMenu::getWidgetType() const
03343 {
03344         return WIDGET_TYPE_PIE_MENU;
03345 }
03346 
03347 LLString LLPieMenu::getWidgetTag() const
03348 {
03349         return LL_PIE_MENU_TAG;
03350 }
03351 
03352 void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory)
03353 {
03354         LLXMLNodePtr child;
03355         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
03356         {
03357                 if (child->hasName(LL_PIE_MENU_TAG))
03358                 {
03359                         // SUBMENU
03360                         LLString name("menu");
03361                         child->getAttributeString("name", name);
03362                         LLString label(name);
03363                         child->getAttributeString("label", label);
03364 
03365                         LLPieMenu *submenu = new LLPieMenu(name, label);
03366                         appendMenu(submenu);
03367                         submenu->initXML(child, context, factory);
03368                 }
03369                 else
03370                 {
03371                         parseChildXML(child, context, factory);
03372                 }
03373         }
03374 }
03375 
03376 // virtual
03377 void LLPieMenu::setVisible(BOOL visible)
03378 {
03379         if (!visible)
03380         {
03381                 hide(FALSE);
03382         }
03383 }
03384 
03385 BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
03386 {
03387         // This is mostly copied from the llview class, but it continues
03388         // the hover handle code after a hover handler has been found.
03389         BOOL handled = FALSE;
03390 
03391         // If we got a hover event, we've already moved the cursor
03392         // for any menu shifts, so subsequent mouseup messages will be in the
03393         // correct position.  No need to correct them.
03394         //mShiftHoriz = 0;
03395         //mShiftVert = 0;
03396 
03397         // release mouse capture after short period of visibility if we're using a finite boundary
03398         // so that right click outside of boundary will trigger new pie menu
03399         if (hasMouseCapture() && 
03400                 !mRightMouseDown && 
03401                 mShrinkBorderTimer.getStarted() && 
03402                 mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
03403         {
03404                 gFocusMgr.setMouseCapture(NULL);
03405                 mUseInfiniteRadius = FALSE;
03406         }
03407 
03408         LLMenuItemGL *item = pieItemFromXY( x, y );
03409 
03410         if (item && item->getEnabled())
03411         {
03412                 getWindow()->setCursor(UI_CURSOR_ARROW);
03413                 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;              
03414                 handled = TRUE;
03415 
03416                 if (item != mHoverItem)
03417                 {
03418                         if (mHoverItem)
03419                         {
03420                                 mHoverItem->setHighlight( FALSE );
03421                         }
03422                         mHoverItem = item;
03423                         mHoverItem->setHighlight( TRUE );
03424 
03425                         switch(pieItemIndexFromXY(x, y))
03426                         {
03427                         case 0:
03428                                 make_ui_sound("UISndPieMenuSliceHighlight0");
03429                                 break;
03430                         case 1:
03431                                 make_ui_sound("UISndPieMenuSliceHighlight1");
03432                                 break;
03433                         case 2:
03434                                 make_ui_sound("UISndPieMenuSliceHighlight2");
03435                                 break;
03436                         case 3:
03437                                 make_ui_sound("UISndPieMenuSliceHighlight3");
03438                                 break;
03439                         case 4:
03440                                 make_ui_sound("UISndPieMenuSliceHighlight4");
03441                                 break;
03442                         case 5:
03443                                 make_ui_sound("UISndPieMenuSliceHighlight5");
03444                                 break;
03445                         case 6:
03446                                 make_ui_sound("UISndPieMenuSliceHighlight6");
03447                                 break;
03448                         case 7:
03449                                 make_ui_sound("UISndPieMenuSliceHighlight7");
03450                                 break;
03451                         default:
03452                                 make_ui_sound("UISndPieMenuSliceHighlight0");
03453                                 break;
03454                         }
03455                 }
03456                 mHoveredAnyItem = TRUE;
03457         }
03458         else
03459         {
03460                 // clear out our selection
03461                 if (mHoverItem)
03462                 {
03463                         mHoverItem->setHighlight(FALSE);
03464                         mHoverItem = NULL;
03465                 }
03466         }
03467 
03468         if( !handled && pointInView( x, y ) )
03469         {
03470                 getWindow()->setCursor(UI_CURSOR_ARROW);
03471                 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;              
03472                 handled = TRUE;
03473         }
03474 
03475         mHoverThisFrame = TRUE;
03476 
03477         return handled;
03478 }
03479 
03480 BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask )
03481 {
03482         BOOL handled = FALSE;
03483         // The click was somewhere within our rectangle
03484         LLMenuItemGL *item = pieItemFromXY( x, y );
03485 
03486         if (item)
03487         {
03488                 // lie to the item about where the click happened
03489                 // to make sure it's within the item's rectangle
03490                 handled = item->handleMouseDown( 0, 0, mask );
03491         }
03492         else if (!mRightMouseDown)
03493         {
03494                 // call hidemenus to make sure transient selections get cleared
03495                 ((LLMenuHolderGL*)getParent())->hideMenus();
03496         }
03497 
03498         // always handle mouse down as mouse up will close open menus
03499         return handled;
03500 }
03501 
03502 BOOL LLPieMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
03503 {
03504         BOOL handled = FALSE;
03505 
03506         mRightMouseDown = TRUE;
03507 
03508         // The click was somewhere within our rectangle
03509         LLMenuItemGL *item = pieItemFromXY( x, y );
03510         S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
03511         S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
03512         BOOL clicked_in_pie = ((delta_x * delta_x) + (delta_y * delta_y) < mCurRadius*mCurRadius) || mUseInfiniteRadius;
03513 
03514         // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
03515         if (clicked_in_pie)
03516         {
03517                 // capture mouse cursor as if on initial menu show
03518                 gFocusMgr.setMouseCapture(this);
03519                 mShrinkBorderTimer.stop();
03520                 mUseInfiniteRadius = TRUE;
03521                 handled = TRUE;
03522         }
03523         
03524         if (item)
03525         {
03526                 // lie to the item about where the click happened
03527                 // to make sure it's within the item's rectangle
03528                 if (item->handleMouseDown( 0, 0, mask ))
03529                 {
03530                         handled = TRUE;
03531                 }
03532         }
03533 
03534         return handled;
03535 }
03536 
03537 BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
03538 {
03539         // release mouse capture when right mouse button released, and we're past the shrink time
03540         if (mShrinkBorderTimer.getStarted() && 
03541                 mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME)
03542         {
03543                 mUseInfiniteRadius = FALSE;
03544                 gFocusMgr.setMouseCapture(NULL);
03545         }
03546 
03547         S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
03548         S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
03549         if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE)
03550         {
03551                 // user released right mouse button in middle of pie, interpret this as closing the menu
03552                 sMenuContainer->hideMenus();
03553                 return TRUE;
03554         }
03555 
03556 
03557         BOOL result = handleMouseUp( x, y, mask );
03558         mRightMouseDown = FALSE;
03559         mHoveredAnyItem = FALSE;
03560 
03561         return result;
03562 }
03563 
03564 BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask )
03565 {
03566         BOOL handled = FALSE;
03567 
03568         // The click was somewhere within our rectangle
03569         LLMenuItemGL *item = pieItemFromXY( x, y );
03570 
03571         if (item)
03572         {
03573                 // lie to the item about where the click happened
03574                 // to make sure it's within the item's rectangle
03575                 if (item->getEnabled())
03576                 {
03577                         handled = item->handleMouseUp( 0, 0, mask );
03578                         hide(TRUE);
03579                 }
03580         }
03581         else if (!mRightMouseDown)
03582         {
03583                 // call hidemenus to make sure transient selections get cleared
03584                 ((LLMenuHolderGL*)getParent())->hideMenus();
03585         }
03586 
03587         if (handled)
03588         {
03589                 make_ui_sound("UISndClickRelease");
03590         }
03591 
03592         if (!handled && !mUseInfiniteRadius)
03593         {
03594                 // call hidemenus to make sure transient selections get cleared
03595                 sMenuContainer->hideMenus();
03596         }
03597 
03598         if (mFirstMouseDown)
03599         {
03600                 make_ui_sound("UISndPieMenuAppear");
03601                 mFirstMouseDown = FALSE;
03602         }
03603         
03604         // *FIX: is this necessary?
03605         if (!mShrinkBorderTimer.getStarted())
03606         {
03607                 mShrinkBorderTimer.start();
03608         }
03609 
03610         return handled;
03611 }
03612 
03613 
03614 // virtual
03615 void LLPieMenu::draw()
03616 {
03617         // clear hover if mouse moved away
03618         if (!mHoverThisFrame && mHoverItem)
03619         {
03620                 mHoverItem->setHighlight(FALSE);
03621                 mHoverItem = NULL;
03622         }
03623 
03624         F32 width = (F32) mRect.getWidth();
03625         F32 height = (F32) mRect.getHeight();
03626         mCurRadius = PIE_SCALE_FACTOR * llmax( width/2, height/2 );
03627 
03628         mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f;
03629         if (mShrinkBorderTimer.getStarted())
03630         {
03631                 mOuterRingAlpha = clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 0.f, 1.f);
03632                 mCurRadius *= clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR);
03633         }
03634 
03635         // correct for non-square pixels
03636         F32 center_x = width/2;
03637         F32 center_y = height/2;
03638         S32 steps = 100;
03639 
03640         glPushMatrix();
03641         {
03642                 glTranslatef(center_x, center_y, 0.f);
03643 
03644                 F32 line_width = LLUI::sConfigGroup->getF32("PieMenuLineWidth");
03645                 LLColor4 line_color = LLUI::sColorsGroup->getColor("PieMenuLineColor");
03646                 LLColor4 bg_color = LLUI::sColorsGroup->getColor("PieMenuBgColor");
03647                 LLColor4 selected_color = LLUI::sColorsGroup->getColor("PieMenuSelectedColor");
03648 
03649                 // main body
03650                 LLColor4 outer_color = bg_color;
03651                 outer_color.mV[VALPHA] *= mOuterRingAlpha;
03652                 gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color );
03653 
03654                 // selected wedge
03655                 item_list_t::iterator item_iter;
03656                 S32 i = 0;
03657                 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
03658                 {
03659                         if ((*item_iter)->getHighlight())
03660                         {
03661                                 F32 arc_size = F_PI * 0.25f;
03662 
03663                                 F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
03664                                 F32 end_radians = start_radians + arc_size;
03665 
03666                                 LLColor4 outer_color = selected_color;
03667                                 outer_color.mV[VALPHA] *= mOuterRingAlpha;
03668                                 gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
03669                         }
03670                         i++;
03671                 }
03672 
03673                 LLUI::setLineWidth( line_width );
03674 
03675                 // inner lines
03676                 outer_color = line_color;
03677                 outer_color.mV[VALPHA] *= mOuterRingAlpha;
03678                 gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color );
03679 
03680                 // inner circle
03681                 glColor4fv( line_color.mV );
03682                 gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE );
03683 
03684                 // outer circle
03685                 glColor4fv( outer_color.mV );
03686                 gl_circle_2d( 0, 0, mCurRadius, steps, FALSE );
03687 
03688                 LLUI::setLineWidth(1.0f);
03689         }
03690         glPopMatrix();
03691 
03692         mHoverThisFrame = FALSE;
03693 
03694         LLView::draw();
03695 }
03696 
03697 void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
03698 {
03699         F32 width = (F32) mRect.getWidth();
03700         F32 height = (F32) mRect.getHeight();
03701         F32 center_x = width/2;
03702         F32 center_y = height/2;
03703         S32 steps = 100;
03704 
03705         glColor4fv( color.mV );
03706         glPushMatrix();
03707         {
03708                 glTranslatef(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
03709 
03710                 item_list_t::iterator item_iter;
03711                 S32 i = 0;
03712                 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
03713                 {
03714                         if ((*item_iter) == itemp)
03715                         {
03716                                 F32 arc_size = F_PI * 0.25f;
03717 
03718                                 F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
03719                                 F32 end_radians = start_radians + arc_size;
03720 
03721                                 LLColor4 outer_color = color;
03722                                 outer_color.mV[VALPHA] *= mOuterRingAlpha;
03723                                 gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color );
03724                         }
03725                         i++;
03726                 }
03727         }
03728         glPopMatrix();
03729 }
03730 
03731 // virtual
03732 BOOL LLPieMenu::append(LLMenuItemGL *item)
03733 {
03734         item->setBriefItem(TRUE);
03735         item->setFont( LLFontGL::sSansSerifSmall );
03736         return LLMenuGL::append(item);
03737 }
03738 
03739 // virtual
03740 BOOL LLPieMenu::appendSeparator(const LLString &separator_name)
03741 {
03742         LLMenuItemGL* separator = new LLMenuItemBlankGL();
03743         separator->setFont( LLFontGL::sSansSerifSmall );
03744         return append( separator );
03745 }
03746 
03747 
03748 // virtual
03749 BOOL LLPieMenu::appendMenu(LLPieMenu *menu,
03750                                                    enabled_callback enabled_cb,
03751                                                    void* user_data)
03752 {
03753         if (menu == this)
03754         {
03755                 llerrs << "Can't attach a pie menu to itself" << llendl;
03756         }
03757         LLPieMenuBranch *item;
03758         item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu, enabled_cb, user_data);
03759         getParent()->addChild(item->getBranch());
03760         item->setFont( LLFontGL::sSansSerifSmall );
03761         return append( item );
03762 }
03763 
03764 // virtual
03765 void LLPieMenu::arrange()
03766 {
03767         const S32 rect_height = 180;
03768         const S32 rect_width = 180;
03769 
03770         // all divide by 6
03771         const S32 CARD_X = 60;
03772         const S32 DIAG_X = 48;
03773         const S32 CARD_Y = 76;
03774         const S32 DIAG_Y = 42;
03775 
03776         const S32 ITEM_CENTER_X[] = { CARD_X, DIAG_X,      0, -DIAG_X, -CARD_X, -DIAG_X,       0,  DIAG_X };
03777         const S32 ITEM_CENTER_Y[] = {      0, DIAG_Y, CARD_Y,  DIAG_Y,       0, -DIAG_Y, -CARD_Y, -DIAG_Y };
03778 
03779         LLRect rect;
03780         
03781         S32 font_height = 0;
03782         if( mItems.size() )
03783         {
03784                 font_height = (*mItems.begin())->getNominalHeight();
03785         }
03786         S32 item_width = 0;
03787 
03788 //      F32 sin_delta = OO_SQRT2;       // sin(45 deg)
03789 //      F32 cos_delta = OO_SQRT2;       // cos(45 deg)
03790 
03791         // TODO: Compute actual bounding rect for menu
03792 
03793         mRect.setOriginAndSize(mRect.mLeft, mRect.mBottom, rect_width, rect_height );
03794 
03795         // place items around a circle, with item 0 at positive X,
03796         // rotating counter-clockwise
03797         item_list_t::iterator item_iter;
03798         S32 i = 0;
03799         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
03800         {
03801                 LLMenuItemGL *item = *item_iter;
03802 
03803                 item_width = item->getNominalWidth();
03804 
03805                 // Put in the right place around a circle centered at 0,0
03806                 rect.setCenterAndSize(ITEM_CENTER_X[i],
03807                                                           ITEM_CENTER_Y[i], 
03808                                                           item_width, font_height );
03809 
03810                 // Correct for the actual rectangle size
03811                 rect.translate( rect_width/2, rect_height/2 );
03812 
03813                 item->setRect( rect );
03814 
03815                 // Make sure enablement is correct
03816                 item->buildDrawLabel();
03817                 i++;
03818         }
03819 }
03820 
03821 LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
03822 {
03823         // We might have shifted this menu on draw.  If so, we need
03824         // to shift over mouseup events until we get a hover event.
03825         //x += mShiftHoriz;
03826         //y += mShiftVert; 
03827 
03828         // An arc of the pie menu is 45 degrees
03829         const F32 ARC_DEG = 45.f;
03830         S32 delta_x = x - mRect.getWidth() / 2;
03831         S32 delta_y = y - mRect.getHeight() / 2;
03832 
03833         // circle safe zone in the center
03834         S32 dist_squared = delta_x*delta_x + delta_y*delta_y;
03835         if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
03836         {
03837                 return NULL;
03838         }
03839 
03840         // infinite radius is only used with right clicks
03841         S32 radius = llmax( mRect.getWidth()/2, mRect.getHeight()/2 );
03842         if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius)
03843         {
03844                 return NULL;
03845         }
03846 
03847         F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
03848         
03849         // rotate marks CCW so that east = [0, ARC_DEG) instead of
03850         // [-ARC_DEG/2, ARC_DEG/2)
03851         angle += ARC_DEG / 2.f;
03852 
03853         // make sure we're only using positive angles
03854         if (angle < 0.f) angle += 360.f;
03855 
03856         S32 which = S32( angle / ARC_DEG );
03857 
03858         if (0 <= which && which < (S32)mItems.size() )
03859         {
03860                 item_list_t::iterator item_iter;
03861                 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
03862                 {
03863                         if (which == 0)
03864                         {
03865                                 return (*item_iter);
03866                         }
03867                         which--;
03868                 }
03869         }
03870 
03871         return NULL;
03872 }
03873 
03874 S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
03875 {
03876         // An arc of the pie menu is 45 degrees
03877         const F32 ARC_DEG = 45.f;
03878         // correct for non-square pixels
03879         S32 delta_x = x - mRect.getWidth() / 2;
03880         S32 delta_y = y - mRect.getHeight() / 2;
03881 
03882         // circle safe zone in the center
03883         if (delta_x*delta_x + delta_y*delta_y < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
03884         {
03885                 return -1;
03886         }
03887 
03888         F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
03889         
03890         // rotate marks CCW so that east = [0, ARC_DEG) instead of
03891         // [-ARC_DEG/2, ARC_DEG/2)
03892         angle += ARC_DEG / 2.f;
03893 
03894         // make sure we're only using positive angles
03895         if (angle < 0.f) angle += 360.f;
03896 
03897         S32 which = S32( angle / ARC_DEG );
03898         return which;
03899 }
03900 
03901 void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
03902 {
03903         S32 width = mRect.getWidth();
03904         S32 height = mRect.getHeight();
03905 
03906         const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
03907 
03908         LLView* parent_view = getParent();
03909         BOOL moved = FALSE;
03910 
03911         S32 local_x, local_y;
03912         parent_view->screenPointToLocal(x, y, &local_x, &local_y);
03913 
03914         mRect.setCenterAndSize(local_x, local_y, width, height);
03915         arrange();
03916 
03917         // Adjust the pie rectangle to keep it on screen
03918         if (mRect.mLeft < menu_region_rect.mLeft) 
03919         {
03920                 //mShiftHoriz = menu_region_rect.mLeft - mRect.mLeft;
03921                 //mRect.translate( mShiftHoriz, 0 );
03922                 mRect.translate( menu_region_rect.mLeft - mRect.mLeft, 0 );
03923                 moved = TRUE;
03924         }
03925 
03926         if (mRect.mRight > menu_region_rect.mRight) 
03927         {
03928                 //mShiftHoriz = menu_region_rect.mRight - mRect.mRight;
03929                 //mRect.translate( mShiftHoriz, 0);
03930                 mRect.translate( menu_region_rect.mRight - mRect.mRight, 0 );
03931                 moved = TRUE;
03932         }
03933 
03934         if (mRect.mBottom < menu_region_rect.mBottom)
03935         {
03936                 //mShiftVert = menu_region_rect.mBottom - mRect.mBottom;
03937                 //mRect.translate( 0, mShiftVert );
03938                 mRect.translate( 0, menu_region_rect.mBottom - mRect.mBottom );
03939                 moved = TRUE;
03940         }
03941 
03942 
03943         if (mRect.mTop > menu_region_rect.mTop)
03944         {
03945                 //mShiftVert = menu_region_rect.mTop - mRect.mTop;
03946                 //mRect.translate( 0, mShiftVert );
03947                 mRect.translate( 0, menu_region_rect.mTop - mRect.mTop );
03948                 moved = TRUE;
03949         }
03950 
03951         // If we had to relocate the pie menu, put the cursor in the
03952         // center of its rectangle
03953         if (moved)
03954         {
03955                 LLCoordGL center;
03956                 center.mX = (mRect.mLeft + mRect.mRight) / 2;
03957                 center.mY = (mRect.mTop + mRect.mBottom) / 2;
03958 
03959                 LLUI::setCursorPositionLocal(getParent(), center.mX, center.mY);
03960         }
03961 
03962         // *FIX: what happens when mouse buttons reversed?
03963         mRightMouseDown = mouse_down;
03964         mFirstMouseDown = mouse_down;
03965         mUseInfiniteRadius = TRUE;
03966         mHoveredAnyItem = FALSE;
03967 
03968         if (!mFirstMouseDown)
03969         {
03970                 make_ui_sound("UISndPieMenuAppear");
03971         }
03972 
03973         LLView::setVisible(TRUE);
03974 
03975         // we want all mouse events in case user does quick right click again off of pie menu
03976         // rectangle, to support gestural menu traversal
03977         gFocusMgr.setMouseCapture(this);
03978 
03979         if (mouse_down)
03980         {
03981                 mShrinkBorderTimer.stop();
03982         }
03983         else 
03984         {
03985                 mShrinkBorderTimer.start();
03986         }
03987 }
03988 
03989 void LLPieMenu::hide(BOOL item_selected)
03990 {
03991         if (!getVisible()) return;
03992 
03993         if (mHoverItem)
03994         {
03995                 mHoverItem->setHighlight( FALSE );
03996                 mHoverItem = NULL;
03997         }
03998 
03999         make_ui_sound("UISndPieMenuHide");
04000 
04001         mFirstMouseDown = FALSE;
04002         mRightMouseDown = FALSE;
04003         mUseInfiniteRadius = FALSE;
04004         mHoveredAnyItem = FALSE;
04005 
04006         LLView::setVisible(FALSE);
04007 
04008         gFocusMgr.setMouseCapture(NULL);
04009 }
04010 
04014 
04015 // Default constructor
04016 LLMenuBarGL::LLMenuBarGL( const LLString& name ) : LLMenuGL ( name, name )
04017 {
04018         mHorizontalLayout = TRUE;
04019         setCanTearOff(FALSE);
04020         mKeepFixedSize = TRUE;
04021         mAltKeyTrigger = FALSE;
04022 }
04023 
04024 // Default destructor
04025 LLMenuBarGL::~LLMenuBarGL()
04026 {
04027         std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer());
04028         mAccelerators.clear();
04029 }
04030 
04031 // virtual
04032 LLXMLNodePtr LLMenuBarGL::getXML(bool save_children) const
04033 {
04034         // Sorty of hacky: reparent items to this and then back at the end of the export
04035         LLView *orig_parent = NULL;
04036         item_list_t::const_iterator item_iter;
04037         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
04038         {
04039                 LLMenuItemGL* child = *item_iter;
04040                 LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child;
04041                 LLMenuGL *menu = branch->getBranch();
04042                 orig_parent = menu->getParent();
04043                 menu->updateParent((LLView *)this);
04044         }
04045 
04046         LLXMLNodePtr node = LLMenuGL::getXML();
04047 
04048         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
04049         {
04050                 LLMenuItemGL* child = *item_iter;
04051                 LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child;
04052                 LLMenuGL *menu = branch->getBranch();
04053                 menu->updateParent(orig_parent);
04054         }
04055 
04056         return node;
04057 }
04058 
04059 LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
04060 {
04061         LLString name("menu");
04062         node->getAttributeString("name", name);
04063 
04064         BOOL opaque = FALSE;
04065         node->getAttributeBOOL("opaque", opaque);
04066 
04067         LLMenuBarGL *menubar = new LLMenuBarGL(name);
04068 
04069         LLViewHandle parent_handle = LLViewHandle::sDeadHandle;
04070         if (parent->getWidgetType() == WIDGET_TYPE_FLOATER)
04071         {
04072                 parent_handle = ((LLFloater*)parent)->getHandle();
04073         }
04074 
04075         // We need to have the rect early so that it's around when building
04076         // the menu items
04077         LLRect view_rect;
04078         createRect(node, view_rect, parent, menubar->getRequiredRect());
04079         menubar->setRect(view_rect);
04080 
04081         if (node->hasAttribute("drop_shadow"))
04082         {
04083                 BOOL drop_shadow = FALSE;
04084                 node->getAttributeBOOL("drop_shadow", drop_shadow);
04085                 menubar->setDropShadowed(drop_shadow);
04086         }
04087 
04088         menubar->setBackgroundVisible(opaque);
04089         LLColor4 color(0,0,0,0);
04090         if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
04091         {
04092                 menubar->setBackgroundColor(color);
04093         }
04094 
04095         LLXMLNodePtr child;
04096         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
04097         {
04098                 if (child->hasName("menu"))
04099                 {
04100                         LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory);
04101                         // because of lazy initialization, have to disable tear off functionality
04102                         // and then re-enable with proper parent handle
04103                         if (menu->getCanTearOff())
04104                         {
04105                                 menu->setCanTearOff(FALSE);
04106                                 menu->setCanTearOff(TRUE, parent_handle);
04107                         }
04108                         menubar->appendMenu(menu);
04109                         if (LLMenuGL::sMenuContainer != NULL)
04110                         {
04111                                 menu->updateParent(LLMenuGL::sMenuContainer);
04112                         }
04113                         else
04114                         {
04115                                 menu->updateParent(parent);
04116                         }
04117                 }
04118         }
04119 
04120         menubar->initFromXML(node, parent);
04121 
04122         BOOL create_jump_keys = FALSE;
04123         node->getAttributeBOOL("create_jump_keys", create_jump_keys);
04124         if (create_jump_keys)
04125         {
04126                 menubar->createJumpKeys();
04127         }
04128 
04129         return menubar;
04130 }
04131 
04132 BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
04133 {
04134         if (getHighlightedItem() && mask == MASK_NONE)
04135         {
04136                 // unmodified key accelerators are ignored when navigating menu
04137                 // (but are used as jump keys so will still work when appropriate menu is up)
04138                 return FALSE;
04139         }
04140         BOOL result = LLMenuGL::handleAcceleratorKey(key, mask);
04141         if (result && mask & MASK_ALT)
04142         {
04143                 // ALT key used to trigger hotkey, don't use as shortcut to open menu
04144                 mAltKeyTrigger = FALSE;
04145         }
04146 
04147         if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key))
04148         {
04149                 if (getHighlightedItem())
04150                 {
04151                         clearHoverItem();
04152                 }
04153                 else
04154                 {
04155                         highlightNextItem(NULL);
04156                         LLMenuGL::setKeyboardMode(TRUE);
04157                 }
04158                 return TRUE;
04159         }
04160 
04161         return result;
04162 }
04163 
04164 BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
04165 {
04166         if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && LLUI::sConfigGroup->getBOOL("UseAltKeyForMenus"))
04167         {
04168                 mAltKeyTrigger = TRUE;
04169         }
04170         else // if any key other than ALT hit, clear out waiting for Alt key mode
04171         {
04172                 mAltKeyTrigger = FALSE;
04173         }
04174 
04175         // before processing any other key, check to see if ALT key has triggered menu access
04176         checkMenuTrigger();
04177 
04178         return LLMenuGL::handleKeyHere(key, mask, called_from_parent);
04179 }
04180 
04181 BOOL LLMenuBarGL::handleJumpKey(KEY key)
04182 {
04183         // perform case-insensitive comparison
04184         key = toupper(key);
04185         navigation_key_map_t::iterator found_it = mJumpKeys.find(key);
04186         if(found_it != mJumpKeys.end() && found_it->second->getEnabled())
04187         {
04188                 // switch to keyboard navigation mode
04189                 LLMenuGL::setKeyboardMode(TRUE);
04190 
04191                 found_it->second->setHighlight(TRUE);
04192                 found_it->second->doIt();
04193         }
04194         return TRUE;
04195 }
04196 
04197 void LLMenuBarGL::draw()
04198 {
04199         LLMenuItemGL* itemp = getHighlightedItem();
04200         // If we are in mouse-control mode and the mouse cursor is not hovering over
04201         // the current highlighted menu item and it isn't open, then remove the highlight.
04202         // This is done via a polling mechanism here, as we don't receive notifications when
04203         // the mouse cursor moves off of us
04204         if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode())
04205         {
04206                 clearHoverItem();
04207         }
04208 
04209         checkMenuTrigger();
04210 
04211         LLMenuGL::draw();
04212 }
04213 
04214 void LLMenuBarGL::checkMenuTrigger()
04215 {
04216         // has the ALT key been pressed and subsequently released?
04217         if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT))
04218         {
04219                 // if alt key was released quickly, treat it as a menu access key
04220                 // otherwise it was probably an Alt-zoom or similar action
04221                 if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= LLUI::sConfigGroup->getF32("MenuAccessKeyTime") ||
04222                         gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2)
04223                 {
04224                         if (getHighlightedItem())
04225                         {
04226                                 clearHoverItem();
04227                         }
04228                         else
04229                         {
04230                                 highlightNextItem(NULL);
04231                                 LLMenuGL::setKeyboardMode(TRUE);
04232                         }
04233                 }
04234                 mAltKeyTrigger = FALSE;
04235         }
04236 }
04237 
04238 BOOL LLMenuBarGL::jumpKeysActive()
04239 {
04240         // require user to be in keyboard navigation mode to activate key triggers
04241         // as menu bars are always visible and it is easy to leave the mouse cursor over them
04242         return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive();
04243 }
04244 
04245 // rearrange the child rects so they fit the shape of the menu bar.
04246 void LLMenuBarGL::arrange( void )
04247 {
04248         U32 pos = 0;
04249         LLRect rect( 0, mRect.getHeight(), 0, 0 );
04250         item_list_t::const_iterator item_iter;
04251         for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
04252         {
04253                 LLMenuItemGL* item = *item_iter;
04254                 if (item->getVisible())
04255                 {
04256                         rect.mLeft = pos;
04257                         pos += item->getNominalWidth();
04258                         rect.mRight = pos;
04259                         item->setRect( rect );
04260                         item->buildDrawLabel();
04261                 }
04262         }
04263         reshape(rect.mRight, rect.getHeight());
04264 }
04265 
04266 
04267 S32 LLMenuBarGL::getRightmostMenuEdge()
04268 {
04269         // Find the last visible menu
04270         item_list_t::reverse_iterator item_iter;
04271         for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter)
04272         {
04273                 if ((*item_iter)->getVisible())
04274                 {
04275                         break;
04276                 }
04277         }
04278 
04279         if (item_iter == mItems.rend())
04280         {
04281                 return 0;
04282         }
04283         return (*item_iter)->getRect().mRight;
04284 }
04285 
04286 // add a vertical separator to this menu
04287 BOOL LLMenuBarGL::appendSeparator( const LLString &separator_name )
04288 {
04289         LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL();
04290         return append( separator );
04291 }
04292 
04293 // add a menu - this will create a drop down menu.
04294 BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu )
04295 {
04296         if( menu == this )
04297         {
04298                 llerrs << "** Attempt to attach menu to itself. This is certainly "
04299                            << "a logic error." << llendl;
04300         }
04301 
04302         BOOL success = TRUE;
04303 
04304         LLMenuItemBranchGL* branch = NULL;
04305         branch = new LLMenuItemBranchDownGL( menu->getName(), menu->getLabel(), menu );
04306         success &= branch->addToAcceleratorList(&mAccelerators);
04307         success &= append( branch );
04308         branch->setJumpKey(branch->getJumpKey());
04309         return success;
04310 }
04311 
04312 BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
04313 {
04314         BOOL handled = FALSE;
04315         LLView* active_menu = NULL;
04316 
04317         BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0;
04318         S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX;
04319         S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY;
04320         mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2);
04321         mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2);
04322         mLastMouseX = x;
04323         mLastMouseY = y;
04324 
04325         // if nothing currently selected or mouse has moved since last call, pick menu item via mouse
04326         // otherwise let keyboard control it
04327         if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0)
04328         {
04329                 // find current active menu
04330                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
04331                 {
04332                         LLView* viewp = *child_it;
04333                         if (((LLMenuItemGL*)viewp)->isOpen())
04334                         {
04335                                 active_menu = viewp;
04336                         }
04337                 }
04338 
04339                 // check for new active menu
04340                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
04341                 {
04342                         LLView* viewp = *child_it;
04343                         S32 local_x = x - viewp->getRect().mLeft;
04344                         S32 local_y = y - viewp->getRect().mBottom;
04345                         if( viewp->getVisible() && 
04346                                 viewp->getEnabled() &&
04347                                 viewp->pointInView(local_x, local_y) && 
04348                                 viewp->handleHover(local_x, local_y, mask))
04349                         {
04350                                 ((LLMenuItemGL*)viewp)->setHighlight(TRUE);
04351                                 handled = TRUE;
04352                                 if (active_menu && active_menu != viewp)
04353                                 {
04354                                         ((LLMenuItemGL*)viewp)->doIt();
04355                                         LLMenuGL::setKeyboardMode(FALSE);
04356                                 }
04357                                 LLMenuGL::setKeyboardMode(FALSE);
04358                         }
04359                 }
04360 
04361                 if (handled)
04362                 {
04363                         // set hover false on inactive menus
04364                         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
04365                         {
04366                                 LLView* viewp = *child_it;
04367                                 S32 local_x = x - viewp->getRect().mLeft;
04368                                 S32 local_y = y - viewp->getRect().mBottom;
04369                                 if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight())
04370                                 {
04371                                         ((LLMenuItemGL*)viewp)->setHighlight(FALSE);
04372                                 }
04373                         }
04374                 }
04375         }
04376 
04377         getWindow()->setCursor(UI_CURSOR_ARROW);
04378         
04379         return TRUE;
04380 }
04381 
04385 LLMenuHolderGL::LLMenuHolderGL()
04386 :       LLPanel("Menu Holder")
04387 {
04388         setMouseOpaque(FALSE);
04389         sItemActivationTimer.stop();
04390         mCanHide = TRUE;
04391 }
04392 
04393 LLMenuHolderGL::LLMenuHolderGL(const LLString& name, const LLRect& rect, BOOL mouse_opaque, U32 follows) 
04394 :       LLPanel(name, rect, FALSE)
04395 {
04396         setMouseOpaque(mouse_opaque);
04397         sItemActivationTimer.stop();
04398         mCanHide = TRUE;
04399 }
04400 
04401 LLMenuHolderGL::~LLMenuHolderGL()
04402 {
04403 }
04404 
04405 EWidgetType LLMenuHolderGL::getWidgetType() const
04406 {
04407         return WIDGET_TYPE_MENU_HOLDER;
04408 }
04409 
04410 LLString LLMenuHolderGL::getWidgetTag() const
04411 {
04412         return LL_MENU_HOLDER_GL_TAG;
04413 }
04414 
04415 void LLMenuHolderGL::draw()
04416 {
04417         LLView::draw();
04418         // now draw last selected item as overlay
04419         LLMenuItemGL* selecteditem = (LLMenuItemGL*)LLView::getViewByHandle(sItemLastSelectedHandle);
04420         if (selecteditem && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME)
04421         {
04422                 // make sure toggle items, for example, show the proper state when fading out
04423                 selecteditem->buildDrawLabel();
04424 
04425                 LLRect item_rect;
04426                 selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this);
04427 
04428                 F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME;
04429                 F32 alpha = lerp(LLMenuItemGL::sHighlightBackground.mV[VALPHA], 0.f, interpolant);
04430                 LLColor4 bg_color(LLMenuItemGL::sHighlightBackground.mV[VRED], 
04431                         LLMenuItemGL::sHighlightBackground.mV[VGREEN], 
04432                         LLMenuItemGL::sHighlightBackground.mV[VBLUE], 
04433                         alpha);
04434                 
04435                 LLUI::pushMatrix();
04436                 {
04437                         LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f);
04438                         selecteditem->getMenu()->drawBackground(selecteditem, bg_color);
04439                         selecteditem->draw();
04440                 }
04441                 LLUI::popMatrix();
04442         }
04443 }
04444 
04445 BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask )
04446 {
04447         BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
04448         if (!handled)
04449         {
04450                 // clicked off of menu, hide them all
04451                 hideMenus();
04452         }
04453         return handled;
04454 }
04455 
04456 BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask )
04457 {
04458         BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL;
04459         if (!handled)
04460         {
04461                 // clicked off of menu, hide them all
04462                 hideMenus();
04463         }
04464         return handled;
04465 }
04466 
04467 void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent)
04468 {
04469         if (width != mRect.getWidth() || height != mRect.getHeight())
04470         {
04471                 hideMenus();
04472         }
04473         LLView::reshape(width, height, called_from_parent);
04474 }
04475 
04476 BOOL LLMenuHolderGL::hasVisibleMenu() const
04477 {
04478         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
04479         {
04480                 LLView* viewp = *child_it;
04481                 if (viewp->getVisible() && viewp->getWidgetType() != WIDGET_TYPE_MENU_BAR)
04482                 {
04483                         return TRUE;
04484                 }
04485         }
04486         return FALSE;
04487 }
04488 
04489 const LLRect LLMenuHolderGL::getMenuRect() const
04490 {
04491         return getLocalRect();
04492 }
04493 
04494 BOOL LLMenuHolderGL::hideMenus()
04495 {
04496         if (!mCanHide)
04497         {
04498                 return FALSE;
04499         }
04500         BOOL menu_visible = hasVisibleMenu();
04501         if (menu_visible)
04502         {
04503                 LLMenuGL::setKeyboardMode(FALSE);
04504                 // clicked off of menu, hide them all
04505                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
04506                 {
04507                         LLView* viewp = *child_it;
04508                         // clicks off of menu do not hide menu bar
04509                         if (viewp->getWidgetType() != WIDGET_TYPE_MENU_BAR && viewp->getVisible())
04510                         {
04511                                 viewp->setVisible(FALSE);
04512                         }
04513                 }
04514         }
04515         //if (gFocusMgr.childHasKeyboardFocus(this))
04516         //{
04517         //      gFocusMgr.setKeyboardFocus(NULL, NULL);
04518         //}
04519 
04520         return menu_visible;
04521 }
04522 
04523 void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
04524 {
04525         sItemLastSelectedHandle = item->mViewHandle;
04526         sItemActivationTimer.start();
04527 }
04528 
04532 LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : 
04533         LLFloater(menup->getName(), LLRect(0, 100, 100, 0), menup->getLabel(), FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, FALSE)
04534 {
04535         LLRect rect;
04536         menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView);
04537         mTargetHeight = (F32)(rect.getHeight() + LLFLOATER_HEADER_SIZE + 5);
04538         reshape(rect.getWidth(), rect.getHeight());
04539         setRect(rect);
04540         mOldParent = menup->getParent();
04541         mOldParent->removeChild(menup);
04542 
04543         menup->setFollowsAll();
04544         addChild(menup);
04545         menup->setVisible(TRUE);
04546         menup->translate(-menup->getRect().mLeft + 1, -menup->getRect().mBottom + 1);
04547 
04548         menup->setTornOff(TRUE);
04549         menup->setDropShadowed(FALSE);
04550 
04551         mMenu = menup;
04552 
04553         // highlight first item (tear off item will be disabled)
04554         mMenu->highlightNextItem(NULL);
04555 }
04556 
04557 LLTearOffMenu::~LLTearOffMenu()
04558 {
04559 }
04560 
04561 void LLTearOffMenu::draw()
04562 {
04563         mMenu->setBackgroundVisible(mBgOpaque);
04564         mMenu->arrange();
04565 
04566         if (mRect.getHeight() != mTargetHeight)
04567         {
04568                 // animate towards target height
04569                 reshape(mRect.getWidth(), llceil(lerp((F32)mRect.getHeight(), mTargetHeight, LLCriticalDamp::getInterpolant(0.05f))));
04570         }
04571         else
04572         {
04573                 // when in stasis, remain big enough to hold menu contents
04574                 mTargetHeight = (F32)(mMenu->getRect().getHeight() + LLFLOATER_HEADER_SIZE + 4);
04575                 reshape(mMenu->getRect().getWidth() + 3, mMenu->getRect().getHeight() + LLFLOATER_HEADER_SIZE + 5);
04576         }
04577         LLFloater::draw();
04578 }
04579 
04580 void LLTearOffMenu::onFocusReceived()
04581 {
04582         // if nothing is highlighted, just highlight first item
04583         if (!mMenu->getHighlightedItem())
04584         {
04585                 mMenu->highlightNextItem(NULL);
04586         }
04587 
04588         // parent menu items get highlights so navigation logic keeps working
04589         LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem();
04590         while(parent_menu_item)
04591         {
04592                 if (parent_menu_item->getMenu()->getVisible())
04593                 {
04594                         parent_menu_item->setHighlight(TRUE);
04595                         parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem();
04596                 }
04597                 else
04598                 {
04599                         break;
04600                 }
04601         }
04602 }
04603 
04604 void LLTearOffMenu::onFocusLost()
04605 {
04606         // remove highlight from parent item and our own menu
04607         mMenu->clearHoverItem();
04608         LLFloater::onFocusLost();
04609 }
04610 
04611 BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
04612 {
04613         // pass keystrokes down to menu
04614         return mMenu->handleUnicodeChar(uni_char, TRUE);
04615 }
04616 
04617 BOOL LLTearOffMenu::handleKey(KEY key, MASK mask, BOOL called_from_parent)
04618 {
04619         if (!mMenu->getHighlightedItem())
04620         {
04621                 if (key == KEY_UP)
04622                 {
04623                         mMenu->highlightPrevItem(NULL);         
04624                         return TRUE;
04625                 }
04626                 else if (key == KEY_DOWN)
04627                 {
04628                         mMenu->highlightNextItem(NULL);
04629                         return TRUE;
04630                 }
04631         }
04632         // pass keystrokes down to menu
04633         return mMenu->handleKey(key, mask, TRUE);
04634 }
04635 
04636 void LLTearOffMenu::translate(S32 x, S32 y)
04637 {
04638         if (x != 0 && y != 0)
04639         {
04640                 // hide open sub-menus by clearing current hover item
04641                 mMenu->clearHoverItem();
04642         }
04643         LLFloater::translate(x, y);
04644 }
04645 
04646 //static
04647 LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
04648 {
04649         LLTearOffMenu* tearoffp = new LLTearOffMenu(menup);
04650         // keep onscreen
04651         gFloaterView->adjustToFitScreen(tearoffp, FALSE);
04652         tearoffp->open();       /* Flawfinder: ignore */
04653         return tearoffp;
04654 }
04655 
04656 void LLTearOffMenu::onClose(bool app_quitting)
04657 {
04658         removeChild(mMenu);
04659         mOldParent->addChild(mMenu);
04660         mMenu->clearHoverItem();
04661         mMenu->setFollowsNone();
04662         mMenu->setBackgroundVisible(TRUE);
04663         mMenu->setVisible(FALSE);
04664         mMenu->setTornOff(FALSE);
04665         mMenu->setDropShadowed(TRUE);
04666         destroy();
04667 }
04668 
04672 LLEditMenuHandlerMgr& LLEditMenuHandlerMgr::getInstance()
04673 {
04674         static LLEditMenuHandlerMgr instance;
04675         return instance;
04676 }
04677 
04678 LLEditMenuHandlerMgr::LLEditMenuHandlerMgr()
04679 {
04680 }
04681 
04682 LLEditMenuHandlerMgr::~LLEditMenuHandlerMgr()
04683 {
04684 }
04685 

Generated on Thu Jul 1 06:08:52 2010 for Second Life Viewer by  doxygen 1.4.7