00001 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
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 
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 
00123 
00124 const S32 PIE_CENTER_SIZE = 20;         
00125 const F32 PIE_SCALE_FACTOR = 1.7f; 
00126 const F32 PIE_SHRINK_TIME = 0.2f; 
00127 
00128 const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f;
00129 
00133 
00134 
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 
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                 
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         
00194         
00195         
00196         
00197         BOOL handled = FALSE;
00198 
00199         if( called_from_parent )  
00200         {
00201                 
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 
00239 
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                         
00254                         
00255                         
00256                         
00257                         
00258                         
00259                         
00260                         
00261                         
00262 
00263                         
00264                         
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 
00276                         }
00277                         listp->push_back(accelerator);
00278                 }
00279         }
00280         return TRUE;
00281 }
00282 
00283 
00284 
00285 void LLMenuItemGL::appendAcceleratorString( LLString& st )
00286 {
00287         
00288         if( KEY_NONE == mAcceleratorKey )
00289         {
00290                 return;
00291         }
00292 
00293         
00294 #ifdef LL_DARWIN
00295         
00296         
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-" );            
00306                 }
00307         }
00308         if( mAcceleratorMask & MASK_ALT )
00309                 st.append( "Opt-" );            
00310         if( mAcceleratorMask & MASK_SHIFT )
00311                 st.append( "Shift-" );          
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 
00342 void LLMenuItemGL::setFont(LLFontGL* font)
00343 {
00344         mFont = font;
00345 }
00346 
00347 
00348 U32 LLMenuItemGL::getNominalHeight( void )
00349 {
00350         return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING;
00351 }
00352 
00353 
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 
00376 void LLMenuItemGL::setLabel( const LLStringExplicit& label )
00377 {
00378         mLabel = label;
00379 }
00380 
00381 
00382 LLMenuGL* LLMenuItemGL::getMenu()
00383 {
00384         return (LLMenuGL*) getParent();
00385 }
00386 
00387 
00388 
00389 
00390 
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 
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         
00427         
00428         if (!getMenu()->getTornOff() 
00429                 && getMenu()->getVisible())
00430         {
00431                 LLMenuGL::sMenuContainer->hideMenus();
00432         }
00433 }
00434 
00435 
00436  void LLMenuItemGL::setHighlight( BOOL highlight )
00437 {
00438         if (highlight)
00439         {
00440                 getMenu()->clearHoverItem();
00441         }
00442         mHighlight = highlight;
00443 }
00444 
00445 
00446 BOOL LLMenuItemGL::isActive( void ) const
00447 {
00448         return FALSE;
00449 }
00450 
00451 
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                         
00465                         LLMenuGL::setKeyboardMode(TRUE);
00466 
00467                         getMenu()->highlightPrevItem(this);
00468                         return TRUE;
00469                 }
00470                 else if (key == KEY_DOWN)
00471                 {
00472                         
00473                         LLMenuGL::setKeyboardMode(TRUE);
00474 
00475                         getMenu()->highlightNextItem(this);
00476                         return TRUE;
00477                 }
00478                 else if (key == KEY_RETURN && mask == MASK_NONE)
00479                 {
00480                         
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                 
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                 
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         
00525         
00526 
00527         
00528         
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         
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         
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         
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 
00609 
00610 
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         
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 
00691 
00692 
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 
00714 
00715 
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                 
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                         
00761                         
00762                         tear_off_menu->setFocus(TRUE);
00763                 }
00764         }
00765         LLMenuItemGL::doIt();
00766 }
00767 
00768 void LLMenuItemTearOffGL::draw()
00769 {
00770         
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 
00795 
00796 
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         
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         
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         
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 
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 
00954 LLXMLNodePtr LLMenuItemCallGL::getXML(bool save_children) const
00955 {
00956         LLXMLNodePtr node = LLMenuItemGL::getXML();
00957 
00958         
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 
00978 void LLMenuItemCallGL::doIt( void )
00979 {
00980         
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         
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 
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 
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 
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 
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 
01192 void LLMenuItemToggleGL::doIt( void )
01193 {
01194         getMenu()->setItemLastSelected( this );
01195         
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 
01212 LLView* LLMenuItemBranchGL::getChildByName(const LLString& name, BOOL recurse) const
01213 {
01214         if (mBranch->getName() == name)
01215         {
01216                 return mBranch;
01217         }
01218         
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 
01233 BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
01234 {
01235         if (mEnabled)
01236         {
01237                 
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 
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 
01265 
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 
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 
01293 void LLMenuItemBranchGL::doIt( void )
01294 {
01295         openMenu();
01296 
01297         
01298         
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 
01339 void LLMenuItemBranchGL::setHighlight( BOOL highlight )
01340 {
01341         if (highlight == getHighlight()) return;
01342 
01343         
01344         if (highlight)
01345         {
01346                 getMenu()->clearHoverItem();
01347         }
01348 
01349         BOOL auto_open = mEnabled && (!mBranch->getVisible() || mBranch->getTornOff());
01350         
01351         if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus())
01352         {
01353                 auto_open = FALSE;
01354         }
01355         
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 
01398 
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                 
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                 
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                 
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                 
01470                 mBranch->highlightNextItem(NULL);
01471         }
01472         else if( !mBranch->getVisible() )
01473         {
01474                 
01475                 const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
01476 
01477                 mBranch->arrange();
01478 
01479                 LLRect rect = mBranch->getRect();
01480                 
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                         
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 
01518 
01519 
01520 
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         
01537         
01538         
01539         virtual U32 getNominalWidth( void );
01540 
01541         
01542         virtual void buildDrawLabel( void );
01543 
01544         
01545         virtual void openMenu( void );
01546 
01547         
01548         
01549         virtual void setHighlight( BOOL highlight );
01550 
01551         virtual BOOL isActive( void ) const;
01552 
01553         
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 
01571 
01572 
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 
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                         
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 
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         
01665         
01666         
01667         return isOpen();
01668 }
01669 
01670 BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
01671 {
01672         
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                 
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         
01702         if (getHighlight() && getMenu()->getVisible() && (isActive() || LLMenuGL::getKeyboardMode()))
01703         {
01704                 if (key == KEY_LEFT)
01705                 {
01706                         
01707                         LLMenuGL::setKeyboardMode(TRUE);
01708 
01709                         LLMenuItemGL* itemp = getMenu()->highlightPrevItem(this);
01710                         
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                         
01721                         LLMenuGL::setKeyboardMode(TRUE);
01722 
01723                         LLMenuItemGL* itemp = getMenu()->highlightNextItem(this);
01724                         
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                         
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                         
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         
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         
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         
01814         
01815         mGotHover = FALSE;
01816 }
01817 
01821 
01822 
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 
01874 LLMenuGL::~LLMenuGL( void )
01875 {
01876         
01877         
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 
01902 LLXMLNodePtr LLMenuGL::getXML(bool save_children) const
01903 {
01904         LLXMLNodePtr node = LLView::getXML();
01905 
01906         
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                 
01917                 node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
01918         }
01919 
01920         
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                 
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                 
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                         
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                                 
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 
02207 
02208 BOOL LLMenuGL::jumpKeysActive()
02209 {
02210         LLMenuItemGL* highlighted_item = getHighlightedItem();
02211         BOOL active = getVisible() && getEnabled();
02212         if (getTornOff())
02213         {
02214                 
02215                 active = active && ((LLFloater*)getParent())->hasFocus();
02216 
02217         }
02218         else
02219         {
02220                 
02221                 
02222                 
02223                 active = active && (!getParentMenuItem() || getParentMenuItem()->isActive()) 
02224                                 && (!highlighted_item || !highlighted_item->isActive()); 
02225         }
02226         return active;
02227 }
02228 
02229 BOOL LLMenuGL::isOpen()
02230 {
02231         if (getTornOff())
02232         {
02233                 LLMenuItemGL* itemp = getHighlightedItem();
02234                 
02235                 
02236                 if (itemp && itemp->isOpen())
02237                 {
02238                         return TRUE;
02239                 }
02240                 
02241                 return ((LLFloater*)getParent())->hasFocus();
02242         }
02243         else
02244         {
02245                 
02246                 
02247                 return getVisible();
02248         }
02249 }
02250 
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         
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 
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 
02338 void LLMenuGL::arrange( void )
02339 {
02340         
02341         
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                 
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                                                 
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                                                 
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                                                 
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                                                 
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                                 
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                 
02470                 delete mSpilloverMenu;
02471                 
02472                 
02473                 mSpilloverMenu = new LLMenuGL("More", "More", mParentFloaterHandle);
02474                 mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer);
02475                 
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                 
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                 
02503                 while (mSpilloverMenu->getItemCount())
02504                 {
02505                         LLMenuItemGL* itemp = mSpilloverMenu->getItem(0);
02506                         mSpilloverMenu->removeChild(itemp);
02507                         mSpilloverMenu->mItems.erase(mSpilloverMenu->mItems.begin());
02508                         
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                                 
02538                                 shared_words.insert(*token_iter);
02539                         }
02540                         else
02541                         {
02542                                 
02543                                 unique_words.insert(*token_iter);
02544                         }
02545                 }
02546         }
02547 
02548         
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                                 
02561                                 
02562                                 (*item_it)->setJumpKey(KEY_NONE);
02563                         }
02564                 }
02565         }
02566 
02567         for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it)
02568         {
02569                 
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                         
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 
02612 void LLMenuGL::empty( void )
02613 {
02614         cleanupSpilloverBranch();
02615 
02616         mItems.clear();
02617 
02618         deleteAllChildren();
02619         
02620 }
02621 
02622 
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         
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                 
02638                 LLMenuGL::setKeyboardMode(TRUE);
02639 
02640                 
02641 
02642                 
02643                 
02644                 found_it->second->setHighlight(TRUE);
02645                 found_it->second->doIt();
02646 
02647         }
02648         
02649         
02650         return TRUE;
02651 }
02652 
02653 
02654 
02655 BOOL LLMenuGL::append( LLMenuItemGL* item )
02656 {
02657         mItems.push_back( item );
02658         addChild( item );
02659         arrange();
02660         return TRUE;
02661 }
02662 
02663 
02664 BOOL LLMenuGL::appendSeparator( const LLString &separator_name )
02665 {
02666         LLMenuItemGL* separator = new LLMenuItemSeparatorGL(separator_name);
02667         return append( separator );
02668 }
02669 
02670 
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         
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 
02702 
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         
02738         item->buildDrawLabel();
02739 }
02740 
02741 
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         
02790         
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         
02821         if (mTearOffItem && !cur_item)
02822         {
02823                 
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                 
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         
02868         
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                 
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 
02951 BOOL LLMenuGL::handleKey( KEY key, MASK mask, BOOL called_from_parent )
02952 {
02953         BOOL handled = FALSE;
02954 
02955         
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         
02984         if(!mEnabled)
02985         {
02986                 return FALSE;
02987         }
02988 
02989         
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         
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         
03029         if ((llabs(mMouseVelX) > 0 || 
03030                         llabs(mMouseVelY) > 0) &&
03031                 (!mHasSelection ||
03032                 
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                                 
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                         
03057                         
03058                         if( viewp->getVisible() && 
03059                                 
03060                                 
03061                                 
03062                                 viewp->pointInView(local_x, local_y) && 
03063                                 viewp->handleHover(local_x, local_y, mask))
03064                         {
03065                                 
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                         
03113                         
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 
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         
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         
03182         menu->setRect( rect );
03183 
03184         S32 bottom;
03185         left = rect.mLeft;
03186         bottom = rect.mBottom;
03187         
03188         
03189         S32 delta_x = 0;
03190         S32 delta_y = 0;
03191         if( bottom < menu_region_rect.mBottom )
03192         {
03193                 
03194                 
03195                 
03196                 delta_y = (rect.getHeight() + 2 * HPAD);
03197         }
03198 
03199         if( left > menu_region_rect.mRight - rect.getWidth() )
03200         {
03201                 
03202                 
03203                 
03204                 delta_x = -(rect.getWidth() + 2 * HPAD);
03205         }
03206         menu->translate( delta_x, delta_y );
03207         menu->setVisible( TRUE );
03208 }
03209 
03210 
03211 
03212 
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         
03224         virtual void buildDrawLabel( void );
03225 
03226         
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 
03252 void LLPieMenuBranch::buildDrawLabel( void )
03253 {
03254         if(mEnabledCallback)
03255         {
03256                 setEnabled(mEnabledCallback(mUserData));
03257                 mDrawTextDisabled = FALSE;
03258         }
03259         else
03260         {
03261                 
03262                 
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         
03286         mDrawBranchLabel.clear();
03287 }
03288 
03289 
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, ¢er_x, ¢er_y);
03298 
03299         parent->hide(FALSE);
03300         mBranch->show(  center_x, center_y, FALSE );
03301 }
03302 
03303 
03304 
03305 
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 
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                         
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 
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         
03388         
03389         BOOL handled = FALSE;
03390 
03391         
03392         
03393         
03394         
03395         
03396 
03397         
03398         
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                 
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         
03484         LLMenuItemGL *item = pieItemFromXY( x, y );
03485 
03486         if (item)
03487         {
03488                 
03489                 
03490                 handled = item->handleMouseDown( 0, 0, mask );
03491         }
03492         else if (!mRightMouseDown)
03493         {
03494                 
03495                 ((LLMenuHolderGL*)getParent())->hideMenus();
03496         }
03497 
03498         
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         
03509         LLMenuItemGL *item = pieItemFromXY( x, y );
03510         S32 delta_x = x  - getLocalRect().getCenterX();
03511         S32 delta_y = y  - getLocalRect().getCenterY();
03512         BOOL clicked_in_pie = ((delta_x * delta_x) + (delta_y * delta_y) < mCurRadius*mCurRadius) || mUseInfiniteRadius;
03513 
03514         
03515         if (clicked_in_pie)
03516         {
03517                 
03518                 gFocusMgr.setMouseCapture(this);
03519                 mShrinkBorderTimer.stop();
03520                 mUseInfiniteRadius = TRUE;
03521                 handled = TRUE;
03522         }
03523         
03524         if (item)
03525         {
03526                 
03527                 
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         
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  - getLocalRect().getCenterX();
03548         S32 delta_y = y  - getLocalRect().getCenterY();
03549         if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE)
03550         {
03551                 
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         
03569         LLMenuItemGL *item = pieItemFromXY( x, y );
03570 
03571         if (item)
03572         {
03573                 
03574                 
03575                 if (item->getEnabled())
03576                 {
03577                         handled = item->handleMouseUp( 0, 0, mask );
03578                         hide(TRUE);
03579                 }
03580         }
03581         else if (!mRightMouseDown)
03582         {
03583                 
03584                 ((LLMenuHolderGL*)getParent())->hideMenus();
03585         }
03586 
03587         if (handled)
03588         {
03589                 make_ui_sound("UISndClickRelease");
03590         }
03591 
03592         if (!handled && !mUseInfiniteRadius)
03593         {
03594                 
03595                 sMenuContainer->hideMenus();
03596         }
03597 
03598         if (mFirstMouseDown)
03599         {
03600                 make_ui_sound("UISndPieMenuAppear");
03601                 mFirstMouseDown = FALSE;
03602         }
03603         
03604         
03605         if (!mShrinkBorderTimer.getStarted())
03606         {
03607                 mShrinkBorderTimer.start();
03608         }
03609 
03610         return handled;
03611 }
03612 
03613 
03614 
03615 void LLPieMenu::draw()
03616 {
03617         
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         
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                 
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                 
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                 
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                 
03681                 glColor4fv( line_color.mV );
03682                 gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE );
03683 
03684                 
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 
03732 BOOL LLPieMenu::append(LLMenuItemGL *item)
03733 {
03734         item->setBriefItem(TRUE);
03735         item->setFont( LLFontGL::sSansSerifSmall );
03736         return LLMenuGL::append(item);
03737 }
03738 
03739 
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 
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 
03765 void LLPieMenu::arrange()
03766 {
03767         const S32 rect_height = 180;
03768         const S32 rect_width = 180;
03769 
03770         
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 
03789 
03790 
03791         
03792 
03793         mRect.setOriginAndSize(mRect.mLeft, mRect.mBottom, rect_width, rect_height );
03794 
03795         
03796         
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                 
03806                 rect.setCenterAndSize(ITEM_CENTER_X[i],
03807                                                           ITEM_CENTER_Y[i], 
03808                                                           item_width, font_height );
03809 
03810                 
03811                 rect.translate( rect_width/2, rect_height/2 );
03812 
03813                 item->setRect( rect );
03814 
03815                 
03816                 item->buildDrawLabel();
03817                 i++;
03818         }
03819 }
03820 
03821 LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
03822 {
03823         
03824         
03825         
03826         
03827 
03828         
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         
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         
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         
03850         
03851         angle += ARC_DEG / 2.f;
03852 
03853         
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         
03877         const F32 ARC_DEG = 45.f;
03878         
03879         S32 delta_x = x - mRect.getWidth() / 2;
03880         S32 delta_y = y - mRect.getHeight() / 2;
03881 
03882         
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         
03891         
03892         angle += ARC_DEG / 2.f;
03893 
03894         
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         
03918         if (mRect.mLeft < menu_region_rect.mLeft) 
03919         {
03920                 
03921                 
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                 
03929                 
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                 
03937                 
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                 
03946                 
03947                 mRect.translate( 0, menu_region_rect.mTop - mRect.mTop );
03948                 moved = TRUE;
03949         }
03950 
03951         
03952         
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         
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         
03976         
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 
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 
04025 LLMenuBarGL::~LLMenuBarGL()
04026 {
04027         std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer());
04028         mAccelerators.clear();
04029 }
04030 
04031 
04032 LLXMLNodePtr LLMenuBarGL::getXML(bool save_children) const
04033 {
04034         
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         
04076         
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                         
04102                         
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                 
04137                 
04138                 return FALSE;
04139         }
04140         BOOL result = LLMenuGL::handleAcceleratorKey(key, mask);
04141         if (result && mask & MASK_ALT)
04142         {
04143                 
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 
04171         {
04172                 mAltKeyTrigger = FALSE;
04173         }
04174 
04175         
04176         checkMenuTrigger();
04177 
04178         return LLMenuGL::handleKeyHere(key, mask, called_from_parent);
04179 }
04180 
04181 BOOL LLMenuBarGL::handleJumpKey(KEY key)
04182 {
04183         
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                 
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         
04201         
04202         
04203         
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         
04217         if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT))
04218         {
04219                 
04220                 
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         
04241         
04242         return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive();
04243 }
04244 
04245 
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         
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 
04287 BOOL LLMenuBarGL::appendSeparator( const LLString &separator_name )
04288 {
04289         LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL();
04290         return append( separator );
04291 }
04292 
04293 
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         
04326         
04327         if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0)
04328         {
04329                 
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                 
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                         
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         
04419         LLMenuItemGL* selecteditem = (LLMenuItemGL*)LLView::getViewByHandle(sItemLastSelectedHandle);
04420         if (selecteditem && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME)
04421         {
04422                 
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                 
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                 
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                 
04505                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
04506                 {
04507                         LLView* viewp = *child_it;
04508                         
04509                         if (viewp->getWidgetType() != WIDGET_TYPE_MENU_BAR && viewp->getVisible())
04510                         {
04511                                 viewp->setVisible(FALSE);
04512                         }
04513                 }
04514         }
04515         
04516         
04517         
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         
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                 
04569                 reshape(mRect.getWidth(), llceil(lerp((F32)mRect.getHeight(), mTargetHeight, LLCriticalDamp::getInterpolant(0.05f))));
04570         }
04571         else
04572         {
04573                 
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         
04583         if (!mMenu->getHighlightedItem())
04584         {
04585                 mMenu->highlightNextItem(NULL);
04586         }
04587 
04588         
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         
04607         mMenu->clearHoverItem();
04608         LLFloater::onFocusLost();
04609 }
04610 
04611 BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
04612 {
04613         
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         
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                 
04641                 mMenu->clearHoverItem();
04642         }
04643         LLFloater::translate(x, y);
04644 }
04645 
04646 
04647 LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
04648 {
04649         LLTearOffMenu* tearoffp = new LLTearOffMenu(menup);
04650         
04651         gFloaterView->adjustToFitScreen(tearoffp, FALSE);
04652         tearoffp->open();       
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