summaryrefslogtreecommitdiff
path: root/indra/llui/llmenugl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llmenugl.cpp')
-rw-r--r--indra/llui/llmenugl.cpp3217
1 files changed, 1329 insertions, 1888 deletions
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index a8d06643ff..d6dfe6c198 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -49,26 +49,22 @@
#include "llmath.h"
#include "llrender.h"
#include "llfocusmgr.h"
-#include "llfont.h"
#include "llcoord.h"
#include "llwindow.h"
#include "llcriticaldamp.h"
#include "lluictrlfactory.h"
+#include "llbutton.h"
#include "llfontgl.h"
#include "llresmgr.h"
#include "llui.h"
-#include "lluitrans.h"
-
#include "llstl.h"
#include "v2math.h"
#include <set>
#include <boost/tokenizer.hpp>
-using namespace LLOldEvents;
-
// static
LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
@@ -80,7 +76,6 @@ S32 MENU_BAR_WIDTH = 0;
///============================================================================
const std::string SEPARATOR_NAME("separator");
-const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
const std::string SEPARATOR_LABEL( "-----------" );
const std::string VERTICAL_SEPARATOR_LABEL( "|" );
@@ -94,7 +89,6 @@ const U32 RIGHT_PAD_PIXELS = 2;
const U32 RIGHT_WIDTH_PIXELS = 15;
const U32 RIGHT_PLAIN_PIXELS = RIGHT_PAD_PIXELS + RIGHT_WIDTH_PIXELS;
-const U32 ACCEL_PAD_PIXELS = 10;
const U32 PLAIN_PAD_PIXELS = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS + RIGHT_PAD_PIXELS + RIGHT_WIDTH_PIXELS;
const U32 BRIEF_PAD_PIXELS = 2;
@@ -112,12 +106,6 @@ const F32 MAX_MOUSE_SLOPE_SUB_MENU = 0.9f;
const S32 PIE_GESTURE_ACTIVATE_DISTANCE = 10;
-LLColor4 LLMenuItemGL::sEnabledColor( 0.0f, 0.0f, 0.0f, 1.0f );
-LLColor4 LLMenuItemGL::sDisabledColor( 0.5f, 0.5f, 0.5f, 1.0f );
-LLColor4 LLMenuItemGL::sHighlightBackground( 0.0f, 0.0f, 0.7f, 1.0f );
-LLColor4 LLMenuItemGL::sHighlightForeground( 1.0f, 1.0f, 1.0f, 1.0f );
-
-LLColor4 LLMenuGL::sDefaultBackgroundColor( 0.25f, 0.25f, 0.25f, 0.75f );
BOOL LLMenuGL::sKeyboardMode = FALSE;
LLHandle<LLView> LLMenuHolderGL::sItemLastSelectedHandle;
@@ -130,72 +118,84 @@ const F32 PIE_SHRINK_TIME = 0.2f; // time of transition between unbounded and bo
const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f;
+static MenuRegistry::Register<LLMenuItemSeparatorGL> register_separator("menu_item_separator");
+static MenuRegistry::Register<LLMenuItemCallGL> register_menu_item_call("menu_item_call");
+static MenuRegistry::Register<LLMenuItemCheckGL> register_menu_item_check("menu_item_check");
+static MenuRegistry::Register<LLMenuGL> register_menu("menu");
+
+static LLDefaultChildRegistry::Register<LLMenuGL> register_menu_default("menu");
+
+
+
///============================================================================
/// Class LLMenuItemGL
///============================================================================
-
// Default constructor
-LLMenuItemGL::LLMenuItemGL( const std::string& name, const std::string& label, KEY key, MASK mask ) :
- LLView( name, TRUE ),
- mJumpKey(KEY_NONE),
- mAcceleratorKey( key ),
- mAcceleratorMask( mask ),
+LLMenuItemGL::LLMenuItemGL(const LLMenuItemGL::Params& p)
+: LLUICtrl(p),
+ mJumpKey(p.jump_key),
mAllowKeyRepeat(FALSE),
mHighlight( FALSE ),
mGotHover( FALSE ),
mBriefItem( FALSE ),
- mFont( LLFontGL::getFontSansSerif() ),
- mStyle(LLFontGL::NORMAL),
- mDrawTextDisabled( FALSE )
+ mDrawTextDisabled( FALSE ),
+ mFont(p.font),
+ mAcceleratorKey(KEY_NONE),
+ mAcceleratorMask(MASK_NONE),
+ mLabel(p.label.isProvided() ? p.label() : p.name()),
+ mEnabledColor(p.enabled_color()),
+ mDisabledColor(p.disabled_color()),
+ mHighlightBackground(p.highlight_bg_color()),
+ mHighlightForeground(p.highlight_fg_color())
{
- setLabel( label );
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const
-{
- LLXMLNodePtr node = LLView::getXML();
-
- node->createChild("type", TRUE)->setStringValue(getType());
-
- node->createChild("label", TRUE)->setStringValue(mLabel);
-
- if (mAcceleratorKey != KEY_NONE)
+#ifdef LL_DARWIN
+ // See if this Mac accelerator should really use the ctrl key and not get mapped to cmd
+ BOOL useMacCtrl = p.use_mac_ctrl;
+#endif // LL_DARWIN
+
+ std::string shortcut = p.shortcut;
+ if (shortcut.find("control") != shortcut.npos)
{
- std::stringstream out;
- if (mAcceleratorMask & MASK_CONTROL)
- {
- out << "control|";
- }
- if (mAcceleratorMask & MASK_ALT)
- {
- out << "alt|";
- }
- if (mAcceleratorMask & MASK_SHIFT)
- {
- out << "shift|";
- }
- out << LLKeyboard::stringFromKey(mAcceleratorKey);
-
- node->createChild("shortcut", TRUE)->setStringValue(out.str());
-
#ifdef LL_DARWIN
- // Write in special tag if this key is really a ctrl combination on the Mac
- if (mAcceleratorMask & MASK_MAC_CONTROL)
+ if ( useMacCtrl )
{
- node->createChild("useMacCtrl", TRUE)->setBoolValue( TRUE );
+ mAcceleratorMask |= MASK_MAC_CONTROL;
}
#endif // LL_DARWIN
+ mAcceleratorMask |= MASK_CONTROL;
}
+ if (shortcut.find("alt") != shortcut.npos)
+ {
+ mAcceleratorMask |= MASK_ALT;
+ }
+ if (shortcut.find("shift") != shortcut.npos)
+ {
+ mAcceleratorMask |= MASK_SHIFT;
+ }
+ S32 pipe_pos = shortcut.rfind("|");
+ std::string key_str = shortcut.substr(pipe_pos+1);
+
+ LLKeyboard::keyFromString(key_str, &mAcceleratorKey);
- return node;
+ LL_DEBUGS("HotKeys") << "Process short cut key: shortcut: " << shortcut
+ << ", key str: " << key_str
+ << ", accelerator mask: " << mAcceleratorMask
+ << ", accelerator key: " << mAcceleratorKey
+ << LL_ENDL;
}
+//virtual
+void LLMenuItemGL::setValue(const LLSD& value)
+{
+ setLabel(value.asString());
+}
+
+//virtual
BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
{
if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
{
- doIt();
+ onCommit();
return TRUE;
}
return FALSE;
@@ -208,6 +208,26 @@ BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask)
return TRUE;
}
+//virtual
+BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ return LLUICtrl::handleRightMouseDown(x,y,mask);
+}
+
+//virtual
+BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
+{
+ // If this event came from a right-click context menu spawn,
+ // process as a left-click to allow menu items to be hit
+ if (LLMenuHolderGL::sContextMenuSpawnPos.mX != S32_MAX
+ || LLMenuHolderGL::sContextMenuSpawnPos.mY != S32_MAX)
+ {
+ BOOL handled = handleMouseUp(x, y, mask);
+ return handled;
+ }
+ return LLUICtrl::handleRightMouseUp(x,y,mask);
+}
+
// This function checks to see if the accelerator key is already in use;
// if not, it will be added to the list
BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
@@ -271,24 +291,24 @@ void LLMenuItemGL::appendAcceleratorString( std::string& st ) const
{
if ( mAcceleratorMask & MASK_MAC_CONTROL )
{
- st.append( LLUITrans::getString("accel-mac-control") );
+ st.append( "Ctrl-" );
}
else
{
- st.append( LLUITrans::getString("accel-mac-command") ); // Symbol would be "\xE2\x8C\x98"
+ st.append( "Cmd-" ); // Symbol would be "\xE2\x8C\x98"
}
}
if( mAcceleratorMask & MASK_ALT )
- st.append( LLUITrans::getString("accel-mac-option") ); // Symbol would be "\xE2\x8C\xA5"
+ st.append( "Opt-" ); // Symbol would be "\xE2\x8C\xA5"
if( mAcceleratorMask & MASK_SHIFT )
- st.append( LLUITrans::getString("accel-mac-shift") ); // Symbol would be "\xE2\x8C\xA7"
+ st.append( "Shift-" ); // Symbol would be "\xE2\x8C\xA7"
#else
if( mAcceleratorMask & MASK_CONTROL )
- st.append( LLUITrans::getString("accel-win-control") );
+ st.append( "Ctrl-" );
if( mAcceleratorMask & MASK_ALT )
- st.append( LLUITrans::getString("accel-win-alt") );
+ st.append( "Alt-" );
if( mAcceleratorMask & MASK_SHIFT )
- st.append( LLUITrans::getString("accel-win-shift") );
+ st.append( "Shift-" );
#endif
std::string keystr = LLKeyboard::stringFromKey( mAcceleratorKey );
@@ -298,6 +318,7 @@ void LLMenuItemGL::appendAcceleratorString( std::string& st ) const
st.append( " " );
}
st.append( keystr );
+ LL_DEBUGS("HotKeys") << "appendAcceleratorString: " << st << LL_ENDL;
}
void LLMenuItemGL::setJumpKey(KEY key)
@@ -312,9 +333,20 @@ U32 LLMenuItemGL::getNominalHeight( void ) const
return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING;
}
+//virtual
+void LLMenuItemGL::setBriefItem(BOOL brief)
+{
+ mBriefItem = brief;
+}
+
+//virtual
+BOOL LLMenuItemGL::isBriefItem() const
+{
+ return mBriefItem;
+}
// Get the parent menu for this item
-LLMenuGL* LLMenuItemGL::getMenu()
+LLMenuGL* LLMenuItemGL::getMenu() const
{
return (LLMenuGL*) getParent();
}
@@ -338,7 +370,7 @@ U32 LLMenuItemGL::getNominalWidth( void ) const
if( KEY_NONE != mAcceleratorKey )
{
- width += ACCEL_PAD_PIXELS;
+ width += getMenu()->getShortcutPad();
std::string temp;
appendAcceleratorString( temp );
width += mFont->getWidth( temp );
@@ -356,7 +388,7 @@ void LLMenuItemGL::buildDrawLabel( void )
mDrawAccelLabel = st;
}
-void LLMenuItemGL::doIt( void )
+void LLMenuItemGL::onCommit( void )
{
// close all open menus by default
// if parent menu is actually visible (and we are not triggering menu item via accelerator)
@@ -365,6 +397,8 @@ void LLMenuItemGL::doIt( void )
{
LLMenuGL::sMenuContainer->hideMenus();
}
+
+ LLUICtrl::onCommit();
}
// set the hover status (called by it's menu)
@@ -404,7 +438,7 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask )
// switch to keyboard navigation mode
LLMenuGL::setKeyboardMode(TRUE);
- doIt();
+ onCommit();
return TRUE;
}
}
@@ -412,25 +446,30 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask )
return FALSE;
}
-BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK )
+BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK mask)
{
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
- doIt();
+ onCommit();
make_ui_sound("UISndClickRelease");
- return TRUE;
+ return LLView::handleMouseUp(x, y, mask);
}
-BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK )
+BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask)
{
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
setHighlight(TRUE);
- return TRUE;
+ return LLView::handleMouseDown(x, y, mask);
}
+BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ // If the menu is scrollable let it handle the wheel event.
+ return !getMenu()->isScrollable();
+}
void LLMenuItemGL::draw( void )
{
@@ -441,55 +480,58 @@ void LLMenuItemGL::draw( void )
// let disabled items be highlighted, just don't draw them as such
if( getEnabled() && getHighlight() && !mBriefItem)
{
- gGL.color4fv( sHighlightBackground.mV );
+ int debug_count = 0;
+ if (dynamic_cast<LLMenuItemCallGL*>(this))
+ debug_count++;
+ gGL.color4fv( mHighlightBackground.get().mV );
gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
}
LLColor4 color;
- U8 font_style = mStyle;
+ LLFontGL::ShadowType shadow_style = LLFontGL::NO_SHADOW;
if (getEnabled() && !mDrawTextDisabled )
{
- font_style |= LLFontGL::DROP_SHADOW_SOFT;
+ shadow_style = LLFontGL::DROP_SHADOW_SOFT;
}
if ( getEnabled() && getHighlight() )
{
- color = sHighlightForeground;
+ color = mHighlightForeground.get();
}
else if( getEnabled() && !mDrawTextDisabled )
{
- color = sEnabledColor;
+ color = mEnabledColor.get();
}
else
{
- color = sDisabledColor;
+ color = mDisabledColor.get();
}
// Draw the text on top.
if (mBriefItem)
{
mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color,
- LLFontGL::LEFT, LLFontGL::BOTTOM, font_style );
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style );
}
else
{
if( !mDrawBoolLabel.empty() )
{
mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
}
mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
if( !mDrawAccelLabel.empty() )
{
mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
}
if( !mDrawBranchLabel.empty() )
{
mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
}
}
@@ -517,38 +559,40 @@ BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit&
return TRUE;
}
+void LLMenuItemGL::handleVisibilityChange(BOOL new_visibility)
+{
+ if (getMenu())
+ {
+ getMenu()->needsArrange();
+ }
+ LLView::handleVisibilityChange(new_visibility);
+}
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemSeparatorGL
//
// This class represents a separator.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLMenuItemSeparatorGL : public LLMenuItemGL
+LLMenuItemSeparatorGL::Params::Params()
{
-public:
- LLMenuItemSeparatorGL( const std::string &name = SEPARATOR_NAME );
-
- virtual std::string getType() const { return "separator"; }
-
- // doIt() - do the primary funcationality of the menu item.
- virtual void doIt( void ) {}
-
- virtual void draw( void );
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
- virtual BOOL handleHover(S32 x, S32 y, MASK mask);
+ name = "separator";
+ label = SEPARATOR_LABEL;
+}
- virtual U32 getNominalHeight( void ) const { return SEPARATOR_HEIGHT_PIXELS; }
-};
+LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) :
+ LLMenuItemGL( p )
+{
+}
-LLMenuItemSeparatorGL::LLMenuItemSeparatorGL( const std::string &name ) :
- LLMenuItemGL( name, SEPARATOR_LABEL )
+//virtual
+U32 LLMenuItemSeparatorGL::getNominalHeight( void ) const
{
+ return SEPARATOR_HEIGHT_PIXELS;
}
void LLMenuItemSeparatorGL::draw( void )
{
- gGL.color4fv( getDisabledColor().mV );
+ gGL.color4fv( mDisabledColor.get().mV );
const S32 y = getRect().getHeight() / 2;
const S32 PAD = 6;
gl_line_2d( PAD, y, getRect().getWidth() - PAD, y );
@@ -559,11 +603,13 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
LLMenuGL* parent_menu = getMenu();
if (y > getRect().getHeight() / 2)
{
- return parent_menu->handleMouseDown(x + getRect().mLeft, getRect().mTop + 1, mask);
+ LLView* prev_menu_item = parent_menu->findPrevSibling(this);
+ return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
}
else
{
- return parent_menu->handleMouseDown(x + getRect().mLeft, getRect().mBottom - 1, mask);
+ LLView* next_menu_item = parent_menu->findNextSibling(this);
+ return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
}
}
@@ -572,11 +618,13 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask)
LLMenuGL* parent_menu = getMenu();
if (y > getRect().getHeight() / 2)
{
- return parent_menu->handleMouseUp(x + getRect().mLeft, getRect().mTop + 1, mask);
+ LLView* prev_menu_item = parent_menu->findPrevSibling(this);
+ return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
}
else
{
- return parent_menu->handleMouseUp(x + getRect().mLeft, getRect().mBottom - 1, mask);
+ LLView* next_menu_item = parent_menu->findNextSibling(this);
+ return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
}
}
@@ -595,7 +643,6 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask)
}
}
-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemVerticalSeparatorGL
//
@@ -619,19 +666,19 @@ LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void )
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemTearOffGL
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LLMenuItemTearOffGL::LLMenuItemTearOffGL(LLHandle<LLFloater> parent_floater_handle) :
- LLMenuItemGL(std::string("tear off"), TEAROFF_SEPARATOR_LABEL),
- mParentHandle(parent_floater_handle)
+LLMenuItemTearOffGL::LLMenuItemTearOffGL(const LLMenuItemTearOffGL::Params& p)
+: LLMenuItemGL(p),
+ mParentHandle(p.parent_floater_handle)
{
}
-void LLMenuItemTearOffGL::doIt()
+void LLMenuItemTearOffGL::onCommit()
{
if (getMenu()->getTornOff())
{
LLTearOffMenu* torn_off_menu = (LLTearOffMenu*)(getMenu()->getParent());
- torn_off_menu->close();
+ torn_off_menu->closeFloater();
}
else
{
@@ -641,7 +688,7 @@ void LLMenuItemTearOffGL::doIt()
getMenu()->highlightNextItem(this);
}
- getMenu()->arrange();
+ getMenu()->needsArrange();
LLFloater* parent_floater = mParentHandle.get();
LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu());
@@ -658,7 +705,7 @@ void LLMenuItemTearOffGL::doIt()
tear_off_menu->setFocus(TRUE);
}
}
- LLMenuItemGL::doIt();
+ LLMenuItemGL::onCommit();
}
void LLMenuItemTearOffGL::draw()
@@ -666,17 +713,17 @@ void LLMenuItemTearOffGL::draw()
// disabled items can be highlighted, but shouldn't render as such
if( getEnabled() && getHighlight() && !isBriefItem())
{
- gGL.color4fv( getHighlightBGColor().mV );
+ gGL.color4fv( mHighlightBackground.get().mV );
gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
}
if (getEnabled())
{
- gGL.color4fv( getEnabledColor().mV );
+ gGL.color4fv( mEnabledColor.get().mV );
}
else
{
- gGL.color4fv( getDisabledColor().mV );
+ gGL.color4fv( mDisabledColor.get().mV );
}
const S32 y = getRect().getHeight() / 3;
const S32 PAD = 6;
@@ -699,11 +746,16 @@ U32 LLMenuItemTearOffGL::getNominalHeight( void ) const
class LLMenuItemBlankGL : public LLMenuItemGL
{
public:
- LLMenuItemBlankGL( void ) : LLMenuItemGL( LLStringUtil::null, LLStringUtil::null )
+ struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
{
- setEnabled(FALSE);
- }
- virtual void doIt( void ) {}
+ Params()
+ {
+ name="";
+ enabled = false;
+ }
+ };
+ LLMenuItemBlankGL( const Params& p ) : LLMenuItemGL( p )
+ {}
virtual void draw( void ) {}
};
@@ -712,238 +764,116 @@ public:
/// Class LLMenuItemCallGL
///============================================================================
-LLMenuItemCallGL::LLMenuItemCallGL( const std::string& name,
- const std::string& label,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- void* user_data,
- KEY key, MASK mask,
- BOOL enabled,
- on_disabled_callback on_disabled_cb) :
- LLMenuItemGL( name, label, key, mask ),
- mCallback( clicked_cb ),
- mEnabledCallback( enabled_cb ),
- mLabelCallback(NULL),
- mUserData( user_data ),
- mOnDisabledCallback(on_disabled_cb)
-{
- if(!enabled) setEnabled(FALSE);
-}
-
-LLMenuItemCallGL::LLMenuItemCallGL( const std::string& name,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- void* user_data,
- KEY key, MASK mask,
- BOOL enabled,
- on_disabled_callback on_disabled_cb) :
- LLMenuItemGL( name, name, key, mask ),
- mCallback( clicked_cb ),
- mEnabledCallback( enabled_cb ),
- mLabelCallback(NULL),
- mUserData( user_data ),
- mOnDisabledCallback(on_disabled_cb)
-{
- if(!enabled) setEnabled(FALSE);
-}
-
-LLMenuItemCallGL::LLMenuItemCallGL(const std::string& name,
- const std::string& label,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- label_callback label_cb,
- void* user_data,
- KEY key, MASK mask,
- BOOL enabled,
- on_disabled_callback on_disabled_cb) :
- LLMenuItemGL(name, label, key, mask),
- mCallback(clicked_cb),
- mEnabledCallback(enabled_cb),
- mLabelCallback(label_cb),
- mUserData(user_data),
- mOnDisabledCallback(on_disabled_cb)
-{
- if(!enabled) setEnabled(FALSE);
-}
-
-LLMenuItemCallGL::LLMenuItemCallGL(const std::string& name,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- label_callback label_cb,
- void* user_data,
- KEY key, MASK mask,
- BOOL enabled,
- on_disabled_callback on_disabled_cb) :
- LLMenuItemGL(name, name, key, mask),
- mCallback(clicked_cb),
- mEnabledCallback(enabled_cb),
- mLabelCallback(label_cb),
- mUserData(user_data),
- mOnDisabledCallback(on_disabled_cb)
-{
- if(!enabled) setEnabled(FALSE);
-}
-
-void LLMenuItemCallGL::setEnabledControl(std::string enabled_control, LLView *context)
-{
- // Register new listener
- if (!enabled_control.empty())
- {
- LLControlVariable *control = context->findControl(enabled_control);
- if (!control)
- {
- context->addBoolControl(enabled_control, getEnabled());
- control = context->findControl(enabled_control);
- llassert_always(control);
- }
- control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("enabled")));
- setEnabled(control->getValue());
- }
-}
-
-void LLMenuItemCallGL::setVisibleControl(std::string visible_control, LLView *context)
+LLMenuItemCallGL::LLMenuItemCallGL(const LLMenuItemCallGL::Params& p)
+: LLMenuItemGL(p)
{
- // Register new listener
- if (!visible_control.empty())
- {
- LLControlVariable *control = context->findControl(visible_control);
- if (!control)
- {
- context->addBoolControl(visible_control, getVisible());
- control = context->findControl(visible_control);
- llassert_always(control);
- }
- control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("visible")));
- setVisible(control->getValue());
- }
}
-// virtual
-LLXMLNodePtr LLMenuItemCallGL::getXML(bool save_children) const
+void LLMenuItemCallGL::initFromParams(const Params& p)
{
- LLXMLNodePtr node = LLMenuItemGL::getXML();
-
- // Contents
-
- std::vector<LLListenerEntry> listeners = mDispatcher->getListeners();
- std::vector<LLListenerEntry>::iterator itor;
- for (itor = listeners.begin(); itor != listeners.end(); ++itor)
+ if (p.on_enable.isProvided())
{
- std::string listener_name = findEventListener((LLSimpleListener*)itor->listener);
- if (!listener_name.empty())
+ initEnableCallback(p.on_enable, mEnableSignal);
+ // Set the enabled control variable (for backwards compatability)
+ if (p.on_enable.control_name.isProvided() && !p.on_enable.control_name().empty())
{
- LLXMLNodePtr child_node = node->createChild("on_click", FALSE);
- child_node->createChild("function", TRUE)->setStringValue(listener_name);
- child_node->createChild("filter", TRUE)->setStringValue(itor->filter.asString());
- child_node->createChild("userdata", TRUE)->setStringValue(itor->userdata.asString());
+ LLControlVariable* control = findControl(p.on_enable.control_name());
+ if (control)
+ setEnabledControlVariable(control);
}
}
-
- return node;
+ if (p.on_click.isProvided())
+ initCommitCallback(p.on_click, mCommitSignal);
+
+ LLUICtrl::initFromParams(p);
}
-// doIt() - Call the callback provided
-void LLMenuItemCallGL::doIt( void )
+void LLMenuItemCallGL::onCommit( void )
{
// RN: menu item can be deleted in callback, so beware
getMenu()->setItemLastSelected( this );
+
+ LLMenuItemGL::onCommit();
+}
- if( mCallback )
+void LLMenuItemCallGL::updateEnabled( void )
+{
+ if (mEnableSignal.num_slots() > 0)
{
- mCallback( mUserData );
+ bool enabled = mEnableSignal(this, LLSD());
+ if (mEnabledControlVariable)
+ {
+ if (!enabled)
+ mEnabledControlVariable->set(false); // callback overrides control variable; this will call setEnabled()
+ }
+ else
+ {
+ setEnabled(enabled);
+ }
}
- LLPointer<LLEvent> fired_event = new LLEvent(this);
- fireEvent(fired_event, "on_click");
- LLMenuItemGL::doIt();
}
void LLMenuItemCallGL::buildDrawLabel( void )
{
- LLPointer<LLEvent> fired_event = new LLEvent(this);
- fireEvent(fired_event, "on_build");
- if( mEnabledCallback )
- {
- setEnabled( mEnabledCallback( mUserData ) );
- }
- if(mLabelCallback)
- {
- std::string label;
- mLabelCallback(label, mUserData);
- mLabel = label;
- }
+ updateEnabled();
LLMenuItemGL::buildDrawLabel();
}
+BOOL LLMenuItemCallGL::handleKeyHere( KEY key, MASK mask )
+{
+ return LLMenuItemGL::handleKeyHere(key, mask);
+}
+
BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask )
{
- if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
+ if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
{
- LLPointer<LLEvent> fired_event = new LLEvent(this);
- fireEvent(fired_event, "on_build");
- if( mEnabledCallback )
- {
- setEnabled( mEnabledCallback( mUserData ) );
- }
- if( !getEnabled() )
+ updateEnabled();
+ if (getEnabled())
{
- if( mOnDisabledCallback )
- {
- mOnDisabledCallback( mUserData );
- }
+ onCommit();
+ return TRUE;
}
}
- return LLMenuItemGL::handleAcceleratorKey(key, mask);
+ return FALSE;
}
+// handleRightMouseUp moved into base class LLMenuItemGL so clicks are
+// handled for all menu item types
+
///============================================================================
/// Class LLMenuItemCheckGL
///============================================================================
-
-LLMenuItemCheckGL::LLMenuItemCheckGL ( const std::string& name,
- const std::string& label,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- check_callback check_cb,
- void* user_data,
- KEY key, MASK mask ) :
- LLMenuItemCallGL( name, label, clicked_cb, enabled_cb, user_data, key, mask ),
- mCheckCallback( check_cb ),
- mChecked(FALSE)
+LLMenuItemCheckGL::LLMenuItemCheckGL (const LLMenuItemCheckGL::Params& p)
+: LLMenuItemCallGL(p)
{
}
-LLMenuItemCheckGL::LLMenuItemCheckGL ( const std::string& name,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- check_callback check_cb,
- void* user_data,
- KEY key, MASK mask ) :
- LLMenuItemCallGL( name, name, clicked_cb, enabled_cb, user_data, key, mask ),
- mCheckCallback( check_cb ),
- mChecked(FALSE)
+void LLMenuItemCheckGL::initFromParams(const Params& p)
{
+ if (p.on_check.isProvided())
+ {
+ initEnableCallback(p.on_check, mCheckSignal);
+ // Set the control name (for backwards compatability)
+ if (p.on_check.control_name.isProvided() && !p.on_check.control_name().empty())
+ {
+ setControlName(p.on_check.control_name());
+ }
+ }
+
+ LLMenuItemCallGL::initFromParams(p);
}
-LLMenuItemCheckGL::LLMenuItemCheckGL ( const std::string& name,
- const std::string& label,
- menu_callback clicked_cb,
- enabled_callback enabled_cb,
- std::string control_name,
- LLView *context,
- void* user_data,
- KEY key, MASK mask ) :
- LLMenuItemCallGL( name, label, clicked_cb, enabled_cb, user_data, key, mask ),
- mCheckCallback( NULL ),
- mChecked(FALSE)
+void LLMenuItemCheckGL::onCommit( void )
{
- setControlName(control_name, context);
+ LLMenuItemCallGL::onCommit();
}
//virtual
void LLMenuItemCheckGL::setValue(const LLSD& value)
{
- mChecked = value.asBoolean();
- if(mChecked)
+ LLUICtrl::setValue(value);
+ if(value.asBoolean())
{
mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
}
@@ -953,34 +883,21 @@ void LLMenuItemCheckGL::setValue(const LLSD& value)
}
}
-void LLMenuItemCheckGL::setCheckedControl(std::string checked_control, LLView *context)
-{
- // Register new listener
- if (!checked_control.empty())
- {
- LLControlVariable *control = context->findControl(checked_control);
- if (!control)
- {
- context->addBoolControl(checked_control, mChecked);
- control = context->findControl(checked_control);
- llassert_always(control);
- }
- control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("value")));
- mChecked = control->getValue();
- }
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemCheckGL::getXML(bool save_children) const
-{
- LLXMLNodePtr node = LLMenuItemCallGL::getXML();
- return node;
-}
-
// called to rebuild the draw label
void LLMenuItemCheckGL::buildDrawLabel( void )
{
- if(mChecked || (mCheckCallback && mCheckCallback( getUserData() ) ) )
+ // Note: mCheckSignal() returns true if no callbacks are set
+ bool checked = mCheckSignal(this, LLSD());
+ if (mControlVariable)
+ {
+ if (!checked)
+ setControlValue(false); // callback overrides control variable; this will call setValue()
+ }
+ else
+ {
+ setValue(checked);
+ }
+ if(getValue().asBoolean())
{
mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
}
@@ -991,95 +908,59 @@ void LLMenuItemCheckGL::buildDrawLabel( void )
LLMenuItemCallGL::buildDrawLabel();
}
-
///============================================================================
-/// Class LLMenuItemToggleGL
+/// Class LLMenuItemBranchGL
///============================================================================
-
-LLMenuItemToggleGL::LLMenuItemToggleGL( const std::string& name, const std::string& label, BOOL* toggle,
- KEY key, MASK mask ) :
- LLMenuItemGL( name, label, key, mask ),
- mToggle( toggle )
+LLMenuItemBranchGL::LLMenuItemBranchGL(const LLMenuItemBranchGL::Params& p)
+ : LLMenuItemGL(p)
{
-}
-
-LLMenuItemToggleGL::LLMenuItemToggleGL( const std::string& name, BOOL* toggle,
- KEY key, MASK mask ) :
- LLMenuItemGL( name, name, key, mask ),
- mToggle( toggle )
-{
-}
-
-
-// called to rebuild the draw label
-void LLMenuItemToggleGL::buildDrawLabel( void )
-{
- if( *mToggle )
- {
- mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
- }
- else
+ LLMenuGL* branch = p.branch;
+ if (branch)
{
- mDrawBoolLabel.clear();
+ mBranchHandle = branch->getHandle();
+ branch->setVisible(FALSE);
+ branch->setParentMenuItem(this);
}
- mDrawAccelLabel.clear();
- std::string st = mDrawAccelLabel;
- appendAcceleratorString( st );
- mDrawAccelLabel = st;
}
-// doIt() - do the primary funcationality of the menu item.
-void LLMenuItemToggleGL::doIt( void )
+LLMenuItemBranchGL::~LLMenuItemBranchGL()
{
- getMenu()->setItemLastSelected( this );
- //llinfos << "LLMenuItemToggleGL::doIt " << mLabel.c_str() << llendl;
- *mToggle = !(*mToggle);
- buildDrawLabel();
- LLMenuItemGL::doIt();
+ LLView::deleteViewByHandle(mBranchHandle);
}
-
-LLMenuItemBranchGL::LLMenuItemBranchGL( const std::string& name, const std::string& label, LLHandle<LLView> branch,
- KEY key, MASK mask ) :
- LLMenuItemGL( name, label, key, mask ),
- mBranch( branch )
+// virtual
+LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse) const
{
- if(!dynamic_cast<LLMenuGL*>(branch.get()))
+ LLMenuGL* branch = getBranch();
+ if (branch)
{
- llerrs << "Non-menu handle passed as branch reference." << llendl;
- }
+ if (branch->getName() == name)
+ {
+ return branch;
+ }
- if(getBranch())
- {
- getBranch()->setVisible( FALSE );
- getBranch()->setParentMenuItem(this);
+ // Always recurse on branches
+ return branch->getChildView(name, recurse);
}
-}
-LLMenuItemBranchGL::~LLMenuItemBranchGL()
-{
- LLView::deleteViewByHandle(mBranch);
+ return LLView::getChildView(name, recurse);
}
-// virtual
-LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const
+LLView* LLMenuItemBranchGL::findChildView(const std::string& name, BOOL recurse) const
{
- // richard: this is redundant with parent, remove
- if (getBranch())
+ LLMenuGL* branch = getBranch();
+ if (branch)
{
- if(getBranch()->getName() == name)
+ if (branch->getName() == name)
{
- return getBranch();
+ return branch;
}
// Always recurse on branches
- LLView* child = getBranch()->getChildView(name, recurse, FALSE);
- if(child)
- {
- return child;
- }
+ return branch->findChildView(name, recurse);
}
- return LLView::getChildView(name, recurse, create_if_missing);;
+
+ return LLView::findChildView(name, recurse);
}
// virtual
@@ -1088,49 +969,35 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
- doIt();
+ onCommit();
make_ui_sound("UISndClickRelease");
return TRUE;
}
BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
{
- if(getBranch())
- {
- return getBranch()->handleAcceleratorKey(key, mask);
- }
- return FALSE;
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemBranchGL::getXML(bool save_children) const
-{
- if (getBranch())
- {
- return getBranch()->getXML();
- }
-
- return LLMenuItemGL::getXML();
+ return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
}
-
// This function checks to see if the accelerator key is already in use;
// if not, it will be added to the list
BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp)
{
- if(getBranch())
- {
- U32 item_count = getBranch()->getItemCount();
- LLMenuItemGL *item;
+ LLMenuGL* branch = getBranch();
+ if (!branch)
+ return FALSE;
- while (item_count--)
+ U32 item_count = branch->getItemCount();
+ LLMenuItemGL *item;
+
+ while (item_count--)
+ {
+ if ((item = branch->getItem(item_count)))
{
- if ((item = getBranch()->getItem(item_count)))
- {
- return item->addToAcceleratorList(listp);
- }
+ return item->addToAcceleratorList(listp);
}
}
+
return FALSE;
}
@@ -1145,23 +1012,24 @@ void LLMenuItemBranchGL::buildDrawLabel( void )
mDrawBranchLabel = BRANCH_SUFFIX;
}
-// doIt() - do the primary functionality of the menu item.
-void LLMenuItemBranchGL::doIt( void )
+void LLMenuItemBranchGL::onCommit( void )
{
openMenu();
// keyboard navigation automatically propagates highlight to sub-menu
// to facilitate fast menu control via jump keys
- if (getBranch() && LLMenuGL::getKeyboardMode() && !getBranch()->getHighlightedItem())
+ if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem())
{
getBranch()->highlightNextItem(NULL);
}
+
+ LLUICtrl::onCommit();
}
BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
{
BOOL handled = FALSE;
- if (called_from_parent && getBranch())
+ if (getBranch() && called_from_parent)
{
handled = getBranch()->handleKey(key, mask, called_from_parent);
}
@@ -1177,7 +1045,7 @@ BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
{
BOOL handled = FALSE;
- if (called_from_parent && getBranch())
+ if (getBranch() && called_from_parent)
{
handled = getBranch()->handleUnicodeChar(uni_char, TRUE);
}
@@ -1193,21 +1061,21 @@ BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa
void LLMenuItemBranchGL::setHighlight( BOOL highlight )
{
- if (highlight == getHighlight()) return;
+ if (highlight == getHighlight())
+ return;
- if(!getBranch())
- {
+ LLMenuGL* branch = getBranch();
+ if (!branch)
return;
- }
- BOOL auto_open = getEnabled() && (!getBranch()->getVisible() || getBranch()->getTornOff());
+ BOOL auto_open = getEnabled() && (!branch->getVisible() || branch->getTornOff());
// torn off menus don't open sub menus on hover unless they have focus
if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus())
{
auto_open = FALSE;
}
// don't auto open torn off sub-menus (need to explicitly active menu item to give them focus)
- if (getBranch()->getTornOff())
+ if (branch->getTornOff())
{
auto_open = FALSE;
}
@@ -1221,14 +1089,14 @@ void LLMenuItemBranchGL::setHighlight( BOOL highlight )
}
else
{
- if (getBranch()->getTornOff())
+ if (branch->getTornOff())
{
- ((LLFloater*)getBranch()->getParent())->setFocus(FALSE);
- getBranch()->clearHoverItem();
+ ((LLFloater*)branch->getParent())->setFocus(FALSE);
+ branch->clearHoverItem();
}
else
{
- getBranch()->setVisible( FALSE );
+ branch->setVisible( FALSE );
}
}
}
@@ -1251,26 +1119,30 @@ void LLMenuItemBranchGL::updateBranchParent(LLView* parentp)
}
}
-void LLMenuItemBranchGL::onVisibilityChange( BOOL new_visibility )
+void LLMenuItemBranchGL::handleVisibilityChange( BOOL new_visibility )
{
if (new_visibility == FALSE && getBranch() && !getBranch()->getTornOff())
{
getBranch()->setVisible(FALSE);
}
- LLMenuItemGL::onVisibilityChange(new_visibility);
+ LLMenuItemGL::handleVisibilityChange(new_visibility);
}
BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask )
{
- if (getMenu()->getVisible() && getBranch() && getBranch()->getVisible() && key == KEY_LEFT)
+ LLMenuGL* branch = getBranch();
+ if (!branch)
+ return LLMenuItemGL::handleKeyHere(key, mask);
+
+ if (getMenu()->getVisible() && branch->getVisible() && key == KEY_LEFT)
{
// switch to keyboard navigation mode
LLMenuGL::setKeyboardMode(TRUE);
- BOOL handled = getBranch()->clearHoverItem();
- if (getBranch()->getTornOff())
+ BOOL handled = branch->clearHoverItem();
+ if (branch->getTornOff())
{
- ((LLFloater*)getBranch()->getParent())->setFocus(FALSE);
+ ((LLFloater*)branch->getParent())->setFocus(FALSE);
}
if (handled && getMenu()->getTornOff())
{
@@ -1281,12 +1153,12 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask )
if (getHighlight() &&
getMenu()->isOpen() &&
- key == KEY_RIGHT && getBranch() && !getBranch()->getHighlightedItem())
+ key == KEY_RIGHT && !branch->getHighlightedItem())
{
// switch to keyboard navigation mode
LLMenuGL::setKeyboardMode(TRUE);
- LLMenuItemGL* itemp = getBranch()->highlightNextItem(NULL);
+ LLMenuItemGL* itemp = branch->highlightNextItem(NULL);
if (itemp)
{
return TRUE;
@@ -1296,41 +1168,55 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask )
return LLMenuItemGL::handleKeyHere(key, mask);
}
+//virtual
+BOOL LLMenuItemBranchGL::isActive() const
+{
+ return isOpen() && getBranch() && getBranch()->getHighlightedItem();
+}
+
+//virtual
+BOOL LLMenuItemBranchGL::isOpen() const
+{
+ return getBranch() && getBranch()->isOpen();
+}
+
void LLMenuItemBranchGL::openMenu()
{
- if(!getBranch()) return;
+ LLMenuGL* branch = getBranch();
+ if (!branch)
+ return;
- if (getBranch()->getTornOff())
+ if (branch->getTornOff())
{
- gFloaterView->bringToFront((LLFloater*)getBranch()->getParent());
+ gFloaterView->bringToFront((LLFloater*)branch->getParent());
// this might not be necessary, as torn off branches don't get focus and hence no highligth
- getBranch()->highlightNextItem(NULL);
+ branch->highlightNextItem(NULL);
}
- else if( !getBranch()->getVisible() )
+ else if( !branch->getVisible() )
{
// get valid rectangle for menus
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
- getBranch()->arrange();
+ branch->arrange();
- LLRect rect = getBranch()->getRect();
+ LLRect rect = branch->getRect();
// calculate root-view relative position for branch menu
S32 left = getRect().mRight;
S32 top = getRect().mTop - getRect().mBottom;
- localPointToOtherView(left, top, &left, &top, getBranch()->getParent());
+ localPointToOtherView(left, top, &left, &top, branch->getParent());
rect.setLeftTopAndSize( left, top,
rect.getWidth(), rect.getHeight() );
- if (getBranch()->getCanTearOff())
+ if (branch->getCanTearOff())
{
rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
}
- getBranch()->setRect( rect );
+ branch->setRect( rect );
S32 x = 0;
S32 y = 0;
- getBranch()->localPointToOtherView( 0, 0, &x, &y, getBranch()->getParent() );
+ branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() );
S32 delta_x = 0;
S32 delta_y = 0;
if( y < menu_region_rect.mBottom )
@@ -1344,9 +1230,9 @@ void LLMenuItemBranchGL::openMenu()
// move sub-menu over to left side
delta_x = llmax(-x, (-1 * (rect.getWidth() + getRect().getWidth())));
}
- getBranch()->translate( delta_x, delta_y );
- getBranch()->setVisible( TRUE );
- getBranch()->getParent()->sendChildToFront(getBranch());
+ branch->translate( delta_x, delta_y );
+ branch->setVisible( TRUE );
+ branch->getParent()->sendChildToFront(branch);
}
}
@@ -1363,10 +1249,7 @@ class LLMenuItemBranchDownGL : public LLMenuItemBranchGL
protected:
public:
- LLMenuItemBranchDownGL( const std::string& name, const std::string& label, LLHandle<LLView> branch,
- KEY key = KEY_NONE, MASK mask = MASK_NONE );
-
- virtual std::string getType() const { return "menu"; }
+ LLMenuItemBranchDownGL( const Params& );
// returns the normal width of this control in pixels - this is
// used for calculating the widest item, as well as for horizontal
@@ -1394,11 +1277,8 @@ public:
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
};
-LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const std::string& name,
- const std::string& label,
- LLHandle<LLView> branch,
- KEY key, MASK mask ) :
- LLMenuItemBranchGL( name, label, branch, key, mask )
+LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const Params& p) :
+ LLMenuItemBranchGL(p)
{
}
@@ -1473,20 +1353,26 @@ void LLMenuItemBranchDownGL::openMenu( void )
// set the hover status (called by it's menu)
void LLMenuItemBranchDownGL::setHighlight( BOOL highlight )
{
- if (highlight == getHighlight()) return;
+ if (highlight == getHighlight())
+ return;
//NOTE: Purposely calling all the way to the base to bypass auto-open.
LLMenuItemGL::setHighlight(highlight);
+
+ LLMenuGL* branch = getBranch();
+ if (!branch)
+ return;
+
if( !highlight)
{
- if (getBranch()->getTornOff())
+ if (branch->getTornOff())
{
- ((LLFloater*)getBranch()->getParent())->setFocus(FALSE);
- getBranch()->clearHoverItem();
+ ((LLFloater*)branch->getParent())->setFocus(FALSE);
+ branch->clearHoverItem();
}
else
{
- getBranch()->setVisible( FALSE );
+ branch->setVisible( FALSE );
}
}
}
@@ -1503,7 +1389,7 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
{
// switch to mouse control mode
LLMenuGL::setKeyboardMode(FALSE);
- doIt();
+ onCommit();
make_ui_sound("UISndClick");
return TRUE;
}
@@ -1542,7 +1428,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
// open new menu only if previous menu was open
if (itemp && itemp->getEnabled() && menu_open)
{
- itemp->doIt();
+ itemp->onCommit();
}
return TRUE;
@@ -1556,7 +1442,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
// open new menu only if previous menu was open
if (itemp && itemp->getEnabled() && menu_open)
{
- itemp->doIt();
+ itemp->onCommit();
}
return TRUE;
@@ -1568,7 +1454,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
if (!isActive())
{
- doIt();
+ onCommit();
}
getBranch()->highlightNextItem(NULL);
return TRUE;
@@ -1580,7 +1466,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
if (!isActive())
{
- doIt();
+ onCommit();
}
getBranch()->highlightPrevItem(NULL);
return TRUE;
@@ -1600,31 +1486,31 @@ void LLMenuItemBranchDownGL::draw( void )
if( getHighlight() )
{
- gGL.color4fv( getHighlightBGColor().mV );
+ gGL.color4fv( mHighlightBackground.get().mV );
gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
}
- U8 font_style = getFontStyle();
+ LLFontGL::ShadowType shadow_style = LLFontGL::NO_SHADOW;
if (getEnabled() && !getDrawTextDisabled() )
{
- font_style |= LLFontGL::DROP_SHADOW_SOFT;
+ shadow_style = LLFontGL::DROP_SHADOW_SOFT;
}
LLColor4 color;
if (getHighlight())
{
- color = getHighlightFGColor();
+ color = mHighlightForeground.get();
}
else if( getEnabled() )
{
- color = getEnabledColor();
+ color = mEnabledColor.get();
}
else
{
- color = getDisabledColor();
+ color = mDisabledColor.get();
}
getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
- LLFontGL::HCENTER, LLFontGL::BOTTOM, font_style );
+ LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style );
// underline navigation key only when keyboard navigation has been initiated
@@ -1647,22 +1533,118 @@ void LLMenuItemBranchDownGL::draw( void )
setHover(FALSE);
}
+
+class LLMenuScrollItem : public LLMenuItemCallGL
+{
+public:
+ enum EArrowType
+ {
+ ARROW_DOWN,
+ ARROW_UP
+ };
+ struct ArrowTypes : public LLInitParam::TypeValuesHelper<EArrowType, ArrowTypes>
+ {
+ static void declareValues()
+ {
+ declare("up", ARROW_UP);
+ declare("down", ARROW_DOWN);
+ }
+ };
+
+ struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
+ {
+ Optional<EArrowType, ArrowTypes> arrow_type;
+ Optional<CommitCallbackParam> scroll_callback;
+ };
+
+protected:
+ LLMenuScrollItem(const Params&);
+ friend class LLUICtrlFactory;
+
+public:
+ /*virtual*/ void draw();
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
+ /*virtual*/ void setEnabled(BOOL enabled);
+ virtual void onCommit( void );
+
+private:
+ LLButton* mArrowBtn;
+};
+
+LLMenuScrollItem::LLMenuScrollItem(const Params& p)
+: LLMenuItemCallGL(p)
+{
+ std::string icon;
+ if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP)
+ {
+ icon = "arrow_up.tga";
+ }
+ else
+ {
+ icon = "arrow_down.tga";
+ }
+
+ LLButton::Params bparams;
+ bparams.label("");
+ bparams.label_selected("");
+ bparams.mouse_opaque(true);
+ bparams.scale_image(false);
+ bparams.click_callback(p.scroll_callback);
+ bparams.mouse_held_callback(p.scroll_callback);
+ bparams.follows.flags(FOLLOWS_ALL);
+ std::string background = "transparent.j2c";
+ bparams.image_unselected.name(background);
+ bparams.image_disabled.name(background);
+ bparams.image_selected.name(background);
+ bparams.image_hover_selected.name(background);
+ bparams.image_disabled_selected.name(background);
+ bparams.image_hover_unselected.name(background);
+ bparams.image_overlay.name(icon);
+
+ mArrowBtn = LLUICtrlFactory::create<LLButton>(bparams);
+ addChild(mArrowBtn);
+}
+
+/*virtual*/
+void LLMenuScrollItem::draw()
+{
+ LLUICtrl::draw();
+}
+
+/*virtual*/
+void LLMenuScrollItem::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ mArrowBtn->reshape(width, height, called_from_parent);
+ LLView::reshape(width, height, called_from_parent);
+}
+
+/*virtual*/
+void LLMenuScrollItem::setEnabled(BOOL enabled)
+{
+ mArrowBtn->setEnabled(enabled);
+ LLView::setEnabled(enabled);
+}
+
+void LLMenuScrollItem::onCommit( void )
+{
+ LLUICtrl::onCommit();
+}
+
///============================================================================
/// Class LLMenuGL
///============================================================================
-static LLRegisterWidget<LLMenuGL> r1("menu");
-
-// Default constructor
-LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle<LLFloater> parent_floater_handle )
-: LLUICtrl( name, LLRect(), FALSE, NULL, NULL ),
- mBackgroundColor( sDefaultBackgroundColor ),
- mBgVisible( TRUE ),
- mParentMenuItem( NULL ),
- mLabel( label ),
- mDropShadowed( TRUE ),
- mHorizontalLayout( FALSE ),
- mKeepFixedSize( FALSE ),
+LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)
+: LLUICtrl(p),
+ mBackgroundColor( p.bg_color() ),
+ mBgVisible( p.bg_visible ),
+ mDropShadowed( p.drop_shadow ),
+ mHorizontalLayout( p.horizontal_layout ),
+ mScrollable(mHorizontalLayout ? FALSE : p.scrollable), // Scrolling is supported only for vertical layout
+ mMaxScrollableItems(p.max_scrollable_items),
+ mPreferredWidth(p.preferred_width),
+ mKeepFixedSize( p.keep_fixed_size ),
+ mLabel (p.label),
mLastMouseX(0),
mLastMouseY(0),
mMouseVelX(0),
@@ -1670,38 +1652,41 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle<
mTornOff(FALSE),
mTearOffItem(NULL),
mSpilloverBranch(NULL),
+ mFirstVisibleItem(NULL),
+ mArrowUpItem(NULL),
+ mArrowDownItem(NULL),
mSpilloverMenu(NULL),
- mParentFloaterHandle(parent_floater_handle),
- mJumpKey(KEY_NONE)
+ mJumpKey(p.jump_key),
+ mCreateJumpKeys(p.create_jump_keys),
+ mParentFloaterHandle(p.parent_floater),
+ mNeedsArrange(FALSE),
+ mShortcutPad(p.shortcut_pad)
{
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("_");
+ tokenizer tokens(p.label(), sep);
+ tokenizer::iterator token_iter;
+
+ S32 token_count = 0;
+ std::string new_menu_label;
+ for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+ {
+ new_menu_label += (*token_iter);
+ if (token_count > 0)
+ {
+ setJumpKey((*token_iter).c_str()[0]);
+ }
+ ++token_count;
+ }
+ setLabel(new_menu_label);
+
mFadeTimer.stop();
- setCanTearOff(TRUE, parent_floater_handle);
- setTabStop(FALSE);
-}
-
-LLMenuGL::LLMenuGL( const std::string& label, LLHandle<LLFloater> parent_floater_handle )
-: LLUICtrl( label, LLRect(), FALSE, NULL, NULL ),
- mBackgroundColor( sDefaultBackgroundColor ),
- mBgVisible( TRUE ),
- mParentMenuItem( NULL ),
- mLabel( label ),
- mDropShadowed( TRUE ),
- mHorizontalLayout( FALSE ),
- mKeepFixedSize( FALSE ),
- mLastMouseX(0),
- mLastMouseY(0),
- mMouseVelX(0),
- mMouseVelY(0),
- mTornOff(FALSE),
- mTearOffItem(NULL),
- mSpilloverBranch(NULL),
- mSpilloverMenu(NULL),
- mParentFloaterHandle(parent_floater_handle),
- mJumpKey(KEY_NONE)
+}
+
+void LLMenuGL::initFromParams(const LLMenuGL::Params& p)
{
- mFadeTimer.stop();
- setCanTearOff(TRUE, parent_floater_handle);
- setTabStop(FALSE);
+ LLUICtrl::initFromParams(p);
+ setCanTearOff(p.can_tear_off, p.parent_floater);
}
// Destroys the object
@@ -1717,10 +1702,10 @@ void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle<LLFloater> parent_floater_h
{
if (tear_off && mTearOffItem == NULL)
{
- mTearOffItem = new LLMenuItemTearOffGL(parent_floater_handle);
- mItems.insert(mItems.begin(), mTearOffItem);
- addChildAtEnd(mTearOffItem);
- arrange();
+ LLMenuItemTearOffGL::Params p;
+ p.parent_floater_handle = parent_floater_handle;
+ mTearOffItem = LLUICtrlFactory::create<LLMenuItemTearOffGL>(p);
+ addChildInBack(mTearOffItem);
}
else if (!tear_off && mTearOffItem != NULL)
{
@@ -1728,313 +1713,45 @@ void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle<LLFloater> parent_floater_h
removeChild(mTearOffItem);
delete mTearOffItem;
mTearOffItem = NULL;
- arrange();
+ needsArrange();
}
}
-// virtual
-LLXMLNodePtr LLMenuGL::getXML(bool save_children) const
+bool LLMenuGL::addChild(LLView* view, S32 tab_group)
{
- LLXMLNodePtr node = LLView::getXML();
-
- // Attributes
-
- node->createChild("opaque", TRUE)->setBoolValue(mBgVisible);
-
- node->createChild("drop_shadow", TRUE)->setBoolValue(mDropShadowed);
-
- node->createChild("tear_off", TRUE)->setBoolValue((mTearOffItem != NULL));
-
- if (mBgVisible)
+ if (LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view))
{
- // TomY TODO: this should save out the color control name
- node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
+ appendMenu(menup);
+ return true;
}
-
- // Contents
- item_list_t::const_iterator item_iter;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+ else if (LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(view))
{
- LLView* child = (*item_iter);
- LLMenuItemGL* item = (LLMenuItemGL*)child;
-
- LLXMLNodePtr child_node = item->getXML();
-
- node->addChild(child_node);
+ append(itemp);
+ return true;
}
-
- return node;
+ return false;
}
-void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory)
+void LLMenuGL::removeChild( LLView* ctrl)
{
- if (child->hasName(LL_MENU_GL_TAG))
+ // previously a dynamic_cast with if statement to check validity
+ // unfortunately removeChild is called by ~LLView, and at that point the
+ // object being deleted is no longer a LLMenuItemGL so a dynamic_cast will fail
+ LLMenuItemGL* itemp = static_cast<LLMenuItemGL*>(ctrl);
+
+ item_list_t::iterator found_it = std::find(mItems.begin(), mItems.end(), (itemp));
+ if (found_it != mItems.end())
{
- // SUBMENU
- LLMenuGL *submenu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory);
- appendMenu(submenu);
- if (LLMenuGL::sMenuContainer != NULL)
- {
- submenu->updateParent(LLMenuGL::sMenuContainer);
- }
- else
- {
- submenu->updateParent(parent);
- }
+ mItems.erase(found_it);
}
- else if (child->hasName(LL_MENU_ITEM_CALL_GL_TAG) ||
- child->hasName(LL_MENU_ITEM_CHECK_GL_TAG) ||
- child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG))
- {
- LLMenuItemGL *item = NULL;
-
- std::string type;
- std::string item_name;
- std::string source_label;
- std::string item_label;
- KEY jump_key = KEY_NONE;
-
- child->getAttributeString("type", type);
- child->getAttributeString("name", item_name);
- child->getAttributeString("label", source_label);
-
- // parse jump key out of label
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("_");
- tokenizer tokens(source_label, sep);
- tokenizer::iterator token_iter;
- S32 token_count = 0;
- for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
- {
- item_label += (*token_iter);
- if (token_count > 0)
- {
- jump_key = (*token_iter).c_str()[0];
- }
- ++token_count;
- }
+ return LLUICtrl::removeChild(ctrl);
+}
- if (child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG))
- {
- appendSeparator(item_name);
- }
- else
- {
- // ITEM
- if (child->hasName(LL_MENU_ITEM_CALL_GL_TAG) ||
- child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
- {
- MASK mask = 0;
-
-#ifdef LL_DARWIN
- // See if this Mac accelerator should really use the ctrl key and not get mapped to cmd
- BOOL useMacCtrl = FALSE;
- child->getAttributeBOOL("useMacCtrl", useMacCtrl);
-#endif // LL_DARWIN
-
- std::string shortcut;
- child->getAttributeString("shortcut", shortcut);
- if (shortcut.find("control") != shortcut.npos)
- {
-#ifdef LL_DARWIN
- if ( useMacCtrl )
- {
- mask |= MASK_MAC_CONTROL;
- }
-#endif // LL_DARWIN
- mask |= MASK_CONTROL;
- }
- if (shortcut.find("alt") != shortcut.npos)
- {
- mask |= MASK_ALT;
- }
- if (shortcut.find("shift") != shortcut.npos)
- {
- mask |= MASK_SHIFT;
- }
- S32 pipe_pos = shortcut.rfind("|");
- std::string key_str = shortcut.substr(pipe_pos+1);
-
- KEY key = KEY_NONE;
- LLKeyboard::keyFromString(key_str, &key);
-
- LLMenuItemCallGL *new_item;
- LLXMLNodePtr call_child;
-
- if (child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
- {
- std::string control_name;
- child->getAttributeString("control_name", control_name);
-
- new_item = new LLMenuItemCheckGL(item_name, item_label, 0, 0, control_name, parent, 0, key, mask);
-
- for (call_child = child->getFirstChild(); call_child.notNull(); call_child = call_child->getNextSibling())
- {
- if (call_child->hasName("on_check"))
- {
- std::string callback_name;
- std::string control_name;
- if (call_child->hasAttribute("function"))
- {
- call_child->getAttributeString("function", callback_name);
-
- control_name = callback_name;
-
- std::string callback_data = item_name;
- if (call_child->hasAttribute("userdata"))
- {
- call_child->getAttributeString("userdata", callback_data);
- if (!callback_data.empty())
- {
- control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
- }
- }
-
- LLSD userdata;
- userdata["control"] = control_name;
- userdata["data"] = callback_data;
-
- LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
- if (!callback) continue;
-
- new_item->addListener(callback, "on_build", userdata);
- }
- else if (call_child->hasAttribute("control"))
- {
- call_child->getAttributeString("control", control_name);
- }
- else
- {
- continue;
- }
- LLControlVariable *control = parent->findControl(control_name);
- if (!control)
- {
- parent->addBoolControl(control_name, FALSE);
- }
- ((LLMenuItemCheckGL*)new_item)->setCheckedControl(control_name, parent);
- }
- }
- }
- else
- {
- new_item = new LLMenuItemCallGL(item_name, item_label, 0, 0, 0, 0, key, mask);
- }
-
- for (call_child = child->getFirstChild(); call_child.notNull(); call_child = call_child->getNextSibling())
- {
- if (call_child->hasName("on_click"))
- {
- std::string callback_name;
- call_child->getAttributeString("function", callback_name);
-
- std::string callback_data = item_name;
- if (call_child->hasAttribute("userdata"))
- {
- call_child->getAttributeString("userdata", callback_data);
- }
-
- LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
- if (!callback) continue;
-
- new_item->addListener(callback, "on_click", callback_data);
- }
- if (call_child->hasName("on_enable"))
- {
- std::string callback_name;
- std::string control_name;
- if (call_child->hasAttribute("function"))
- {
- call_child->getAttributeString("function", callback_name);
-
- control_name = callback_name;
-
- std::string callback_data;
- if (call_child->hasAttribute("userdata"))
- {
- call_child->getAttributeString("userdata", callback_data);
- if (!callback_data.empty())
- {
- control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
- }
- }
-
- LLSD userdata;
- userdata["control"] = control_name;
- userdata["data"] = callback_data;
-
- LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
- if (!callback) continue;
-
- new_item->addListener(callback, "on_build", userdata);
- }
- else if (call_child->hasAttribute("control"))
- {
- call_child->getAttributeString("control", control_name);
- }
- else
- {
- continue;
- }
- new_item->setEnabledControl(control_name, parent);
- }
- if (call_child->hasName("on_visible"))
- {
- std::string callback_name;
- std::string control_name;
- if (call_child->hasAttribute("function"))
- {
- call_child->getAttributeString("function", callback_name);
-
- control_name = callback_name;
-
- std::string callback_data;
- if (call_child->hasAttribute("userdata"))
- {
- call_child->getAttributeString("userdata", callback_data);
- if (!callback_data.empty())
- {
- control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
- }
- }
-
- LLSD userdata;
- userdata["control"] = control_name;
- userdata["data"] = callback_data;
-
- LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
- if (!callback) continue;
-
- new_item->addListener(callback, "on_build", userdata);
- }
- else if (call_child->hasAttribute("control"))
- {
- call_child->getAttributeString("control", control_name);
- }
- else
- {
- continue;
- }
- new_item->setVisibleControl(control_name, parent);
- }
- }
- item = new_item;
- item->setLabel(item_label);
- if (jump_key != KEY_NONE)
- item->setJumpKey(jump_key);
- }
-
- if (item != NULL)
- {
- append(item);
- }
- }
- }
+BOOL LLMenuGL::postBuild()
+{
+ createJumpKeys();
+ return LLUICtrl::postBuild();
}
// are we the childmost active menu and hence our jump keys should be enabled?
@@ -2081,77 +1798,88 @@ BOOL LLMenuGL::isOpen()
return getVisible();
}
}
-// static
-LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
- std::string name("menu");
- node->getAttributeString("name", name);
-
- std::string label = name;
- node->getAttributeString("label", label);
-
- // parse jump key out of label
- std::string new_menu_label;
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("_");
- tokenizer tokens(label, sep);
- tokenizer::iterator token_iter;
+void LLMenuGL::scrollItemsUp()
+{
+ // Slowing down the items scrolling when arrow button is held
+ if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)
+ {
+ mScrollItemsTimer.setTimerExpirySec(.033f);
+ }
+ else
+ {
+ return;
+ }
- KEY jump_key = KEY_NONE;
- S32 token_count = 0;
- for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+ item_list_t::iterator cur_item_iter;
+ item_list_t::iterator prev_item_iter;
+ for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- new_menu_label += (*token_iter);
- if (token_count > 0)
+ if( (*cur_item_iter) == mFirstVisibleItem)
{
- jump_key = (*token_iter).c_str()[0];
+ break;
+ }
+ if ((*cur_item_iter)->getVisible())
+ {
+ prev_item_iter = cur_item_iter;
}
- ++token_count;
}
- BOOL opaque = FALSE;
- node->getAttributeBOOL("opaque", opaque);
-
- LLMenuGL *menu = new LLMenuGL(name, new_menu_label);
-
- menu->setJumpKey(jump_key);
-
- BOOL tear_off = FALSE;
- node->getAttributeBOOL("tear_off", tear_off);
- menu->setCanTearOff(tear_off);
+ if ((*prev_item_iter)->getVisible())
+ {
+ mFirstVisibleItem = *prev_item_iter;
+ }
+
+ mNeedsArrange = TRUE;
+ arrangeAndClear();
+}
- if (node->hasAttribute("drop_shadow"))
+void LLMenuGL::scrollItemsDown()
+{
+ // Slowing down the items scrolling when arrow button is held
+ if (mScrollItemsTimer.hasExpired())
{
- BOOL drop_shadow = FALSE;
- node->getAttributeBOOL("drop_shadow", drop_shadow);
- menu->setDropShadowed(drop_shadow);
+ mScrollItemsTimer.setTimerExpirySec(.033f);
+ }
+ else
+ {
+ return;
+ }
+
+ if (NULL == mFirstVisibleItem)
+ {
+ mFirstVisibleItem = *mItems.begin();
}
- menu->setBackgroundVisible(opaque);
- LLColor4 color(0,0,0,1);
- if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
+ item_list_t::iterator cur_item_iter;
+
+ for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- menu->setBackgroundColor(color);
+ if( (*cur_item_iter) == mFirstVisibleItem)
+ {
+ break;
+ }
}
- BOOL create_jump_keys = FALSE;
- node->getAttributeBOOL("create_jump_keys", create_jump_keys);
+ item_list_t::iterator next_item_iter;
- LLXMLNodePtr child;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+ for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
{
- menu->parseChildXML(child, parent, factory);
+ if( (*next_item_iter)->getVisible())
+ {
+ break;
+ }
}
- if (create_jump_keys)
+ if ((*next_item_iter)->getVisible())
{
- menu->createJumpKeys();
+ mFirstVisibleItem = *next_item_iter;
}
- return menu;
+
+ mNeedsArrange = TRUE;
+ arrangeAndClear();
}
-
// rearrange the child rects so they fit the shape of the menu.
void LLMenuGL::arrange( void )
{
@@ -2169,11 +1897,27 @@ void LLMenuGL::arrange( void )
// torn off menus are not constrained to the size of the screen
U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth();
- U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight();
+ U32 max_height = U32_MAX;
+ if (!getTornOff())
+ {
+ max_height = getRect().mTop - menu_region_rect.mBottom;
+ if (menu_region_rect.mTop - getRect().mTop > (S32)max_height)
+ {
+ max_height = menu_region_rect.mTop - getRect().mTop;
+ }
+ }
+
// *FIX: create the item first and then ask for its dimensions?
- S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") );
+ S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate
S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING;
+ // Scrolling support
+ item_list_t::iterator first_visible_item_iter;
+ item_list_t::iterator first_hidden_item_iter = mItems.end();
+ S32 height_before_first_visible_item = -1;
+ S32 visible_items_height = 0;
+ U32 scrollable_items_cnt = 0;
+
if (mHorizontalLayout)
{
item_list_t::iterator item_iter;
@@ -2182,26 +1926,27 @@ void LLMenuGL::arrange( void )
if ((*item_iter)->getVisible())
{
if (!getTornOff()
- && item_iter != mItems.begin() // Don't spillover the first item!
+ && *item_iter != mSpilloverBranch
&& width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width)
{
// no room for any more items
createSpilloverBranch();
- item_list_t::iterator spillover_iter;
- for (spillover_iter = item_iter; spillover_iter != mItems.end(); ++spillover_iter)
+ std::vector<LLMenuItemGL*> items_to_remove;
+ std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove));
+ std::vector<LLMenuItemGL*>::iterator spillover_iter;
+ for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter)
{
LLMenuItemGL* itemp = (*spillover_iter);
removeChild(itemp);
- mSpilloverMenu->appendNoArrange(itemp); // *NOTE:Mani Favor addChild() in merge with skinning
+ mSpilloverMenu->addChild(itemp);
}
- mSpilloverMenu->arrange(); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mItems.erase(item_iter, mItems.end());
- mItems.push_back(mSpilloverBranch);
+
addChild(mSpilloverBranch);
+
height = llmax(height, mSpilloverBranch->getNominalHeight());
width += mSpilloverBranch->getNominalWidth();
+
break;
}
else
@@ -2216,31 +1961,35 @@ void LLMenuGL::arrange( void )
else
{
item_list_t::iterator item_iter;
+
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter)->getVisible())
{
if (!getTornOff()
- && item_iter != mItems.begin() // Don't spillover the first item!
+ && !mScrollable
+ && *item_iter != mSpilloverBranch
&& height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height)
{
// no room for any more items
createSpilloverBranch();
- item_list_t::iterator spillover_iter;
- for (spillover_iter= item_iter; spillover_iter != mItems.end(); ++spillover_iter)
+ std::vector<LLMenuItemGL*> items_to_remove;
+ std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove));
+ std::vector<LLMenuItemGL*>::iterator spillover_iter;
+ for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter)
{
LLMenuItemGL* itemp = (*spillover_iter);
removeChild(itemp);
- mSpilloverMenu->appendNoArrange(itemp); // *NOTE:Mani Favor addChild() in merge with skinning
+ mSpilloverMenu->addChild(itemp);
}
- mSpilloverMenu->arrange(); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mItems.erase(item_iter, mItems.end());
- mItems.push_back(mSpilloverBranch);
+
+
addChild(mSpilloverBranch);
+
height += mSpilloverBranch->getNominalHeight();
width = llmax( width, mSpilloverBranch->getNominalWidth() );
+
break;
}
else
@@ -2249,19 +1998,173 @@ void LLMenuGL::arrange( void )
height += (*item_iter)->getNominalHeight();
width = llmax( width, (*item_iter)->getNominalWidth() );
}
+
+ if (mScrollable)
+ {
+ // Determining visible items boundaries
+ if (NULL == mFirstVisibleItem)
+ {
+ mFirstVisibleItem = *item_iter;
+ }
+
+ if (*item_iter == mFirstVisibleItem)
+ {
+ height_before_first_visible_item = height - (*item_iter)->getNominalHeight();
+ first_visible_item_iter = item_iter;
+ scrollable_items_cnt = 0;
+ }
+
+ if (-1 != height_before_first_visible_item && 0 == visible_items_height &&
+ (++scrollable_items_cnt > mMaxScrollableItems ||
+ height - height_before_first_visible_item > max_height - spillover_item_height * 2 ))
+ {
+ first_hidden_item_iter = item_iter;
+ visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight();
+ scrollable_items_cnt--;
+ }
+ }
}
}
- }
- setRect(LLRect(getRect().mLeft, getRect().mBottom + height, getRect().mLeft + width, getRect().mBottom));
+ if (mPreferredWidth < U32_MAX)
+ width = llmin(mPreferredWidth, max_width);
+
+ if (mScrollable)
+ {
+ S32 max_items_height = max_height - spillover_item_height * 2;
+
+ if (visible_items_height == 0)
+ visible_items_height = height - height_before_first_visible_item;
+
+ // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit
+ if (visible_items_height < max_items_height && scrollable_items_cnt < mMaxScrollableItems)
+ {
+ item_list_t::iterator tmp_iter(first_visible_item_iter);
+ while (visible_items_height < max_items_height &&
+ scrollable_items_cnt < mMaxScrollableItems &&
+ first_visible_item_iter != mItems.begin())
+ {
+ if ((*first_visible_item_iter)->getVisible())
+ {
+ // It keeps visible item, after first_visible_item_iter
+ tmp_iter = first_visible_item_iter;
+ }
+
+ first_visible_item_iter--;
+
+ if ((*first_visible_item_iter)->getVisible())
+ {
+ visible_items_height += (*first_visible_item_iter)->getNominalHeight();
+ height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight();
+ scrollable_items_cnt++;
+ }
+ }
+
+ // Roll back one item, that doesn't fit
+ if (visible_items_height > max_items_height)
+ {
+ visible_items_height -= (*first_visible_item_iter)->getNominalHeight();
+ height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight();
+ scrollable_items_cnt--;
+ first_visible_item_iter = tmp_iter;
+ }
+ if (!(*first_visible_item_iter)->getVisible())
+ {
+ first_visible_item_iter = tmp_iter;
+ }
+
+ mFirstVisibleItem = *first_visible_item_iter;
+ }
+ }
+ }
S32 cur_height = (S32)llmin(max_height, height);
+
+ if (mScrollable &&
+ (height_before_first_visible_item > MENU_ITEM_PADDING ||
+ height_before_first_visible_item + visible_items_height < (S32)height))
+ {
+ // Reserving 2 extra slots for arrow items
+ cur_height = visible_items_height + spillover_item_height * 2;
+ }
+
+ setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height));
+
S32 cur_width = 0;
+ S32 offset = 0;
+ if (mScrollable)
+ {
+ // No space for all items, creating arrow items
+ if (height_before_first_visible_item > MENU_ITEM_PADDING ||
+ height_before_first_visible_item + visible_items_height < (S32)height)
+ {
+ if (NULL == mArrowUpItem)
+ {
+ LLMenuScrollItem::Params item_params;
+ item_params.name(ARROW_UP);
+ item_params.arrow_type(LLMenuScrollItem::ARROW_UP);
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this));
+
+ mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
+ LLUICtrl::addChild(mArrowUpItem);
+
+ }
+ if (NULL == mArrowDownItem)
+ {
+ LLMenuScrollItem::Params item_params;
+ item_params.name(ARROW_DOWN);
+ item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN);
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this));
+
+ mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
+ LLUICtrl::addChild(mArrowDownItem);
+ }
+
+ LLRect rect;
+ mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight()));
+ mArrowUpItem->setVisible(TRUE);
+ mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING);
+ mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight());
+ mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight()));
+ mArrowDownItem->setVisible(TRUE);
+ mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height);
+ mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight());
+
+ cur_height -= mArrowUpItem->getNominalHeight();
+
+ offset = menu_region_rect.mRight; // This moves items behind visible area
+ }
+ else
+ {
+ if (NULL != mArrowUpItem)
+ {
+ mArrowUpItem->setVisible(FALSE);
+ }
+ if (NULL != mArrowDownItem)
+ {
+ mArrowDownItem->setVisible(FALSE);
+ }
+ }
+
+ }
+
item_list_t::iterator item_iter;
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter)->getVisible())
{
+ if (mScrollable)
+ {
+ if (item_iter == first_visible_item_iter)
+ {
+ offset = 0;
+ }
+ else if (item_iter == first_hidden_item_iter)
+ {
+ offset = menu_region_rect.mRight; // This moves items behind visible area
+ }
+ }
+
// setup item rect to hold label
LLRect rect;
if (mHorizontalLayout)
@@ -2271,8 +2174,11 @@ void LLMenuGL::arrange( void )
}
else
{
- rect.setLeftTopAndSize( 0, cur_height, width, (*item_iter)->getNominalHeight());
- cur_height -= (*item_iter)->getNominalHeight();
+ rect.setLeftTopAndSize( 0 + offset, cur_height, width, (*item_iter)->getNominalHeight());
+ if (offset == 0)
+ {
+ cur_height -= (*item_iter)->getNominalHeight();
+ }
}
(*item_iter)->setRect( rect );
(*item_iter)->buildDrawLabel();
@@ -2285,6 +2191,15 @@ void LLMenuGL::arrange( void )
}
}
+void LLMenuGL::arrangeAndClear( void )
+{
+ if (mNeedsArrange)
+ {
+ arrange();
+ mNeedsArrange = FALSE;
+ }
+}
+
void LLMenuGL::createSpilloverBranch()
{
if (!mSpilloverBranch)
@@ -2293,14 +2208,24 @@ void LLMenuGL::createSpilloverBranch()
delete mSpilloverMenu;
// technically, you can't tear off spillover menus, but we're passing the handle
// along just to be safe
- mSpilloverMenu = new LLMenuGL(std::string("More"), std::string("More"), mParentFloaterHandle);
+ LLMenuGL::Params p;
+ p.name("More");
+ p.label("More"); // *TODO: Translate
+ p.parent_floater(mParentFloaterHandle);
+ p.bg_color(mBackgroundColor);
+ p.bg_visible(true);
+ p.can_tear_off(false);
+ mSpilloverMenu = new LLMenuGL(p);
mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer);
- // Inherit colors
- mSpilloverMenu->setBackgroundColor( mBackgroundColor );
- mSpilloverMenu->setCanTearOff(FALSE);
- mSpilloverBranch = new LLMenuItemBranchGL(std::string("More"), std::string("More"), mSpilloverMenu->getHandle());
- mSpilloverBranch->setFontStyle(LLFontGL::ITALIC);
+ LLMenuItemBranchGL::Params branch_params;
+ branch_params.name = "More";
+ branch_params.label = "More"; // *TODO: Translate
+ branch_params.branch = mSpilloverMenu;
+ branch_params.font.style = "italic";
+
+
+ mSpilloverBranch = LLUICtrlFactory::create<LLMenuItemBranchGL>(branch_params);
}
}
@@ -2311,25 +2236,15 @@ void LLMenuGL::cleanupSpilloverBranch()
// head-recursion to propagate items back up to root menu
mSpilloverMenu->cleanupSpilloverBranch();
- removeChild(mSpilloverBranch);
-
- item_list_t::iterator found_iter = std::find(mItems.begin(), mItems.end(), mSpilloverBranch);
- if (found_iter != mItems.end())
- {
- mItems.erase(found_iter);
- }
-
// pop off spillover items
while (mSpilloverMenu->getItemCount())
{
LLMenuItemGL* itemp = mSpilloverMenu->getItem(0);
mSpilloverMenu->removeChild(itemp);
- mSpilloverMenu->mItems.erase(mSpilloverMenu->mItems.begin());
// put them at the end of our own list
- mItems.push_back(itemp);
addChild(itemp);
}
-
+
// Delete the branch, and since the branch will delete the menu,
// set the menu* to null.
delete mSpilloverBranch;
@@ -2340,6 +2255,9 @@ void LLMenuGL::cleanupSpilloverBranch()
void LLMenuGL::createJumpKeys()
{
+ if (!mCreateJumpKeys) return;
+ mCreateJumpKeys = FALSE;
+
mJumpKeys.clear();
std::set<std::string> unique_words;
@@ -2440,16 +2358,18 @@ void LLMenuGL::empty( void )
cleanupSpilloverBranch();
mItems.clear();
+ mFirstVisibleItem = NULL;
+ mArrowUpItem = NULL;
+ mArrowDownItem = NULL;
deleteAllChildren();
-
}
// Adjust rectangle of the menu
void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom)
{
setRect(LLRect(left, getRect().mTop, getRect().mRight, bottom));
- arrange();
+ needsArrange();
}
BOOL LLMenuGL::handleJumpKey(KEY key)
@@ -2462,12 +2382,9 @@ BOOL LLMenuGL::handleJumpKey(KEY key)
// switch to keyboard navigation mode
LLMenuGL::setKeyboardMode(TRUE);
- // force highlight to close old menus and any open sub-menus
-
- //clearHoverItem();
// force highlight to close old menus and open and sub-menus
found_it->second->setHighlight(TRUE);
- found_it->second->doIt();
+ found_it->second->onCommit();
}
// if we are navigating the menus, we need to eat the keystroke
@@ -2479,30 +2396,18 @@ BOOL LLMenuGL::handleJumpKey(KEY key)
// Add the menu item to this menu.
BOOL LLMenuGL::append( LLMenuItemGL* item )
{
+ if (!item) return FALSE;
mItems.push_back( item );
- addChild( item );
- arrange();
- return TRUE;
-}
-
-// *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0
-// Its added as a fix to a viewer 1.23 bug that has already been address by skinning work.
-BOOL LLMenuGL::appendNoArrange( LLMenuItemGL* item )
-{
- mItems.push_back( item );
- addChild( item );
+ LLUICtrl::addChild(item);
+ needsArrange();
return TRUE;
}
// add a separator to this menu
-BOOL LLMenuGL::appendSeparator( const std::string &separator_name )
+BOOL LLMenuGL::addSeparator()
{
- LLMenuItemGL* separator;
- if (separator_name.empty())
- separator = new LLMenuItemSeparatorGL(std::string("separator"));
- else
- separator = new LLMenuItemSeparatorGL(separator_name);
- return append( separator );
+ LLMenuItemGL* separator = new LLMenuItemSeparatorGL();
+ return addChild(separator);
}
// add a menu - this will create a cascading menu
@@ -2515,14 +2420,22 @@ BOOL LLMenuGL::appendMenu( LLMenuGL* menu )
}
BOOL success = TRUE;
- LLMenuItemBranchGL* branch = NULL;
- branch = new LLMenuItemBranchGL( menu->getName(), menu->getLabel(), menu->getHandle() );
- branch->setJumpKey(menu->getJumpKey());
+ LLMenuItemBranchGL::Params p;
+ p.name = menu->getName();
+ p.label = menu->getLabel();
+ p.branch = menu;
+ p.jump_key = menu->getJumpKey();
+ p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor");
+ p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor");
+ p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor");
+ p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor");
+
+ LLMenuItemBranchGL* branch = LLUICtrlFactory::create<LLMenuItemBranchGL>(p);
success &= append( branch );
// Inherit colors
menu->setBackgroundColor( mBackgroundColor );
-
+ menu->updateParent(LLMenuGL::sMenuContainer);
return success;
}
@@ -2560,6 +2473,7 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible )
if( (*item_iter)->getName() == name )
{
(*item_iter)->setVisible( visible );
+ needsArrange();
break;
}
}
@@ -2572,7 +2486,7 @@ void LLMenuGL::setItemLastSelected(LLMenuItemGL* item)
LLMenuHolderGL::setActivatedItem(item);
}
- // fix the checkmarks
+ // update enabled and checkmark status
item->buildDrawLabel();
}
@@ -2670,7 +2584,7 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
while(1)
{
// skip separators and disabled/invisible items
- if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && (*next_item_iter)->getType() != SEPARATOR_NAME)
+ if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && !dynamic_cast<LLMenuItemSeparatorGL*>(*next_item_iter))
{
if (cur_item)
{
@@ -2777,7 +2691,10 @@ void LLMenuGL::updateParent(LLView* parentp)
{
getParent()->removeChild(this);
}
- parentp->addChild(this);
+ if (parentp)
+ {
+ parentp->addChild(this);
+ }
item_list_t::iterator item_iter;
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
@@ -2880,29 +2797,59 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
}
}
getWindow()->setCursor(UI_CURSOR_ARROW);
+
+ // *HACK Release the mouse capture
+ // This is done to release the mouse after the Navigation Bar "Back" or "Forward" button
+ // drop-down menu is shown. Otherwise any other view won't be able to handle mouse events
+ // until the user chooses one of the drop-down menu items.
+
+ return TRUE;
+}
+
+BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ if (!mScrollable)
+ return blockMouseEvent(x, y);
+
+ if( clicks > 0 )
+ {
+ while( clicks-- )
+ scrollItemsDown();
+ }
+ else
+ {
+ while( clicks++ )
+ scrollItemsUp();
+ }
+
return TRUE;
}
void LLMenuGL::draw( void )
{
+ if (mNeedsArrange)
+ {
+ arrange();
+ mNeedsArrange = FALSE;
+ }
if (mDropShadowed && !mTornOff)
{
+ static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0);
+ static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
- LLUI::sColorsGroup->getColor("ColorDropShadow"),
- LLUI::sConfigGroup->getS32("DropShadowFloater") );
+ color_drop_shadow, drop_shadow_floater );
}
- LLColor4 bg_color = mBackgroundColor;
-
if( mBgVisible )
{
- gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor );
+ gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor.get() );
}
LLView::draw();
}
-void LLMenuGL::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
+void LLMenuGL::drawBackground(LLMenuItemGL* itemp, F32 alpha)
{
+ LLColor4 color = itemp->getHighlightBgColor() % alpha;
gGL.color4fv( color.mV );
LLRect item_rect = itemp->getRect();
gl_rect_2d( 0, item_rect.getHeight(), item_rect.getWidth(), 0);
@@ -2931,9 +2878,9 @@ void LLMenuGL::setVisible(BOOL visible)
}
}
-LLMenuGL* LLMenuGL::getChildMenuByName(const std::string& name, BOOL recurse) const
+LLMenuGL* LLMenuGL::findChildMenuByName(const std::string& name, BOOL recurse) const
{
- LLView* view = getChildView(name, recurse, FALSE);
+ LLView* view = findChildView(name, recurse);
if (view)
{
LLMenuItemBranchGL* branch = dynamic_cast<LLMenuItemBranchGL*>(view);
@@ -2972,9 +2919,19 @@ void hide_top_view( LLView* view )
}
+// x and y are the desired location for the popup, NOT necessarily the
+// mouse location
// static
void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
{
+ // Save click point for detecting cursor moves before mouse-up.
+ // Must be in local coords to compare with mouseUp events.
+ // If the mouse doesn't move, the menu will stay open ala the Mac.
+ // See also LLContextMenu::show()
+ S32 mouse_x, mouse_y;
+ LLUI::getCursorPositionLocal(menu->getParent(), &mouse_x, &mouse_y);
+ LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y);
+
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
const S32 HPAD = 2;
@@ -2985,23 +2942,27 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
spawning_view->localPointToOtherView(left, top, &left, &top, menu->getParent());
rect.setLeftTopAndSize( left, top,
rect.getWidth(), rect.getHeight() );
-
-
- //rect.setLeftTopAndSize(x + HPAD, y, rect.getWidth(), rect.getHeight());
menu->setRect( rect );
+ // Resetting scrolling position
+ if (menu->isScrollable())
+ {
+ menu->mFirstVisibleItem = NULL;
+ menu->needsArrange();
+ }
+ menu->arrangeAndClear(); // Fix menu rect if needed.
+ rect = menu->getRect();
+
+ // Adjust context menu to fit onscreen
S32 bottom;
left = rect.mLeft;
bottom = rect.mBottom;
- //menu->getParent()->localPointToScreen( rect.mLeft, rect.mBottom,
- // &left, &bottom );
S32 delta_x = 0;
S32 delta_y = 0;
if( bottom < menu_region_rect.mBottom )
{
// At this point, we need to move the context menu to the
// other side of the mouse.
- //delta_y = menu_region_rect.mBottom - bottom;
delta_y = (rect.getHeight() + 2 * HPAD);
}
@@ -3009,7 +2970,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
{
// At this point, we need to move the context menu to the
// other side of the mouse.
- //delta_x = (window_width - rect.getWidth()) - x;
delta_x = -(rect.getWidth() + 2 * HPAD);
}
menu->translate( delta_x, delta_y );
@@ -3017,794 +2977,16 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
menu->getParent()->sendChildToFront(menu);
}
-//-----------------------------------------------------------------------------
-// class LLPieMenuBranch
-// A branch to another pie menu
-//-----------------------------------------------------------------------------
-class LLPieMenuBranch : public LLMenuItemGL
-{
-public:
- LLPieMenuBranch(const std::string& name, const std::string& label, LLPieMenu* branch);
-
- // called to rebuild the draw label
- virtual void buildDrawLabel( void );
-
- // doIt() - do the primary funcationality of the menu item.
- virtual void doIt( void );
-
- LLPieMenu* getBranch() { return mBranch; }
-
-protected:
- LLPieMenu* mBranch;
-};
-
-LLPieMenuBranch::LLPieMenuBranch(const std::string& name,
- const std::string& label,
- LLPieMenu* branch)
-: LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ),
- mBranch( branch )
-{
- mBranch->hide(FALSE);
- mBranch->setParentMenuItem(this);
-}
-
-// called to rebuild the draw label
-void LLPieMenuBranch::buildDrawLabel( void )
-{
- {
- // default enablement is this -- if any of the subitems are
- // enabled, this item is enabled. JC
- U32 sub_count = mBranch->getItemCount();
- U32 i;
- BOOL any_enabled = FALSE;
- for (i = 0; i < sub_count; i++)
- {
- LLMenuItemGL* item = mBranch->getItem(i);
- item->buildDrawLabel();
- if (item->getEnabled() && !item->getDrawTextDisabled() )
- {
- any_enabled = TRUE;
- break;
- }
- }
- setDrawTextDisabled(!any_enabled);
- setEnabled(TRUE);
- }
-
- mDrawAccelLabel.clear();
- std::string st = mDrawAccelLabel;
- appendAcceleratorString( st );
- mDrawAccelLabel = st;
-
- // No special branch suffix
- mDrawBranchLabel.clear();
-}
-
-// doIt() - do the primary funcationality of the menu item.
-void LLPieMenuBranch::doIt( void )
-{
- LLPieMenu *parent = (LLPieMenu *)getParent();
-
- LLRect rect = parent->getRect();
- S32 center_x;
- S32 center_y;
- parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, &center_x, &center_y);
-
- parent->hide(FALSE);
- mBranch->show( center_x, center_y, FALSE );
-}
-
-//-----------------------------------------------------------------------------
-// class LLPieMenu
-// A circular menu of items, icons, etc.
-//-----------------------------------------------------------------------------
-LLPieMenu::LLPieMenu(const std::string& name, const std::string& label)
-: LLMenuGL(name, label),
- mFirstMouseDown(FALSE),
- mUseInfiniteRadius(FALSE),
- mHoverItem(NULL),
- mHoverThisFrame(FALSE),
- mHoveredAnyItem(FALSE),
- mOuterRingAlpha(1.f),
- mCurRadius(0.f),
- mRightMouseDown(FALSE)
-{
- LLMenuGL::setVisible(FALSE);
- setCanTearOff(FALSE);
-}
-
-LLPieMenu::LLPieMenu(const std::string& name)
-: LLMenuGL(name, name),
- mFirstMouseDown(FALSE),
- mUseInfiniteRadius(FALSE),
- mHoverItem(NULL),
- mHoverThisFrame(FALSE),
- mHoveredAnyItem(FALSE),
- mOuterRingAlpha(1.f),
- mCurRadius(0.f),
- mRightMouseDown(FALSE)
-{
- LLMenuGL::setVisible(FALSE);
- setCanTearOff(FALSE);
-}
-
-
-void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory)
-{
- LLXMLNodePtr child;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
- {
- if (child->hasName(LL_PIE_MENU_TAG))
- {
- // SUBMENU
- std::string name("menu");
- child->getAttributeString("name", name);
- std::string label(name);
- child->getAttributeString("label", label);
-
- LLPieMenu *submenu = new LLPieMenu(name, label);
- appendPieMenu(submenu);
- submenu->initXML(child, context, factory);
- }
- else
- {
- parseChildXML(child, context, factory);
- }
- }
-}
-
-// virtual
-void LLPieMenu::setVisible(BOOL visible)
-{
- if (!visible)
- {
- hide(FALSE);
- }
-}
-
-BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
-{
- // This is mostly copied from the llview class, but it continues
- // the hover handle code after a hover handler has been found.
- BOOL handled = FALSE;
-
- // If we got a hover event, we've already moved the cursor
- // for any menu shifts, so subsequent mouseup messages will be in the
- // correct position. No need to correct them.
- //mShiftHoriz = 0;
- //mShiftVert = 0;
-
- // release mouse capture after short period of visibility if we're using a finite boundary
- // so that right click outside of boundary will trigger new pie menu
- if (hasMouseCapture() &&
- !mRightMouseDown &&
- mShrinkBorderTimer.getStarted() &&
- mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
- {
- gFocusMgr.setMouseCapture(NULL);
- mUseInfiniteRadius = FALSE;
- }
-
- LLMenuItemGL *item = pieItemFromXY( x, y );
-
- if (item && item->getEnabled())
- {
- getWindow()->setCursor(UI_CURSOR_ARROW);
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
- handled = TRUE;
-
- if (item != mHoverItem)
- {
- if (mHoverItem)
- {
- mHoverItem->setHighlight( FALSE );
- }
- mHoverItem = item;
- mHoverItem->setHighlight( TRUE );
-
- switch(pieItemIndexFromXY(x, y))
- {
- case 0:
- make_ui_sound("UISndPieMenuSliceHighlight0");
- break;
- case 1:
- make_ui_sound("UISndPieMenuSliceHighlight1");
- break;
- case 2:
- make_ui_sound("UISndPieMenuSliceHighlight2");
- break;
- case 3:
- make_ui_sound("UISndPieMenuSliceHighlight3");
- break;
- case 4:
- make_ui_sound("UISndPieMenuSliceHighlight4");
- break;
- case 5:
- make_ui_sound("UISndPieMenuSliceHighlight5");
- break;
- case 6:
- make_ui_sound("UISndPieMenuSliceHighlight6");
- break;
- case 7:
- make_ui_sound("UISndPieMenuSliceHighlight7");
- break;
- default:
- make_ui_sound("UISndPieMenuSliceHighlight0");
- break;
- }
- }
- mHoveredAnyItem = TRUE;
- }
- else
- {
- // clear out our selection
- if (mHoverItem)
- {
- mHoverItem->setHighlight(FALSE);
- mHoverItem = NULL;
- }
- }
-
- if( !handled && pointInView( x, y ) )
- {
- getWindow()->setCursor(UI_CURSOR_ARROW);
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
- handled = TRUE;
- }
-
- mHoverThisFrame = TRUE;
-
- return handled;
-}
-
-BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask )
-{
- BOOL handled = FALSE;
- // The click was somewhere within our rectangle
- LLMenuItemGL *item = pieItemFromXY( x, y );
-
- if (item)
- {
- // lie to the item about where the click happened
- // to make sure it's within the item's rectangle
- handled = item->handleMouseDown( 0, 0, mask );
- }
- else if (!mRightMouseDown)
- {
- // call hidemenus to make sure transient selections get cleared
- ((LLMenuHolderGL*)getParent())->hideMenus();
- }
-
- // always handle mouse down as mouse up will close open menus
- return handled;
-}
-
-BOOL LLPieMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- BOOL handled = FALSE;
-
- mRightMouseDown = TRUE;
-
- // The click was somewhere within our rectangle
- LLMenuItemGL *item = pieItemFromXY( x, y );
- S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
- S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
- BOOL clicked_in_pie = ((delta_x * delta_x) + (delta_y * delta_y) < mCurRadius*mCurRadius) || mUseInfiniteRadius;
-
- // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
- if (clicked_in_pie)
- {
- // capture mouse cursor as if on initial menu show
- gFocusMgr.setMouseCapture(this);
- mShrinkBorderTimer.stop();
- mUseInfiniteRadius = TRUE;
- handled = TRUE;
- }
-
- if (item)
- {
- // lie to the item about where the click happened
- // to make sure it's within the item's rectangle
- if (item->handleMouseDown( 0, 0, mask ))
- {
- handled = TRUE;
- }
- }
-
- return handled;
-}
-
-BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
-{
- // release mouse capture when right mouse button released, and we're past the shrink time
- if (mShrinkBorderTimer.getStarted() &&
- mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME)
- {
- mUseInfiniteRadius = FALSE;
- gFocusMgr.setMouseCapture(NULL);
- }
-
- S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
- S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
- if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE)
- {
- // user released right mouse button in middle of pie, interpret this as closing the menu
- sMenuContainer->hideMenus();
- return TRUE;
- }
-
-
- BOOL result = handleMouseUp( x, y, mask );
- mRightMouseDown = FALSE;
- mHoveredAnyItem = FALSE;
-
- return result;
-}
-
-BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask )
-{
- BOOL handled = FALSE;
-
- // The click was somewhere within our rectangle
- LLMenuItemGL *item = pieItemFromXY( x, y );
-
- if (item)
- {
- // lie to the item about where the click happened
- // to make sure it's within the item's rectangle
- if (item->getEnabled())
- {
- handled = item->handleMouseUp( 0, 0, mask );
- hide(TRUE);
- }
- }
- else if (!mRightMouseDown)
- {
- // call hidemenus to make sure transient selections get cleared
- ((LLMenuHolderGL*)getParent())->hideMenus();
- }
-
- if (handled)
- {
- make_ui_sound("UISndClickRelease");
- }
-
- if (!handled && !mUseInfiniteRadius)
- {
- // call hidemenus to make sure transient selections get cleared
- sMenuContainer->hideMenus();
- }
-
- if (mFirstMouseDown)
- {
- make_ui_sound("UISndPieMenuAppear");
- mFirstMouseDown = FALSE;
- }
-
- // *FIX: is this necessary?
- if (!mShrinkBorderTimer.getStarted())
- {
- mShrinkBorderTimer.start();
- }
-
- return handled;
-}
-
-
-// virtual
-void LLPieMenu::draw()
-{
- // clear hover if mouse moved away
- if (!mHoverThisFrame && mHoverItem)
- {
- mHoverItem->setHighlight(FALSE);
- mHoverItem = NULL;
- }
-
- F32 width = (F32) getRect().getWidth();
- F32 height = (F32) getRect().getHeight();
- mCurRadius = PIE_SCALE_FACTOR * llmax( width/2, height/2 );
-
- mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f;
- if (mShrinkBorderTimer.getStarted())
- {
- mOuterRingAlpha = clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 0.f, 1.f);
- mCurRadius *= clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR);
- }
-
- // correct for non-square pixels
- F32 center_x = width/2;
- F32 center_y = height/2;
- S32 steps = 100;
-
- gGL.pushMatrix();
- {
- gGL.translatef(center_x, center_y, 0.f);
-
- F32 line_width = LLUI::sConfigGroup->getF32("PieMenuLineWidth");
- LLColor4 line_color = LLUI::sColorsGroup->getColor("PieMenuLineColor");
- LLColor4 bg_color = LLUI::sColorsGroup->getColor("PieMenuBgColor");
- LLColor4 selected_color = LLUI::sColorsGroup->getColor("PieMenuSelectedColor");
-
- // main body
- LLColor4 outer_color = bg_color;
- outer_color.mV[VALPHA] *= mOuterRingAlpha;
- gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color );
-
- // selected wedge
- item_list_t::iterator item_iter;
- S32 i = 0;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- if ((*item_iter)->getHighlight())
- {
- F32 arc_size = F_PI * 0.25f;
-
- F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
- F32 end_radians = start_radians + arc_size;
-
- LLColor4 outer_color = selected_color;
- outer_color.mV[VALPHA] *= mOuterRingAlpha;
- gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
- }
- i++;
- }
-
- LLUI::setLineWidth( line_width );
-
- // inner lines
- outer_color = line_color;
- outer_color.mV[VALPHA] *= mOuterRingAlpha;
- gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color );
-
- // inner circle
- gGL.color4fv( line_color.mV );
- gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE );
-
- // outer circle
- gGL.color4fv( outer_color.mV );
- gl_circle_2d( 0, 0, mCurRadius, steps, FALSE );
-
- LLUI::setLineWidth(1.0f);
- }
- gGL.popMatrix();
-
- mHoverThisFrame = FALSE;
-
- LLView::draw();
-}
-
-void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
-{
- F32 width = (F32) getRect().getWidth();
- F32 height = (F32) getRect().getHeight();
- F32 center_x = width/2;
- F32 center_y = height/2;
- S32 steps = 100;
-
- gGL.color4fv( color.mV );
- gGL.pushMatrix();
- {
- gGL.translatef(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
-
- item_list_t::iterator item_iter;
- S32 i = 0;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- if ((*item_iter) == itemp)
- {
- F32 arc_size = F_PI * 0.25f;
-
- F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
- F32 end_radians = start_radians + arc_size;
-
- LLColor4 outer_color = color;
- outer_color.mV[VALPHA] *= mOuterRingAlpha;
- gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color );
- }
- i++;
- }
- }
- gGL.popMatrix();
-}
-
-// virtual
-BOOL LLPieMenu::append(LLMenuItemGL *item)
-{
- item->setBriefItem(TRUE);
- item->setFont( LLFontGL::getFontSansSerifSmall() );
- return LLMenuGL::append(item);
-}
-
-// virtual
-BOOL LLPieMenu::appendSeparator(const std::string &separator_name)
-{
- LLMenuItemGL* separator = new LLMenuItemBlankGL();
- separator->setFont( LLFontGL::getFontSansSerifSmall() );
- return append( separator );
-}
-
-
-BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
-{
- if (menu == this)
- {
- llerrs << "Can't attach a pie menu to itself" << llendl;
- }
- LLPieMenuBranch *item;
- item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu);
- getParent()->addChild(item->getBranch());
- item->setFont( LLFontGL::getFontSansSerifSmall() );
- return append( item );
-}
-
-// virtual
-void LLPieMenu::arrange()
-{
- const S32 rect_height = 190;
- const S32 rect_width = 190;
-
- // all divide by 6
- const S32 CARD_X = 60;
- const S32 DIAG_X = 48;
- const S32 CARD_Y = 76;
- const S32 DIAG_Y = 42;
-
- const S32 ITEM_CENTER_X[] = { CARD_X, DIAG_X, 0, -DIAG_X, -CARD_X, -DIAG_X, 0, DIAG_X };
- const S32 ITEM_CENTER_Y[] = { 0, DIAG_Y, CARD_Y, DIAG_Y, 0, -DIAG_Y, -CARD_Y, -DIAG_Y };
-
- LLRect rect;
-
- S32 font_height = 0;
- if( mItems.size() )
- {
- font_height = (*mItems.begin())->getNominalHeight();
- }
- S32 item_width = 0;
-
-// F32 sin_delta = OO_SQRT2; // sin(45 deg)
-// F32 cos_delta = OO_SQRT2; // cos(45 deg)
-
- // TODO: Compute actual bounding rect for menu
-
- // HACK: casting away const. Should use setRect or some helper function instead.
- const_cast<LLRect&>(getRect()).setOriginAndSize(getRect().mLeft, getRect().mBottom, rect_width, rect_height );
-
- // place items around a circle, with item 0 at positive X,
- // rotating counter-clockwise
- item_list_t::iterator item_iter;
- S32 i = 0;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- LLMenuItemGL *item = *item_iter;
-
- item_width = item->getNominalWidth();
-
- // Put in the right place around a circle centered at 0,0
- rect.setCenterAndSize(ITEM_CENTER_X[i],
- ITEM_CENTER_Y[i],
- item_width, font_height );
-
- // Correct for the actual rectangle size
- rect.translate( rect_width/2, rect_height/2 );
-
- item->setRect( rect );
-
- // Make sure enablement is correct
- item->buildDrawLabel();
- i++;
- }
-}
-
-LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
-{
- // We might have shifted this menu on draw. If so, we need
- // to shift over mouseup events until we get a hover event.
- //x += mShiftHoriz;
- //y += mShiftVert;
-
- // An arc of the pie menu is 45 degrees
- const F32 ARC_DEG = 45.f;
- S32 delta_x = x - getRect().getWidth() / 2;
- S32 delta_y = y - getRect().getHeight() / 2;
-
- // circle safe zone in the center
- S32 dist_squared = delta_x*delta_x + delta_y*delta_y;
- if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
- {
- return NULL;
- }
-
- // infinite radius is only used with right clicks
- S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 );
- if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius)
- {
- return NULL;
- }
-
- F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
-
- // rotate marks CCW so that east = [0, ARC_DEG) instead of
- // [-ARC_DEG/2, ARC_DEG/2)
- angle += ARC_DEG / 2.f;
-
- // make sure we're only using positive angles
- if (angle < 0.f) angle += 360.f;
-
- S32 which = S32( angle / ARC_DEG );
-
- if (0 <= which && which < (S32)mItems.size() )
- {
- item_list_t::iterator item_iter;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- if (which == 0)
- {
- return (*item_iter);
- }
- which--;
- }
- }
-
- return NULL;
-}
-
-S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
-{
- // An arc of the pie menu is 45 degrees
- const F32 ARC_DEG = 45.f;
- // correct for non-square pixels
- S32 delta_x = x - getRect().getWidth() / 2;
- S32 delta_y = y - getRect().getHeight() / 2;
-
- // circle safe zone in the center
- if (delta_x*delta_x + delta_y*delta_y < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
- {
- return -1;
- }
-
- F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
-
- // rotate marks CCW so that east = [0, ARC_DEG) instead of
- // [-ARC_DEG/2, ARC_DEG/2)
- angle += ARC_DEG / 2.f;
-
- // make sure we're only using positive angles
- if (angle < 0.f) angle += 360.f;
-
- S32 which = S32( angle / ARC_DEG );
- return which;
-}
-
-void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
-{
- S32 width = getRect().getWidth();
- S32 height = getRect().getHeight();
-
- const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
-
- LLView* parent_view = getParent();
- BOOL moved = FALSE;
-
- S32 local_x, local_y;
- parent_view->screenPointToLocal(x, y, &local_x, &local_y);
-
- // HACK: casting away const. Should use setRect or some helper function instead.
- const_cast<LLRect&>(getRect()).setCenterAndSize(local_x, local_y, width, height);
- arrange();
-
- // Adjust the pie rectangle to keep it on screen
- if (getRect().mLeft < menu_region_rect.mLeft)
- {
- //mShiftHoriz = menu_region_rect.mLeft - getRect().mLeft;
- //getRect().translate( mShiftHoriz, 0 );
- // HACK: casting away const. Should use setRect or some helper function instead.
- const_cast<LLRect&>(getRect()).translate( menu_region_rect.mLeft - getRect().mLeft, 0 );
- moved = TRUE;
- }
-
- if (getRect().mRight > menu_region_rect.mRight)
- {
- //mShiftHoriz = menu_region_rect.mRight - getRect().mRight;
- //getRect().translate( mShiftHoriz, 0);
- // HACK: casting away const. Should use setRect or some helper function instead.
- const_cast<LLRect&>(getRect()).translate( menu_region_rect.mRight - getRect().mRight, 0 );
- moved = TRUE;
- }
-
- if (getRect().mBottom < menu_region_rect.mBottom)
- {
- //mShiftVert = menu_region_rect.mBottom - getRect().mBottom;
- //getRect().translate( 0, mShiftVert );
- // HACK: casting away const. Should use setRect or some helper function instead.
- const_cast<LLRect&>(getRect()).translate( 0, menu_region_rect.mBottom - getRect().mBottom );
- moved = TRUE;
- }
-
-
- if (getRect().mTop > menu_region_rect.mTop)
- {
- //mShiftVert = menu_region_rect.mTop - getRect().mTop;
- //getRect().translate( 0, mShiftVert );
- // HACK: casting away const. Should use setRect or some helper function instead.
- const_cast<LLRect&>(getRect()).translate( 0, menu_region_rect.mTop - getRect().mTop );
- moved = TRUE;
- }
-
- // If we had to relocate the pie menu, put the cursor in the
- // center of its rectangle
- if (moved)
- {
- LLCoordGL center;
- center.mX = (getRect().mLeft + getRect().mRight) / 2;
- center.mY = (getRect().mTop + getRect().mBottom) / 2;
-
- LLUI::setCursorPositionLocal(getParent(), center.mX, center.mY);
- }
-
- // *FIX: what happens when mouse buttons reversed?
- mRightMouseDown = mouse_down;
- mFirstMouseDown = mouse_down;
- mUseInfiniteRadius = TRUE;
- mHoveredAnyItem = FALSE;
-
- if (!mFirstMouseDown)
- {
- make_ui_sound("UISndPieMenuAppear");
- }
-
- LLView::setVisible(TRUE);
-
- // we want all mouse events in case user does quick right click again off of pie menu
- // rectangle, to support gestural menu traversal
- gFocusMgr.setMouseCapture(this);
-
- if (mouse_down)
- {
- mShrinkBorderTimer.stop();
- }
- else
- {
- mShrinkBorderTimer.start();
- }
-}
-
-void LLPieMenu::hide(BOOL item_selected)
-{
- if (!getVisible()) return;
-
- if (mHoverItem)
- {
- mHoverItem->setHighlight( FALSE );
- mHoverItem = NULL;
- }
-
- make_ui_sound("UISndPieMenuHide");
-
- mFirstMouseDown = FALSE;
- mRightMouseDown = FALSE;
- mUseInfiniteRadius = FALSE;
- mHoveredAnyItem = FALSE;
-
- LLView::setVisible(FALSE);
-
- gFocusMgr.setMouseCapture(NULL);
-}
-
///============================================================================
/// Class LLMenuBarGL
///============================================================================
-static LLRegisterWidget<LLMenuBarGL> r2("menu_bar");
+static LLDefaultChildRegistry::Register<LLMenuBarGL> r2("menu_bar");
-// Default constructor
-LLMenuBarGL::LLMenuBarGL( const std::string& name ) : LLMenuGL ( name, name )
-{
- mHorizontalLayout = TRUE;
- setCanTearOff(FALSE);
- mKeepFixedSize = TRUE;
- mAltKeyTrigger = FALSE;
-}
+LLMenuBarGL::LLMenuBarGL( const Params& p )
+: LLMenuGL(p),
+ mAltKeyTrigger(FALSE)
+{}
// Default destructor
LLMenuBarGL::~LLMenuBarGL()
@@ -3813,108 +2995,6 @@ LLMenuBarGL::~LLMenuBarGL()
mAccelerators.clear();
}
-// virtual
-LLXMLNodePtr LLMenuBarGL::getXML(bool save_children) const
-{
- // Sorty of hacky: reparent items to this and then back at the end of the export
- LLView *orig_parent = NULL;
- item_list_t::const_iterator item_iter;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- LLMenuItemGL* child = *item_iter;
- LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child;
- LLMenuGL *menu = branch->getBranch();
- orig_parent = menu->getParent();
- menu->updateParent((LLView *)this);
- }
-
- LLXMLNodePtr node = LLMenuGL::getXML();
-
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- LLMenuItemGL* child = *item_iter;
- LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child;
- LLMenuGL *menu = branch->getBranch();
- menu->updateParent(orig_parent);
- }
-
- return node;
-}
-
-LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
- std::string name("menu");
- node->getAttributeString("name", name);
-
- BOOL opaque = FALSE;
- node->getAttributeBOOL("opaque", opaque);
-
- LLMenuBarGL *menubar = new LLMenuBarGL(name);
-
- LLHandle<LLFloater> parent_handle;
- LLFloater* parent_floater = dynamic_cast<LLFloater*>(parent);
- if (parent_floater)
- {
- parent_handle = parent_floater->getHandle();
- }
-
- // We need to have the rect early so that it's around when building
- // the menu items
- LLRect view_rect;
- createRect(node, view_rect, parent, menubar->getRequiredRect());
- menubar->setRect(view_rect);
-
- if (node->hasAttribute("drop_shadow"))
- {
- BOOL drop_shadow = FALSE;
- node->getAttributeBOOL("drop_shadow", drop_shadow);
- menubar->setDropShadowed(drop_shadow);
- }
-
- menubar->setBackgroundVisible(opaque);
- LLColor4 color(0,0,0,0);
- if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
- {
- menubar->setBackgroundColor(color);
- }
-
- LLXMLNodePtr child;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
- {
- if (child->hasName("menu"))
- {
- LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory);
- // because of lazy initialization, have to disable tear off functionality
- // and then re-enable with proper parent handle
- if (menu->getCanTearOff())
- {
- menu->setCanTearOff(FALSE);
- menu->setCanTearOff(TRUE, parent_handle);
- }
- menubar->appendMenu(menu);
- if (LLMenuGL::sMenuContainer != NULL)
- {
- menu->updateParent(LLMenuGL::sMenuContainer);
- }
- else
- {
- menu->updateParent(parent);
- }
- }
- }
-
- menubar->initFromXML(node, parent);
-
- BOOL create_jump_keys = FALSE;
- node->getAttributeBOOL("create_jump_keys", create_jump_keys);
- if (create_jump_keys)
- {
- menubar->createJumpKeys();
- }
-
- return menubar;
-}
-
BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
{
if (getHighlightedItem() && mask == MASK_NONE)
@@ -3951,7 +3031,8 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask)
{
- if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && LLUI::sConfigGroup->getBOOL("UseAltKeyForMenus"))
+ static LLUICachedControl<bool> use_altkey_for_menus ("UseAltKeyForMenus", 0);
+ if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && use_altkey_for_menus)
{
mAltKeyTrigger = TRUE;
}
@@ -3984,7 +3065,7 @@ BOOL LLMenuBarGL::handleJumpKey(KEY key)
LLMenuGL::setKeyboardMode(TRUE);
found_it->second->setHighlight(TRUE);
- found_it->second->doIt();
+ found_it->second->onCommit();
}
return TRUE;
}
@@ -4001,19 +3082,6 @@ BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask)
return LLMenuGL::handleMouseDown(x, y, mask);
}
-BOOL LLMenuBarGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- // clicks on menu bar closes existing menus from other contexts but leave
- // own menu open so that we get toggle behavior
- if (!getHighlightedItem() || !getHighlightedItem()->isActive())
- {
- LLMenuGL::sMenuContainer->hideMenus();
- }
-
- return LLMenuGL::handleMouseDown(x, y, mask);
-}
-
-
void LLMenuBarGL::draw()
{
LLMenuItemGL* itemp = getHighlightedItem();
@@ -4031,6 +3099,7 @@ void LLMenuBarGL::draw()
LLMenuGL::draw();
}
+
void LLMenuBarGL::checkMenuTrigger()
{
// has the ALT key been pressed and subsequently released?
@@ -4038,7 +3107,8 @@ void LLMenuBarGL::checkMenuTrigger()
{
// if alt key was released quickly, treat it as a menu access key
// otherwise it was probably an Alt-zoom or similar action
- if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= LLUI::sConfigGroup->getF32("MenuAccessKeyTime") ||
+ static LLUICachedControl<F32> menu_access_key_time ("MenuAccessKeyTime", 0);
+ if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= menu_access_key_time ||
gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2)
{
if (getHighlightedItem())
@@ -4107,7 +3177,7 @@ S32 LLMenuBarGL::getRightmostMenuEdge()
}
// add a vertical separator to this menu
-BOOL LLMenuBarGL::appendSeparator( const std::string &separator_name )
+BOOL LLMenuBarGL::addSeparator()
{
LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL();
return append( separator );
@@ -4124,11 +3194,23 @@ BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu )
BOOL success = TRUE;
- LLMenuItemBranchGL* branch = NULL;
- branch = new LLMenuItemBranchDownGL( menu->getName(), menu->getLabel(), menu->getHandle());
+ // *TODO: Hack! Fix this
+ LLMenuItemBranchDownGL::Params p;
+ p.name = menu->getName();
+ p.label = menu->getLabel();
+ p.visible = menu->getVisible();
+ p.branch = menu;
+ p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor");
+ p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor");
+ p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor");
+ p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor");
+
+ LLMenuItemBranchDownGL* branch = LLUICtrlFactory::create<LLMenuItemBranchDownGL>(p);
success &= branch->addToAcceleratorList(&mAccelerators);
success &= append( branch );
branch->setJumpKey(branch->getJumpKey());
+ menu->updateParent(LLMenuGL::sMenuContainer);
+
return success;
}
@@ -4174,7 +3256,7 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
handled = TRUE;
if (active_menu && active_menu != viewp)
{
- ((LLMenuItemGL*)viewp)->doIt();
+ ((LLMenuItemGL*)viewp)->onCommit();
LLMenuGL::setKeyboardMode(FALSE);
}
LLMenuGL::setKeyboardMode(FALSE);
@@ -4205,23 +3287,17 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
///============================================================================
/// Class LLMenuHolderGL
///============================================================================
+LLCoordGL LLMenuHolderGL::sContextMenuSpawnPos(S32_MAX, S32_MAX);
+
LLMenuHolderGL::LLMenuHolderGL()
- : LLPanel(std::string("Menu Holder"))
+ : LLPanel()
{
+ setName("Menu Holder");
setMouseOpaque(FALSE);
sItemActivationTimer.stop();
mCanHide = TRUE;
}
-LLMenuHolderGL::LLMenuHolderGL(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows)
-: LLPanel(name, rect, FALSE)
-{
- setMouseOpaque(mouse_opaque);
- sItemActivationTimer.stop();
- mCanHide = TRUE;
-}
-
-
void LLMenuHolderGL::draw()
{
LLView::draw();
@@ -4236,16 +3312,11 @@ void LLMenuHolderGL::draw()
selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this);
F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME;
- F32 alpha = lerp(LLMenuItemGL::getHighlightBGColor().mV[VALPHA], 0.f, interpolant);
- LLColor4 bg_color(LLMenuItemGL::getHighlightBGColor().mV[VRED],
- LLMenuItemGL::getHighlightBGColor().mV[VGREEN],
- LLMenuItemGL::getHighlightBGColor().mV[VBLUE],
- alpha);
LLUI::pushMatrix();
{
LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f);
- selecteditem->getMenu()->drawBackground(selecteditem, bg_color);
+ selecteditem->getMenu()->drawBackground(selecteditem, interpolant);
selecteditem->draw();
}
LLUI::popMatrix();
@@ -4274,6 +3345,32 @@ BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask )
return handled;
}
+// This occurs when you mouse-down to spawn a context menu, hold the button
+// down, move off the menu, then mouse-up. We want this to close the menu.
+BOOL LLMenuHolderGL::handleRightMouseUp( S32 x, S32 y, MASK mask )
+{
+ const S32 SLOP = 2;
+ S32 spawn_dx = (x - sContextMenuSpawnPos.mX);
+ S32 spawn_dy = (y - sContextMenuSpawnPos.mY);
+ if (-SLOP <= spawn_dx && spawn_dx <= SLOP
+ && -SLOP <= spawn_dy && spawn_dy <= SLOP)
+ {
+ // we're still inside the slop region from spawning this menu
+ // so interpret the mouse-up as a single-click to show and leave on
+ // screen
+ sContextMenuSpawnPos.set(S32_MAX, S32_MAX);
+ return TRUE;
+ }
+
+ BOOL handled = LLView::childrenHandleRightMouseUp(x, y, mask) != NULL;
+ if (!handled)
+ {
+ // clicked off of menu, hide them all
+ hideMenus();
+ }
+ return handled;
+}
+
void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent)
{
if (width != getRect().getWidth() || height != getRect().getHeight())
@@ -4336,17 +3433,22 @@ void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
/// Class LLTearOffMenu
///============================================================================
LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) :
- LLFloater(menup->getName(), LLRect(0, 100, 100, 0), menup->getLabel(), FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, FALSE)
+ LLFloater(LLSD())
{
+ static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+
+ setName(menup->getName());
+ setTitle(menup->getLabel());
+ setCanMinimize(FALSE);
// flag menu as being torn off
menup->setTornOff(TRUE);
// update menu layout as torn off menu (no spillover menus)
- menup->arrange();
+ menup->needsArrange();
LLRect rect;
menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView);
// make sure this floater is big enough for menu
- mTargetHeight = (F32)(rect.getHeight() + LLFLOATER_HEADER_SIZE + 5);
+ mTargetHeight = (F32)(rect.getHeight() + floater_header_size + 5);
reshape(rect.getWidth(), rect.getHeight());
setRect(rect);
@@ -4362,13 +3464,21 @@ LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) :
// highlight first item (tear off item will be disabled)
mMenu->highlightNextItem(NULL);
+
+ // Can't do this in postBuild() because that is only called for floaters
+ // constructed from XML.
+ mCloseSignal.connect(boost::bind(&LLTearOffMenu::closeTearOff, this));
}
+LLTearOffMenu::~LLTearOffMenu()
+{
+}
void LLTearOffMenu::draw()
{
+ static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
mMenu->setBackgroundVisible(isBackgroundOpaque());
- mMenu->arrange();
+ mMenu->needsArrange();
if (getRect().getHeight() != mTargetHeight)
{
@@ -4378,8 +3488,8 @@ void LLTearOffMenu::draw()
else
{
// when in stasis, remain big enough to hold menu contents
- mTargetHeight = (F32)(mMenu->getRect().getHeight() + LLFLOATER_HEADER_SIZE + 4);
- reshape(mMenu->getRect().getWidth() + 3, mMenu->getRect().getHeight() + LLFLOATER_HEADER_SIZE + 5);
+ mTargetHeight = (F32)(mMenu->getRect().getHeight() + floater_header_size + 4);
+ reshape(mMenu->getRect().getWidth() + 3, mMenu->getRect().getHeight() + floater_header_size + 5);
}
LLFloater::draw();
}
@@ -4457,12 +3567,12 @@ LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
LLTearOffMenu* tearoffp = new LLTearOffMenu(menup);
// keep onscreen
gFloaterView->adjustToFitScreen(tearoffp, FALSE);
- tearoffp->open(); /* Flawfinder: ignore */
+ tearoffp->openFloater(LLSD());
return tearoffp;
}
-void LLTearOffMenu::onClose(bool app_quitting)
+void LLTearOffMenu::closeTearOff()
{
removeChild(mMenu);
mOldParent->addChild(mMenu);
@@ -4472,6 +3582,337 @@ void LLTearOffMenu::onClose(bool app_quitting)
mMenu->setVisible(FALSE);
mMenu->setTornOff(FALSE);
mMenu->setDropShadowed(TRUE);
- destroy();
+}
+
+
+//-----------------------------------------------------------------------------
+// class LLContextMenuBranch
+// A branch to another context menu
+//-----------------------------------------------------------------------------
+class LLContextMenuBranch : public LLMenuItemGL
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
+ {
+ Mandatory<LLContextMenu*> branch;
+ };
+
+ LLContextMenuBranch(const Params&);
+
+ // called to rebuild the draw label
+ virtual void buildDrawLabel( void );
+
+ // onCommit() - do the primary funcationality of the menu item.
+ virtual void onCommit( void );
+
+ LLContextMenu* getBranch() { return mBranch; }
+ void setHighlight( BOOL highlight );
+
+protected:
+ void showSubMenu();
+
+ LLContextMenu* mBranch;
+};
+
+LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)
+: LLMenuItemGL(p),
+ mBranch( p.branch )
+{
+ mBranch->hide();
+ mBranch->setParentMenuItem(this);
+}
+
+// called to rebuild the draw label
+void LLContextMenuBranch::buildDrawLabel( void )
+{
+ {
+ // default enablement is this -- if any of the subitems are
+ // enabled, this item is enabled. JC
+ U32 sub_count = mBranch->getItemCount();
+ U32 i;
+ BOOL any_enabled = FALSE;
+ for (i = 0; i < sub_count; i++)
+ {
+ LLMenuItemGL* item = mBranch->getItem(i);
+ item->buildDrawLabel();
+ if (item->getEnabled() && !item->getDrawTextDisabled() )
+ {
+ any_enabled = TRUE;
+ break;
+ }
+ }
+ setDrawTextDisabled(!any_enabled);
+ setEnabled(TRUE);
+ }
+
+ mDrawAccelLabel.clear();
+ std::string st = mDrawAccelLabel;
+ appendAcceleratorString( st );
+ mDrawAccelLabel = st;
+
+ // No special branch suffix
+ mDrawBranchLabel.clear();
+}
+
+void LLContextMenuBranch::showSubMenu()
+{
+ S32 center_x;
+ S32 center_y;
+ localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
+ mBranch->show( center_x, center_y);
+}
+
+// onCommit() - do the primary funcationality of the menu item.
+void LLContextMenuBranch::onCommit( void )
+{
+ showSubMenu();
+
+}
+void LLContextMenuBranch::setHighlight( BOOL highlight )
+{
+ if (highlight == getHighlight()) return;
+ LLMenuItemGL::setHighlight(highlight);
+ if( highlight )
+ {
+ showSubMenu();
+ }
+ else
+ {
+ mBranch->hide();
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//-----------------------------------------------------------------------------
+// class LLContextMenu
+// A context menu
+//-----------------------------------------------------------------------------
+static LLDefaultChildRegistry::Register<LLContextMenu> context_menu_register("context_menu");
+static MenuRegistry::Register<LLContextMenu> context_menu_register2("context_menu");
+
+
+LLContextMenu::LLContextMenu(const Params& p)
+: LLMenuGL(p),
+ mHoveredAnyItem(FALSE),
+ mHoverItem(NULL)
+{
+ //setBackgroundVisible(TRUE);
+}
+
+void LLContextMenu::setVisible(BOOL visible)
+{
+ if (!visible)
+ hide();
+}
+
+// Takes cursor position in screen space?
+void LLContextMenu::show(S32 x, S32 y)
+{
+ // Save click point for detecting cursor moves before mouse-up.
+ // Must be in local coords to compare with mouseUp events.
+ // If the mouse doesn't move, the menu will stay open ala the Mac.
+ // See also LLMenuGL::showPopup()
+ LLMenuHolderGL::sContextMenuSpawnPos.set(x,y);
+
+ arrangeAndClear();
+
+ S32 width = getRect().getWidth();
+ S32 height = getRect().getHeight();
+ const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
+ LLView* parent_view = getParent();
+
+ // Open upwards if menu extends past bottom
+ if (y - height < menu_region_rect.mBottom)
+ {
+ if (getParentMenuItem()) // Adjust if this is a submenu
+ {
+ y += height - getParentMenuItem()->getNominalHeight();
+ }
+ else
+ {
+ y += height;
+ }
+ }
+
+ // Open out to the left if menu extends past right edge
+ if (x + width > menu_region_rect.mRight)
+ {
+ if (getParentMenuItem())
+ {
+ x -= getParentMenuItem()->getRect().getWidth() + width;
+ }
+ else
+ {
+ x -= width;
+ }
+ }
+
+ S32 local_x, local_y;
+ parent_view->screenPointToLocal(x, y, &local_x, &local_y);
+
+ LLRect rect;
+ rect.setLeftTopAndSize(local_x, local_y, width, height);
+ setRect(rect);
+ arrange();
+
+ LLView::setVisible(TRUE);
+}
+
+void LLContextMenu::hide()
+{
+ if (!getVisible()) return;
+
+ LLView::setVisible(FALSE);
+
+ if (mHoverItem)
+ {
+ mHoverItem->setHighlight( FALSE );
+ }
+ mHoverItem = NULL;
+}
+
+
+BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask )
+{
+ LLMenuGL::handleHover(x,y,mask);
+
+ BOOL handled = FALSE;
+
+ LLMenuItemGL *item = getHighlightedItem();
+
+ if (item && item->getEnabled())
+ {
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+ handled = TRUE;
+
+ if (item != mHoverItem)
+ {
+ if (mHoverItem)
+ {
+ mHoverItem->setHighlight( FALSE );
+ }
+ mHoverItem = item;
+ mHoverItem->setHighlight( TRUE );
+ }
+ mHoveredAnyItem = TRUE;
+ }
+ else
+ {
+ // clear out our selection
+ if (mHoverItem)
+ {
+ mHoverItem->setHighlight(FALSE);
+ mHoverItem = NULL;
+ }
+ }
+
+ if( !handled && pointInView( x, y ) )
+ {
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+ handled = TRUE;
+ }
+
+ return handled;
+}
+
+// handleMouseDown and handleMouseUp are handled by LLMenuGL
+
+
+BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = FALSE;
+
+ // The click was somewhere within our rectangle
+ LLMenuItemGL *item = getHighlightedItem();
+
+ S32 local_x = x - getRect().mLeft;
+ S32 local_y = y - getRect().mBottom;
+
+ BOOL clicked_in_menu = pointInView(local_x, local_y) ;
+
+ // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
+ if (clicked_in_menu)
+ {
+ // capture mouse cursor as if on initial menu show
+ handled = TRUE;
+ }
+
+ if (item)
+ {
+ // lie to the item about where the click happened
+ // to make sure it's within the item's rectangle
+ if (item->handleMouseDown( 0, 0, mask ))
+ {
+ handled = TRUE;
+ }
+ }
+
+ return handled;
+}
+
+BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
+{
+ S32 local_x = x - getRect().mLeft;
+ S32 local_y = y - getRect().mBottom;
+
+ if (!mHoveredAnyItem && !pointInView(local_x, local_y))
+ {
+ sMenuContainer->hideMenus();
+ return TRUE;
+ }
+
+
+ BOOL result = handleMouseUp( x, y, mask );
+ mHoveredAnyItem = FALSE;
+
+ return result;
+}
+
+void LLContextMenu::draw()
+{
+ LLMenuGL::draw();
+}
+
+BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu)
+{
+
+ if (menu == this)
+ {
+ llerrs << "Can't attach a context menu to itself" << llendl;
+ }
+
+ LLContextMenuBranch *item;
+ LLContextMenuBranch::Params p;
+ p.name = menu->getName();
+ p.label = menu->getLabel();
+ p.branch = menu;
+ p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor");
+ p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor");
+ p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor");
+ p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor");
+
+ item = LLUICtrlFactory::create<LLContextMenuBranch>(p);
+ LLMenuGL::sMenuContainer->addChild(item->getBranch());
+ item->setFont( LLFontGL::getFontSansSerifSmall() );
+
+ return append( item );
+}
+
+bool LLContextMenu::addChild(LLView* view, S32 tab_group)
+{
+ LLContextMenu* context = dynamic_cast<LLContextMenu*>(view);
+ if (context)
+ return appendContextSubMenu(context);
+
+ LLMenuItemSeparatorGL* separator = dynamic_cast<LLMenuItemSeparatorGL*>(view);
+ if (separator)
+ return append(separator);
+
+ LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view);
+ if (item)
+ return append(item);
+
+ return false;
}