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