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